summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJürgen Gehring <Juergen.Gehring@bmw.de>2016-09-20 03:59:53 -0700
committerJürgen Gehring <Juergen.Gehring@bmw.de>2016-09-20 03:59:53 -0700
commit273814c76be4a8f906dc053492529b8d53b9e807 (patch)
treee7160dc68fe3f478a0c5c86aaccaeb620d528b63
parent4c5d160362d8693aed8abd642212e68c9778bbda (diff)
downloadvSomeIP-273814c76be4a8f906dc053492529b8d53b9e807.tar.gz
vSomeIP 2.2.42.2.4
-rw-r--r--.gitignore48
-rw-r--r--CHANGES126
-rw-r--r--CMakeLists.txt36
-rw-r--r--LICENSE_boost25
-rw-r--r--README392
-rwxr-xr-x[-rw-r--r--]README.md0
-rw-r--r--config/vsomeip-local-tracing.json86
-rw-r--r--config/vsomeip-tcp-client.json46
-rw-r--r--config/vsomeip-udp-client.json8
-rw-r--r--config/vsomeip-udp-service.json12
-rw-r--r--daemon/CMakeLists.txt4
-rw-r--r--daemon/vsomeipd.cpp21
-rw-r--r--documentation/todo.txt16
-rw-r--r--examples/CMakeLists.txt2
-rw-r--r--examples/hello_world/CMakeLists.txt2
-rw-r--r--examples/hello_world/hello_world_client.cpp2
-rw-r--r--examples/hello_world/hello_world_service.cpp2
-rw-r--r--examples/hello_world/helloworld-local.json69
-rw-r--r--examples/hello_world/readme2
-rw-r--r--examples/notify-sample.cpp2
-rw-r--r--examples/readme.txt10
-rw-r--r--examples/request-sample.cpp2
-rw-r--r--examples/response-sample.cpp2
-rw-r--r--examples/sample-ids.hpp2
-rw-r--r--examples/subscribe-sample.cpp12
-rw-r--r--exportmap.gcc1
-rw-r--r--implementation/configuration/include/client.hpp28
-rw-r--r--implementation/configuration/include/configuration.hpp39
-rw-r--r--implementation/configuration/include/configuration_impl.hpp137
-rw-r--r--implementation/configuration/include/event.hpp2
-rw-r--r--implementation/configuration/include/eventgroup.hpp4
-rw-r--r--implementation/configuration/include/internal.hpp.in61
-rw-r--r--implementation/configuration/include/service.hpp3
-rw-r--r--implementation/configuration/include/trace.hpp62
-rw-r--r--implementation/configuration/include/watchdog.hpp21
-rw-r--r--implementation/configuration/src/configuration.cpp2
-rw-r--r--implementation/configuration/src/configuration_impl.cpp907
-rw-r--r--implementation/endpoints/include/buffer.hpp2
-rw-r--r--implementation/endpoints/include/client_endpoint_impl.hpp27
-rw-r--r--implementation/endpoints/include/endpoint.hpp6
-rw-r--r--implementation/endpoints/include/endpoint_definition.hpp2
-rw-r--r--implementation/endpoints/include/endpoint_host.hpp8
-rw-r--r--implementation/endpoints/include/endpoint_impl.hpp18
-rw-r--r--implementation/endpoints/include/local_client_endpoint_impl.hpp25
-rw-r--r--implementation/endpoints/include/local_server_endpoint_impl.hpp22
-rw-r--r--implementation/endpoints/include/server_endpoint_impl.hpp21
-rw-r--r--implementation/endpoints/include/tcp_client_endpoint_impl.hpp8
-rw-r--r--implementation/endpoints/include/tcp_server_endpoint_impl.hpp13
-rw-r--r--implementation/endpoints/include/udp_client_endpoint_impl.hpp9
-rw-r--r--implementation/endpoints/include/udp_server_endpoint_impl.hpp30
-rw-r--r--implementation/endpoints/include/virtual_server_endpoint_impl.hpp6
-rw-r--r--implementation/endpoints/src/client_endpoint_impl.cpp159
-rw-r--r--implementation/endpoints/src/endpoint_definition.cpp2
-rw-r--r--implementation/endpoints/src/endpoint_impl.cpp93
-rw-r--r--implementation/endpoints/src/local_client_endpoint_impl.cpp150
-rw-r--r--implementation/endpoints/src/local_server_endpoint_impl.cpp62
-rw-r--r--implementation/endpoints/src/server_endpoint_impl.cpp97
-rw-r--r--implementation/endpoints/src/tcp_client_endpoint_impl.cpp93
-rw-r--r--implementation/endpoints/src/tcp_server_endpoint_impl.cpp124
-rw-r--r--implementation/endpoints/src/udp_client_endpoint_impl.cpp58
-rw-r--r--implementation/endpoints/src/udp_server_endpoint_impl.cpp218
-rw-r--r--implementation/endpoints/src/virtual_server_endpoint_impl.cpp12
-rw-r--r--implementation/helper/boost/asio/basic_datagram_socket_ext.hpp954
-rw-r--r--implementation/helper/boost/asio/datagram_socket_service_ext.hpp437
-rw-r--r--implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp516
-rw-r--r--implementation/helper/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp270
-rw-r--r--implementation/helper/boost/asio/detail/impl/socket_ops_ext.ipp210
-rw-r--r--implementation/helper/boost/asio/detail/reactive_socket_recv_op_ext.hpp126
-rw-r--r--implementation/helper/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp136
-rw-r--r--implementation/helper/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp128
-rw-r--r--implementation/helper/boost/asio/detail/reactive_socket_service_base_ext.hpp455
-rw-r--r--implementation/helper/boost/asio/detail/reactive_socket_service_ext.hpp462
-rw-r--r--implementation/helper/boost/asio/detail/reactor_op_ext.hpp42
-rw-r--r--implementation/helper/boost/asio/detail/socket_ops_ext.hpp62
-rw-r--r--implementation/helper/boost/asio/ip/udp_ext.hpp115
-rw-r--r--implementation/logging/include/defines.hpp15
-rw-r--r--implementation/logging/include/dlt_sink_backend.hpp6
-rw-r--r--implementation/logging/include/logger.hpp2
-rw-r--r--implementation/logging/include/logger_impl.hpp5
-rw-r--r--implementation/logging/src/dlt_sink_backend.cpp15
-rw-r--r--implementation/logging/src/logger.cpp2
-rw-r--r--implementation/logging/src/logger_impl.cpp23
-rw-r--r--implementation/message/include/deserializer.hpp2
-rw-r--r--implementation/message/include/message_base_impl.hpp6
-rw-r--r--implementation/message/include/message_header_impl.hpp2
-rw-r--r--implementation/message/include/message_impl.hpp12
-rw-r--r--implementation/message/include/payload_impl.hpp2
-rw-r--r--implementation/message/include/serializer.hpp2
-rw-r--r--implementation/message/src/deserializer.cpp6
-rw-r--r--implementation/message/src/message_base_impl.cpp10
-rw-r--r--implementation/routing/include/event.hpp29
-rw-r--r--implementation/routing/include/eventgroupinfo.hpp35
-rw-r--r--implementation/routing/include/routing_manager.hpp21
-rw-r--r--implementation/routing/include/routing_manager_adapter.hpp2
-rw-r--r--implementation/routing/include/routing_manager_base.hpp193
-rw-r--r--implementation/routing/include/routing_manager_host.hpp6
-rw-r--r--implementation/routing/include/routing_manager_impl.hpp160
-rw-r--r--implementation/routing/include/routing_manager_proxy.hpp83
-rw-r--r--implementation/routing/include/routing_manager_stub.hpp47
-rw-r--r--implementation/routing/include/routing_manager_stub_host.hpp29
-rw-r--r--implementation/routing/include/serviceinfo.hpp22
-rw-r--r--implementation/routing/include/types.hpp2
-rw-r--r--implementation/routing/src/event.cpp123
-rw-r--r--implementation/routing/src/eventgroupinfo.cpp86
-rw-r--r--implementation/routing/src/routing_manager_base.cpp782
-rw-r--r--implementation/routing/src/routing_manager_impl.cpp1824
-rw-r--r--implementation/routing/src/routing_manager_proxy.cpp809
-rw-r--r--implementation/routing/src/routing_manager_stub.cpp586
-rw-r--r--implementation/routing/src/serviceinfo.cpp50
-rw-r--r--implementation/runtime/include/application_impl.hpp125
-rw-r--r--implementation/runtime/include/runtime_impl.hpp7
-rw-r--r--implementation/runtime/src/application_impl.cpp963
-rw-r--r--implementation/runtime/src/error.cpp2
-rw-r--r--implementation/runtime/src/runtime.cpp10
-rw-r--r--implementation/runtime/src/runtime_impl.cpp14
-rw-r--r--implementation/service_discovery/include/configuration_option_impl.hpp2
-rw-r--r--implementation/service_discovery/include/constants.hpp2
-rw-r--r--implementation/service_discovery/include/defines.hpp16
-rwxr-xr-ximplementation/service_discovery/include/deserializer.hpp2
-rwxr-xr-ximplementation/service_discovery/include/entry_impl.hpp5
-rw-r--r--implementation/service_discovery/include/enumeration_types.hpp2
-rwxr-xr-ximplementation/service_discovery/include/eventgroupentry_impl.hpp13
-rw-r--r--implementation/service_discovery/include/fsm_base.hpp12
-rw-r--r--implementation/service_discovery/include/fsm_events.hpp21
-rw-r--r--implementation/service_discovery/include/ip_option_impl.hpp2
-rw-r--r--implementation/service_discovery/include/ipv4_option_impl.hpp2
-rw-r--r--implementation/service_discovery/include/ipv6_option_impl.hpp2
-rwxr-xr-ximplementation/service_discovery/include/load_balancing_option_impl.hpp2
-rwxr-xr-ximplementation/service_discovery/include/message_element_impl.hpp2
-rwxr-xr-ximplementation/service_discovery/include/message_impl.hpp12
-rw-r--r--implementation/service_discovery/include/option_impl.hpp2
-rw-r--r--implementation/service_discovery/include/primitive_types.hpp2
-rwxr-xr-ximplementation/service_discovery/include/protection_option_impl.hpp2
-rw-r--r--implementation/service_discovery/include/request.hpp7
-rw-r--r--implementation/service_discovery/include/runtime.hpp2
-rw-r--r--implementation/service_discovery/include/runtime_impl.hpp2
-rw-r--r--implementation/service_discovery/include/service_discovery.hpp24
-rw-r--r--implementation/service_discovery/include/service_discovery_fsm.hpp74
-rw-r--r--implementation/service_discovery/include/service_discovery_host.hpp30
-rw-r--r--implementation/service_discovery/include/service_discovery_impl.hpp157
-rw-r--r--implementation/service_discovery/include/serviceentry_impl.hpp2
-rw-r--r--implementation/service_discovery/include/subscription.hpp20
-rwxr-xr-ximplementation/service_discovery/src/configuration_option_impl.cpp50
-rw-r--r--implementation/service_discovery/src/deserializer.cpp2
-rwxr-xr-ximplementation/service_discovery/src/entry_impl.cpp31
-rwxr-xr-ximplementation/service_discovery/src/eventgroupentry_impl.cpp53
-rw-r--r--implementation/service_discovery/src/fsm_base.cpp40
-rw-r--r--implementation/service_discovery/src/ip_option_impl.cpp2
-rw-r--r--implementation/service_discovery/src/ipv4_option_impl.cpp6
-rwxr-xr-ximplementation/service_discovery/src/ipv6_option_impl.cpp6
-rwxr-xr-ximplementation/service_discovery/src/load_balancing_option_impl.cpp2
-rwxr-xr-ximplementation/service_discovery/src/message_element_impl.cpp2
-rwxr-xr-ximplementation/service_discovery/src/message_impl.cpp9
-rwxr-xr-ximplementation/service_discovery/src/option_impl.cpp2
-rwxr-xr-ximplementation/service_discovery/src/protection_option_impl.cpp2
-rw-r--r--implementation/service_discovery/src/request.cpp13
-rw-r--r--implementation/service_discovery/src/runtime.cpp2
-rw-r--r--implementation/service_discovery/src/runtime_impl.cpp2
-rw-r--r--implementation/service_discovery/src/service_discovery_fsm.cpp205
-rw-r--r--implementation/service_discovery/src/service_discovery_impl.cpp1536
-rwxr-xr-ximplementation/service_discovery/src/serviceentry_impl.cpp2
-rw-r--r--implementation/service_discovery/src/subscription.cpp30
-rw-r--r--implementation/tracing/include/defines.hpp12
-rw-r--r--implementation/tracing/include/enumeration_types.hpp21
-rw-r--r--implementation/tracing/include/trace_connector.hpp100
-rw-r--r--implementation/tracing/include/trace_header.hpp38
-rw-r--r--implementation/tracing/src/trace_connector.cpp361
-rw-r--r--implementation/tracing/src/trace_header.cpp58
-rw-r--r--implementation/utility/include/byteorder.hpp2
-rw-r--r--implementation/utility/include/utility.hpp10
-rw-r--r--implementation/utility/src/utility.cpp273
-rw-r--r--initial.txt1
-rw-r--r--interface/vsomeip/application.hpp31
-rw-r--r--interface/vsomeip/constants.hpp12
-rw-r--r--interface/vsomeip/defines.hpp4
-rw-r--r--interface/vsomeip/enumeration_types.hpp2
-rw-r--r--interface/vsomeip/error.hpp2
-rw-r--r--interface/vsomeip/export.hpp2
-rw-r--r--interface/vsomeip/handler.hpp3
-rw-r--r--interface/vsomeip/internal/deserializable.hpp2
-rw-r--r--interface/vsomeip/internal/serializable.hpp2
-rw-r--r--interface/vsomeip/message.hpp2
-rw-r--r--interface/vsomeip/message_base.hpp4
-rw-r--r--interface/vsomeip/payload.hpp2
-rw-r--r--interface/vsomeip/primitive_types.hpp4
-rw-r--r--interface/vsomeip/runtime.hpp6
-rw-r--r--interface/vsomeip/vsomeip.hpp2
-rw-r--r--test/CMakeLists.txt415
-rw-r--r--test/application_tests/application_test.cpp61
-rw-r--r--test/application_tests/application_test.json9
-rw-r--r--test/application_tests/application_test_daemon.json38
-rw-r--r--test/application_tests/application_test_no_dispatch_threads_daemon.json37
-rwxr-xr-xtest/application_tests/application_test_starter.sh31
-rw-r--r--test/big_payload_tests/big_payload_test_client.cpp2
-rw-r--r--test/big_payload_tests/big_payload_test_client.hpp2
-rw-r--r--test/big_payload_tests/big_payload_test_globals.hpp2
-rw-r--r--test/big_payload_tests/big_payload_test_service.cpp2
-rw-r--r--test/big_payload_tests/big_payload_test_service.hpp2
-rw-r--r--test/client_id_tests/client_id_test_globals.hpp9
-rwxr-xr-xtest/client_id_tests/client_id_test_master_starter.sh8
-rw-r--r--test/client_id_tests/client_id_test_service.cpp4
-rwxr-xr-xtest/client_id_tests/client_id_test_slave_starter.sh12
-rw-r--r--test/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_master.json.in14
-rw-r--r--test/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_slave.json.in28
-rw-r--r--test/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_master.json.in70
-rw-r--r--test/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_slave.json.in70
-rw-r--r--test/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_master.json.in14
-rw-r--r--test/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_slave.json.in16
-rw-r--r--test/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_master.json.in14
-rw-r--r--test/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_slave.json.in26
-rw-r--r--test/client_id_tests/conf/client_id_test_same_client_ids_same_ports_master.json.in14
-rw-r--r--test/client_id_tests/conf/client_id_test_same_client_ids_same_ports_slave.json.in14
-rw-r--r--test/configuration_tests/configuration-test.cpp2
-rw-r--r--test/cpu_load_tests/conf/cpu_load_test_client_master.json.in32
-rw-r--r--test/cpu_load_tests/conf/cpu_load_test_client_slave.json.in32
-rw-r--r--test/cpu_load_tests/conf/cpu_load_test_service_master.json.in46
-rw-r--r--test/cpu_load_tests/conf/cpu_load_test_service_slave.json.in46
-rw-r--r--test/cpu_load_tests/cpu_load_measurer.cpp158
-rw-r--r--test/cpu_load_tests/cpu_load_measurer.hpp35
-rw-r--r--test/cpu_load_tests/cpu_load_test_client.cpp376
-rw-r--r--test/cpu_load_tests/cpu_load_test_globals.hpp18
-rwxr-xr-xtest/cpu_load_tests/cpu_load_test_master_starter.sh70
-rw-r--r--test/cpu_load_tests/cpu_load_test_service.cpp204
-rwxr-xr-xtest/cpu_load_tests/cpu_load_test_slave_starter.sh52
-rw-r--r--test/header_factory_tests/header_factory_test.cpp2
-rw-r--r--test/header_factory_tests/header_factory_test_client.cpp2
-rw-r--r--test/header_factory_tests/header_factory_test_client.hpp2
-rw-r--r--test/header_factory_tests/header_factory_test_service.cpp2
-rw-r--r--test/header_factory_tests/header_factory_test_service.hpp2
-rw-r--r--test/magic_cookies_tests/magic_cookies_test_client.cpp32
-rwxr-xr-xtest/magic_cookies_tests/magic_cookies_test_client_start.sh2
-rw-r--r--test/magic_cookies_tests/magic_cookies_test_service.cpp2
-rwxr-xr-xtest/magic_cookies_tests/magic_cookies_test_service_start.sh2
-rwxr-xr-xtest/magic_cookies_tests/magic_cookies_test_starter.sh2
-rwxr-xr-xtest/payload_tests/external_local_payload_test_client_external_start.sh2
-rwxr-xr-xtest/payload_tests/external_local_payload_test_client_external_starter.sh2
-rwxr-xr-xtest/payload_tests/external_local_payload_test_client_local_and_external_starter.sh2
-rwxr-xr-xtest/payload_tests/external_local_payload_test_client_local_start.sh2
-rwxr-xr-xtest/payload_tests/external_local_payload_test_client_local_starter.sh2
-rwxr-xr-xtest/payload_tests/external_local_payload_test_service_client_external_start.sh2
-rwxr-xr-xtest/payload_tests/external_local_payload_test_service_start.sh2
-rwxr-xr-xtest/payload_tests/local_payload_test_client_start.sh2
-rwxr-xr-xtest/payload_tests/local_payload_test_service_start.sh2
-rwxr-xr-xtest/payload_tests/local_payload_test_starter.sh2
-rw-r--r--test/payload_tests/payload_test_client.cpp2
-rw-r--r--test/payload_tests/payload_test_client.hpp2
-rw-r--r--test/payload_tests/payload_test_service.cpp2
-rw-r--r--test/payload_tests/payload_test_service.hpp2
-rw-r--r--test/payload_tests/stopwatch.cpp2
-rw-r--r--test/payload_tests/stopwatch.hpp2
-rw-r--r--test/readme.txt55
-rwxr-xr-xtest/routing_tests/external_local_routing_test_client_external_start.sh2
-rw-r--r--test/routing_tests/external_local_routing_test_service.cpp16
-rw-r--r--test/routing_tests/external_local_routing_test_service.hpp3
-rwxr-xr-xtest/routing_tests/external_local_routing_test_service_start.sh2
-rwxr-xr-xtest/routing_tests/external_local_routing_test_starter.sh2
-rw-r--r--test/routing_tests/local_routing_test_client.cpp2
-rw-r--r--test/routing_tests/local_routing_test_client.hpp2
-rwxr-xr-xtest/routing_tests/local_routing_test_client_start.sh2
-rw-r--r--test/routing_tests/local_routing_test_service.cpp2
-rw-r--r--test/routing_tests/local_routing_test_service.hpp2
-rwxr-xr-xtest/routing_tests/local_routing_test_service_start.sh2
-rwxr-xr-xtest/routing_tests/local_routing_test_starter.sh2
-rw-r--r--test/someip_test_globals.hpp2
-rw-r--r--test/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master.json.in74
-rw-r--r--test/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json.in74
-rw-r--r--test/subscribe_notify_one_tests/subscribe_notify_one_test_globals.hpp35
-rwxr-xr-xtest/subscribe_notify_one_tests/subscribe_notify_one_test_master_starter.sh93
-rw-r--r--test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp442
-rwxr-xr-xtest/subscribe_notify_one_tests/subscribe_notify_one_test_slave_starter.sh72
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master.json.in70
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave.json.in70
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_master.json.in70
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_slave.json.in70
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master.json.in70
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave.json.in70
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_master.json.in70
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_slave.json.in70
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_master.json.in70
-rw-r--r--test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_slave.json.in70
-rw-r--r--test/subscribe_notify_tests/subscribe_notify_test_globals.hpp35
-rwxr-xr-xtest/subscribe_notify_tests/subscribe_notify_test_master_starter.sh93
-rw-r--r--test/subscribe_notify_tests/subscribe_notify_test_service.cpp416
-rwxr-xr-xtest/subscribe_notify_tests/subscribe_notify_test_slave_starter.sh72
-rw-r--r--tools/CMakeLists.txt18
-rw-r--r--tools/vsomeip_ctrl.cpp429
286 files changed, 18180 insertions, 3404 deletions
diff --git a/.gitignore b/.gitignore
index 1b7d204..3aa1ebf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,24 +1,40 @@
-/build*/*
-/examples/hello_world/build
-/.settings
-/doc
-/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
-/test/configuration_tests/configuration-test.json
-/test/configuration_tests/configuration-test-deprecated.json
-/test/magic_cookies_tests/magic_cookies_test_client.json
-/test/magic_cookies_tests/magic_cookies_test_service.json
-/test/payload_tests/external_local_payload_test_client_external.json
-/test/payload_tests/external_local_payload_test_client_local.json
-/test/payload_tests/external_local_payload_test_service.json
-/test/routing_tests/external_local_routing_test_client_external.json
-/test/routing_tests/external_local_routing_test_service.json
+/build*/*
+/examples/hello_world/build
+/.settings
+/doc
+/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
+/test/magic_cookies_tests/magic_cookies_test_client.json
+/test/magic_cookies_tests/magic_cookies_test_service.json
+/test/payload_tests/external_local_payload_test_client_external.json
+/test/payload_tests/external_local_payload_test_client_local.json
+/test/payload_tests/external_local_payload_test_service.json
+/test/routing_tests/external_local_routing_test_client_external.json
+/test/routing_tests/external_local_routing_test_service.json
/test/client_id_tests/client_id_test_diff_client_ids_diff_ports_master.json
/test/client_id_tests/client_id_test_diff_client_ids_diff_ports_slave.json
/test/client_id_tests/client_id_test_diff_client_ids_same_ports_master.json
/test/client_id_tests/client_id_test_diff_client_ids_same_ports_slave.json
+/test/client_id_tests/client_id_test_diff_client_ids_partial_same_ports_master.json
+/test/client_id_tests/client_id_test_diff_client_ids_partial_same_ports_slave.json
/test/client_id_tests/client_id_test_same_client_ids_diff_ports_master.json
/test/client_id_tests/client_id_test_same_client_ids_diff_ports_slave.json
/test/client_id_tests/client_id_test_same_client_ids_same_ports_master.json
/test/client_id_tests/client_id_test_same_client_ids_same_ports_slave.json
+/test/subscribe_notify_tests/subscribe_notify_test_diff_client_ids_diff_ports_master.json
+/test/subscribe_notify_tests/subscribe_notify_test_diff_client_ids_diff_ports_slave.json
+/test/subscribe_notify_tests/subscribe_notify_test_diff_client_ids_same_ports_master.json
+/test/subscribe_notify_tests/subscribe_notify_test_diff_client_ids_same_ports_slave.json
+/test/subscribe_notify_tests/subscribe_notify_test_diff_client_ids_partial_same_ports_master.json
+/test/subscribe_notify_tests/subscribe_notify_test_diff_client_ids_partial_same_ports_slave.json
+/test/subscribe_notify_tests/subscribe_notify_test_same_client_ids_diff_ports_master.json
+/test/subscribe_notify_tests/subscribe_notify_test_same_client_ids_diff_ports_slave.json
+/test/subscribe_notify_tests/subscribe_notify_test_same_client_ids_same_ports_master.json
+/test/subscribe_notify_tests/subscribe_notify_test_same_client_ids_same_ports_slave.json
+/test/subscribe_notify_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/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
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..362beb5
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,126 @@
+Changes
+=======
+
+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
+- 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
+- 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)
+- Ensure consistency of version information
+- Fixed Service Discovery state machine
+
+v1.3.0
+- Fixed SD library loading on Windows
+- Changed cmake directory name (CMake --> cmake)
+- Corrected check for multicast address in Service Discovery
+- Added default setting for Service Discovery timings
+- Ensure only local services are reported by the Service Discovery
+- Fixed a crash in case of a wrong unicast address definition
+- Protected forwarding of availability information
+- Improved handling of notification events
+- Added initial support for selective broadcasts (CommonAPI)
+- Avoid deadlock when offering services
+- Correct handling of events
+- Added initial support for managed interfaces (CommonAPI)
+
+v2.0.0
+- Buffer sizes were adapted to the transport protocols
+- 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
+- Support automatic configuration of local communication
+- 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"
+- Fixed serialization of major version in Eventgroup entries
+- Magic Cookies are no longer forwarded to the routing manager but handled in the receiving endpoint
+- vsomeip daemon was added
+
+v2.0.1
+- Ensure Unicast flag is set in all Service Discovery messages
+- Allow "local" as alias for unicast address in Magic Cookie configuration
+- Correctly set layer 4 protocol in multicast options
+- Increased robustness of deserialization of configuration options
+- Fixed handling of unknown Service Discovery options
+
+v2.0.2
+- Fixed endpoint flushing
+- Improved handling of Selective Broadcasts (CommonAPI)
+- Trace connector was added
+- Added reboot detection
+- Reworked handling of TCP connections
+- Support multiple multicast eventgroups per service
+- Improved handling of multicasts
+- Extended Service Discovery to send FindMessage messages for unknown services
+- Support multiple SOME/IP messages in a single UDP datagram
+
+v2.0.3
+- Fixed shutdown and application re-registering
+
+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)
+
+v2.0.5
+- Fixed reboot detection behavior
+
+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
+- 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
+- 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
+- Allow to specify an application specific DLT application
+- Ensure correct ordering of availability notifications
+- Automatically expire subscription based on the given TTL
+- Do not include internal services in SD offer messages
+- Consider all fields of SD subscribe messages
+- Made the watchdog configurable
+- Support destination address resolution on Windows (for reboot detection)
+- Support auto-configuration (client identifiers, routing manager) on Windows
+
+v2.1.1
+- Ensure SD FindService-messages are sent after client re-registration
+- Corrected configuration of MagicCookies
+- Make client ports configurable
+- Implemented FindService message optimization
+- Extended configuration consistency checks
+
+v2.1.2
+- Ensure correct message order
+
+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
+- 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
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bf03c16..5f85a14 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
@@ -7,8 +7,8 @@ cmake_minimum_required (VERSION 2.8.12)
project (vsomeip)
set (VSOMEIP_MAJOR_VERSION 2)
-set (VSOMEIP_MINOR_VERSION 0)
-set (VSOMEIP_PATCH_VERSION 1)
+set (VSOMEIP_MINOR_VERSION 2)
+set (VSOMEIP_PATCH_VERSION 4)
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)
@@ -66,18 +66,32 @@ include_directories(
find_package(Threads REQUIRED)
# Boost
-find_package( Boost 1.54 COMPONENTS system thread log REQUIRED )
+find_package( Boost 1.55 COMPONENTS system thread log REQUIRED )
include_directories( ${Boost_INCLUDE_DIR} )
+if(Boost_FOUND)
+ if(Boost_LIBRARY_DIR)
+ MESSAGE( STATUS "Boost_LIBRARY_DIR not empty using it: ${Boost_LIBRARY_DIR}" )
+ else()
+ if(BOOST_LIBRARYDIR)
+ MESSAGE( STATUS "Boost_LIBRARY_DIR empty but BOOST_LIBRARYDIR is set setting Boost_LIBRARY_DIR to: ${BOOST_LIBRARYDIR}" )
+ set(Boost_LIBRARY_DIR ${BOOST_LIBRARYDIR})
+ endif()
+ endif()
+else()
+ MESSAGE( STATUS "Boost was not found!")
+endif()
+
# DLT
find_package(PkgConfig)
pkg_check_modules(DLT "automotive-dlt >= 2.11")
IF(DLT_FOUND)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_DLT")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_DLT")
ENDIF(DLT_FOUND)
include_directories(
include
+ implementation/helper
${DLT_INCLUDE_DIRS}
)
@@ -90,6 +104,7 @@ file(GLOB vsomeip_SRC
"implementation/configuration/src/*.cpp"
"implementation/endpoints/src/*.cpp"
"implementation/logging/src/*.cpp"
+ "implementation/tracing/src/*.cpp"
"implementation/message/src/*.cpp"
"implementation/routing/src/*.cpp"
"implementation/runtime/src/*.cpp"
@@ -97,8 +112,9 @@ file(GLOB vsomeip_SRC
)
if (MSVC)
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_WIN32_WINNT=0x0501 -DWIN32 -DUSE_VSOMEIP_STATISTICS -DCOMMONAPI_INTERNAL_COMPILATION -DBOOST_LOG_DYN_LINK /EHsc")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_WIN32_WINNT=0x0501 -DWIN32 -DUSE_VSOMEIP_STATISTICS -DCOMMONAPI_INTERNAL_COMPILATION -DBOOST_LOG_DYN_LINK /EHsc")
+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})
@@ -136,7 +152,7 @@ set(EXAMPLE_CONFIG_FILES
)
###################################################################################################
-set (VSOMEIP_DIAGNOSIS_ADDRESS "0x11")
+set (VSOMEIP_DIAGNOSIS_ADDRESS "0x00")
if (DIAGNOSIS_ADDRESS)
set (VSOMEIP_DIAGNOSIS_ADDRESS ${DIAGNOSIS_ADDRESS})
endif ()
@@ -301,6 +317,10 @@ add_custom_target( daemon )
add_subdirectory( daemon )
endif()
+# build tools
+add_custom_target( tools )
+add_subdirectory( tools )
+
# build examples
add_custom_target( examples )
add_subdirectory( examples EXCLUDE_FROM_ALL )
diff --git a/LICENSE_boost b/LICENSE_boost
new file mode 100644
index 0000000..eff5f98
--- /dev/null
+++ b/LICENSE_boost
@@ -0,0 +1,25 @@
+This license applies to all files in directory implementation/helper/boost:
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/README b/README
index 893d004..79b7eff 100644
--- a/README
+++ b/README
@@ -15,7 +15,7 @@ vsomeip
Copyright
+++++++++
-Copyright (C) 2015, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+Copyright (C) 2015-2016, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
License
+++++++
@@ -44,15 +44,15 @@ Dependencies
~~~~~~~~~~~~
* A C++11 enabled compiler like gcc >= 4.8 is needed.
* vsomeip uses cmake as buildsystem.
-* vsomeip uses Boost >= 1.54:
+* vsomeip uses Boost >= 1.55:
** Ubuntu 14.04:
-*** `sudo apt-get install libboost-system1.54-dev libboost-thread1.54-dev
- libboost-log1.54-dev`
+*** `sudo apt-get install libboost-system1.55-dev libboost-thread1.55-dev
+ libboost-log1.55-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`
+*** `sudo apt-get install libboost-system1.55-dev libboost-thread1.55-dev
+ libboost-log1.55-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,
@@ -81,6 +81,21 @@ make
make install
----
+Compilation with predefined unicast and/or diagnosis address
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+To predefine the unicast address, call cmake like:
+[source,bash]
+----
+cmake -DUNICAST_ADDRESS=<YOUR IP ADDRESS> ..
+----
+
+To predefine the diagnosis address, call cmake like:
+[source,bash]
+----
+cmake -DDIAGNOSIS_ADDRESS=<YOUR DIAGNOSIS ADDRESS> ..
+----
+The diagnosis address is a single byte value.
+
Compilation of examples
^^^^^^^^^^^^^^^^^^^^^^^
For compilation of the examples call:
@@ -155,6 +170,17 @@ Example cmake call:
cmake -DTESTS_BAT=ON ..
----
+Compilation of vsomeip_ctrl
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+For compilation of the <<vsomeip_ctrl>> utility call:
+[source, bash]
+----
+mkdir build
+cd build
+cmake ..
+make vsomeip_ctrl
+----
+
Generating the documentation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To generate the documentation call cmake as described in <<Compilation>> and
@@ -227,6 +253,10 @@ The IP address of the host system.
+
The netmask to specify the subnet of the host system.
+
+* 'diagnosis'
++
+The diagnosis address (byte) that will be used to build client identifiers.
++
//Logging
* 'logging'
+
@@ -254,6 +284,59 @@ The absolute path of the log file.
Specifies whether Diagnostic Log and Trace (DLT) is enabled (valid values:
_true, false_).
+
+//Tracing
+* anchor:config-tracing[]'tracing' (optional)
++
+** '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>>
++
+** 'channels (array)' (optional)
++
+Contains the channels to DLT.
++
+NOTE: You can set up multiple channels to DLT over that you can forward the
+messages.
++
+*** 'name'
++
+The name of the channel.
++
+*** 'id'
++
+The id of the channel.
++
+** 'filters (array)' (optional)
++
+Contains the filters that are applied on the messages.
++
+NOTE: You can apply filters respectively filter rules on the messages with
+specific criterias and expressions. So only the filtered messages are forwarded
+to DLT.
++
+*** 'channel' (optional)
++
+The id of the channel over that the filtered messages are forwarded to DLT. If
+no channel is specified the default channel is used.
++
+IMPORTANT: If multiple filters are used, the channel MUST always be
+specified and accordingly defined! Each filter needs its own channel!
++
+*** 'services (array)' (optional)
++
+Contains the service ids. The messages that relates to the specified services will be filtered.
++
+*** 'methods (array)' (optional)
++
+Contains the method ids. The messages that relates to the specified methods will be filtered.
++
+*** 'clients (array)' (optional)
++
+Contains the client ids. The messages that relates to the specified clients will
+be filtered.
++
//Applications
* 'applications (array)'
+
@@ -267,27 +350,29 @@ The name of the application.
+
The id of the application.
+
-** 'num_dispatchers'
+** 'max_dispatchers'
++
+The maximum number of threads that shall be used to execute the application callbacks.
+
-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.
+** 'max_dispatch_time'
+
-** `services` (array)
+The maximum time that an application callback may consume before the callback is
+considered to be blocked (and an additional thread is used to execute pending
+callbacks if max_dispatchers is configured greater than 0).
++
+* `services` (array)
+
Contains the services of the service provider.
-*** `service`
+** `service`
+
The id of the service.
-*** `instance`
+** `instance`
+
The id of the service instance.
-*** `protocol` (optional)
+** `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
@@ -295,7 +380,7 @@ 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)
+** `unicast` (optional)
+
The unicast that hosts the service instance.
+
@@ -303,46 +388,34 @@ 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`
+** `reliable`
+
Specifies that the communication with the service is reliable respectively the
TCP protocol is used for communication.
-**** `port`
+*** `port`
+
The port of the TCP endpoint.
-**** `enable-magic-cookies`
+*** `enable-magic-cookies`
+
Specifies whether magic cookies are enabled (valid values: _true_, _false_).
-*** `unreliable`
+** `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)
+** `events` (array)
+
Contains the events of the service.
-**** `event`
+*** `event`
+
The id of the event.
-***** `is_field`
+**** `is_field`
+
Specifies whether the event is of type field.
+
@@ -350,35 +423,64 @@ 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`
+**** `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)
+** `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`
+*** `eventgroup`
+
The id of the event group.
-**** `events` (array)
+*** `events` (array)
+
Contains the ids of the appropriate events.
-**** `is_multicast`
+*** `multicast`
++
+Specifies the multicast that is used to publish the eventgroup.
+
+**** `address`
++
+The multicast address.
+
+**** `port`
++
+The multicast port.
+
+* `clients` (array)
++
+The client-side ports that shall be used to connect to a specific service.
+For each service, an array of ports to be used for reliable / unreliable
+communication can be specified. vsomeip will take the first free port of
+the list. If no free port can be found, the connection will fail. If
+vsomeip is asked to connect to a service instance without specified port(s),
+the port will be selected by the system. This implies that the user has
+to ensure that the ports configured here do not overlap with the ports
+automatically selected by the IP stack.
+
+** `service`
+** `instance`
++
+Together they specify the service instance the port configuration shall be applied to.
+
+** `reliable` (array)
+
-Specifies whether the events should be sent via multicast (valid values:
-_true_,_false_).
+The list of client ports to be used for reliable (TCP) communication to the given
+service instance.
-**** `multicast`
+** `unreliable` (array)
+
-The multicast address which the events are sent to.
+The list of client ports to be used for unreliable (UDP) communication to the given
+service instance.
* `payload-sizes` (array)
+
@@ -473,6 +575,42 @@ Cycle of the OfferService messages in the main phase.
+
Minimum delay of a unicast message to a multicast message for
provided services and eventgroups.
++
+//Watchdog
+* anchor:config-watchdog[]'watchdog' (optional)
++
+The Watchdog sends periodically pings to all known local clients.
+If a client isn't responding within a configurred time/amount of pongs
+the watchdog deregisters this application/client.
+If not configured the watchdog isn't activated.
++
+** 'enable'
++
+Specifies whether the watchdog is enabled or disabled.
+(valid values: _true, false_), (default is _false_).
++
+** 'timeout'
++
+Specifies the timeout in ms the watchdog gets activated if a ping
+isn't answered with a pong by a local client within that time.
+(valid values: _2 - 2^32_), (default is _5000_ ms).
++
+** 'allowed_missing_pongs'
++
+Specifies the amount of allowed missing pongs.
+(valid values: _1 - 2^32_), (default is _3_ pongs).
++
+//CAPI-Selective Broadcasts support
+* anchor:config-supports_selective_broadcasts[]'supports_selective_broadcasts' (optional)
++
+This nodes allow to add a list of IP addresses on which CAPI-Selective-Broadcasts feature is supported.
+If not specified the feature can't be used and the subscription behavior of the stack is same as with
+normal events.
++
+** 'address'
++
+Specifies an IP-Address (in IPv4 or IPv6 notation) on which the "selective"-feature is supported.
+Multiple addresses can be configuered.
Autoconfiguration
-----------------
@@ -762,3 +900,167 @@ This function unregister the event and the message handler and shuts down the
application.
:numbered:
+
+Trace Connector
+---------------
+anchor:traceconnector[]
+
+Overview/Prerequisites
+~~~~~~~~~~~~~~~~~~~~~~
+
+The Trace Connector is used to forward the internal messages that are sent over
+the Unix Domain Sockets to DLT. +
+So a prerequisite is that DLT is installed and the module can be found in
+context of CMake.
+
+Configuration
+~~~~~~~~~~~~~
+
+Static Configuration
+^^^^^^^^^^^^^^^^^^^^
+
+The Trace Connector can be configured statically over the
+<<config-tracing,JSON configuration file>>. +
+
+[float]
+Example 1 (Minimal Configuration)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+[source, bash]
+----
+{
+ ...
+
+ "tracing" :
+ {
+ "enable" : "true"
+ },
+
+ ...
+----
+
+This is the minimal configuration of the Trace Connector. This just enables the
+tracing and all of the sent internal messages will be traced/forwarded to DLT.
+
+[float]
+Example 2 (Using Filters)
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+[source, bash]
+----
+{
+ ...
+
+ "tracing" :
+ {
+ "enable" : "true",
+ "channels" :
+ [
+ {
+ "name" : "My channel",
+ "id" : "MC"
+ }
+ ],
+ "filters" : [
+ {
+ "channel" : "MC",
+ "services" : [ "0x1234" ],
+ "methods" : [ "0x80e8" ],
+ "clients" : [ "0x1343" ],
+ }
+ ]
+ },
+
+ ...
+----
+
+You can apply filters to the messages. In this example only the messages that
+
+* are addressed to the service with the id _0x1234_
++
+* relates to the method with the id _0x80e8_
++
+* relates to the client with the id _0x1234_
+
+
+will be traced/forwarded to DLT. The messages will be forwarded over the channel
+with the id _MC_. If just one filter is used, then the definition of a channel is
+optional. But if multiple filters are used, each filter needs an own channel! +
+In this example each criteria has only one expression/value but it's also possible
+to define multiple values to get a more fine-grained filter. +
+The ids of the filter criterias can be found in the appropriate _.fdepl_ files
+and in the rest of the configuration file. +
+
+Dynamic Configuration
+^^^^^^^^^^^^^^^^^^^^^
+
+The Trace Connector can also be configured dynamically over its interfaces.
+
+[float]
+Example:
+^^^^^^^^
+
+[source, bash]
+----
+ // get trace connector
+ std::shared_ptr<tc::trace_connector> its_trace_connector = tc::trace_connector::get();
+
+ // add channel
+ its_trace_connector->add_channel("MC", "My channel");
+
+ //add filter rule
+ tc::trace_connector::filter_rule_t its_filter_rule;
+
+ its_filter_rule[tc::filter_criteria_e::SERVICES] = { 4660 };
+
+ its_filter_rule[tc::filter_criteria_e::METHODS] = { 33000 };
+ its_filter_rule[tc::filter_criteria_e::CLIENTS] = { 4931 };
+
+ its_trace_connector->add_filter_rule("MC", its_filter_rule);
+
+ // init trace connector
+ its_trace_connector->init();
+
+ // enable trace connector
+ its_trace_connector->set_enabled(true);
+
+ //forward a message to DLT
+ its_trace_connector->forward_to_dlt(MESSAGE_TO_FORWARD);
+----
+
+Tools
+-----
+
+vsomeip_ctrl
+~~~~~~~~~~~~
+anchor:vsomeip_ctrl[]
+`vsomeip_ctrl` is a small utility which can be used to send SOME/IP messages
+from the commandline. If a response arrives within 5 seconds the response will
+be printed.
+
+* It can be build via `vsomeip_ctrl` make target (`make vsomeip_ctrl`).
+* The instance id of the target service has to be passed in hexadecimal
+ notation.
+* The complete message has to be passed in hexadecimal notation.
+* See the `--help` parameter for available options.
+* If `vsomeip_ctrl` is used to send messages to a remote service and no
+ `vsomeipd` is running on the local machine, make sure to pass a json
+ configuration file where `vsomeip_ctrl` is set as routing manager via
+ environment variable.
+* If `vsomeip_ctrl` is used to send messages to a local service and no
+ `vsomeipd` is running on the local machine, make sure to use the same json
+ configuration file as the local service.
+
+Example: Calling method with method id 0x80e8 on service with service id 0x1234,
+instance id 0x5678:
+[source, bash]
+----
+./vsomeip_ctrl --instance 5678 --message 123480e800000015134300030100000000000009efbbbf576f726c6400
+----
+
+Example: Sending a message to service with service id 0x1234, instance id
+0x5678 and method id 0x0bb8 via TCP
+[source, bash]
+----
+./vsomeip_ctrl --tcp --instance 5678 --message 12340bb8000000081344000101010000
+----
diff --git a/README.md b/README.md
index 8864fec..8864fec 100644..100755
--- a/README.md
+++ b/README.md
diff --git a/config/vsomeip-local-tracing.json b/config/vsomeip-local-tracing.json
new file mode 100644
index 0000000..ba3a6bf
--- /dev/null
+++ b/config/vsomeip-local-tracing.json
@@ -0,0 +1,86 @@
+{
+ "unicast" : "10.0.2.15",
+ "logging" :
+ {
+ "level" : "debug",
+ "console" : "true",
+ "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" },
+ "dlt" : "false"
+ },
+ "tracing" :
+ {
+ "enable" : "true"
+ },
+ "applications" :
+ [
+ {
+ "name" : "service-sample",
+ "id" : "0x1277"
+ },
+ {
+ "name" : "client-sample",
+ "id" : "0x1344"
+ }
+ ],
+ "services" :
+ [
+ {
+ "service" : "0x1234",
+ "instance" : "0x5678",
+ "unreliable" : "30509",
+ "multicast" :
+ {
+ "address" : "224.225.226.233",
+ "port" : "32344"
+ },
+ "events" :
+ [
+ {
+ "event" : "0x0777",
+ "is_field" : "true",
+ "update-cycle" : 2000
+ },
+ {
+ "event" : "0x0778",
+ "is_field" : "true",
+ "update-cycle" : 0
+ },
+ {
+ "event" : "0x0779",
+ "is_field" : "true"
+ }
+ ],
+ "eventgroups" :
+ [
+ {
+ "eventgroup" : "0x4455",
+ "events" : [ "0x777", "0x778" ]
+ },
+ {
+ "eventgroup" : "0x4465",
+ "events" : [ "0x778", "0x779" ],
+ "is_multicast" : "true"
+ },
+ {
+ "eventgroup" : "0x4555",
+ "events" : [ "0x777", "0x779" ]
+ }
+ ]
+ }
+ ],
+ "routing" : "service-sample",
+ "service-discovery" :
+ {
+ "enable" : "true",
+ "multicast" : "224.244.224.245",
+ "port" : "30490",
+ "protocol" : "udp",
+ "initial_delay_min" : "10",
+ "initial_delay_max" : "100",
+ "repetitions_base_delay" : "200",
+ "repetitions_max" : "3",
+ "ttl" : "3",
+ "cyclic_offer_delay" : "2000",
+ "request_response_delay" : "1500"
+ }
+}
diff --git a/config/vsomeip-tcp-client.json b/config/vsomeip-tcp-client.json
index 52e349a..b3d58cf 100644
--- a/config/vsomeip-tcp-client.json
+++ b/config/vsomeip-tcp-client.json
@@ -1,5 +1,5 @@
{
- "unicast" : "127.0.0.1",
+ "unicast" : "192.168.56.101",
"netmask" : "255.255.255.0",
"logging" :
{
@@ -27,48 +27,18 @@
"id" : "0x1346"
}
],
- "services" :
+ "clients" :
[
- {
- "service" : "0x1234",
- "instance" : "0x5678",
- "reliable" : { "port" : "30509", "enable-magic-cookies" : false },
- "events" :
- [
- {
- "event" : "0x0777",
- "is_field" : "true"
- },
- {
- "event" : "0x0778",
- "is_field" : "false"
- },
- {
- "event" : "0x0779",
- "is_field" : "true"
- }
- ],
- "eventgroups" :
- [
- {
- "eventgroup" : "0x4455",
- "events" : [ "0x777", "0x778" ]
- },
- {
- "eventgroup" : "0x4465",
- "events" : [ "0x778", "0x779" ]
- },
- {
- "eventgroup" : "0x4555",
- "events" : [ "0x777", "0x779" ]
- }
- ]
- }
+ {
+ "service" : "0x1234",
+ "instance" : "0x5678",
+ "reliable" : [ "41234" ]
+ }
],
"routing" : "client-sample",
"service-discovery" :
{
- "enable" : "false",
+ "enable" : "true",
"multicast" : "224.244.224.245",
"port" : "30490",
"protocol" : "udp",
diff --git a/config/vsomeip-udp-client.json b/config/vsomeip-udp-client.json
index 9c8a846..909eab5 100644
--- a/config/vsomeip-udp-client.json
+++ b/config/vsomeip-udp-client.json
@@ -27,6 +27,14 @@
"id" : "0x1346"
}
],
+ "clients" :
+ [
+ {
+ "service" : "0x1234",
+ "instance" : "0x5678",
+ "unreliable" : [ 40000, 40002 ]
+ }
+ ],
"routing" : "client-sample",
"service-discovery" :
{
diff --git a/config/vsomeip-udp-service.json b/config/vsomeip-udp-service.json
index b04aa4e..6850a7f 100644
--- a/config/vsomeip-udp-service.json
+++ b/config/vsomeip-udp-service.json
@@ -20,11 +20,6 @@
"service" : "0x1234",
"instance" : "0x5678",
"unreliable" : "30509",
- "multicast" :
- {
- "address" : "224.225.226.233",
- "port" : "32344"
- },
"events" :
[
{
@@ -47,11 +42,16 @@
{
"eventgroup" : "0x4455",
"events" : [ "0x8777", "0x8778" ]
+
},
{
"eventgroup" : "0x4465",
"events" : [ "0x8778", "0x8779" ],
- "is_multicast" : "true"
+ "multicast" :
+ {
+ "address" : "224.225.226.233",
+ "port" : "32344"
+ }
},
{
"eventgroup" : "0x4555",
diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt
index bdc0f3c..09d8b03 100644
--- a/daemon/CMakeLists.txt
+++ b/daemon/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
@@ -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})
+target_link_libraries(vsomeipd vsomeip ${Boost_LIBRARIES} ${systemd-journal_LIBRARIES} ${DL_LIBRARY} ${DLT_LIBRARIES})
install (
TARGETS vsomeipd
diff --git a/daemon/vsomeipd.cpp b/daemon/vsomeipd.cpp
index db60e23..54c6b9b 100644
--- a/daemon/vsomeipd.cpp
+++ b/daemon/vsomeipd.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -11,11 +11,20 @@
#include <vsomeip/vsomeip.hpp>
#include "../implementation/configuration/include/internal.hpp"
+#include "../implementation/logging/include/logger.hpp"
+
+#ifdef USE_DLT
+#include <dlt/dlt.h>
+#include "../implementation/logging/include/defines.hpp"
+#endif
/*
* Create a vsomeip application object and start it.
*/
int process(void) {
+#ifdef USE_DLT
+ DLT_REGISTER_APP(VSOMEIP_LOG_DEFAULT_APPLICATION_ID, VSOMEIP_LOG_DEFAULT_APPLICATION_NAME);
+#endif
std::shared_ptr<vsomeip::runtime> its_runtime
= vsomeip::runtime::get();
@@ -27,11 +36,13 @@ int process(void) {
= its_runtime->create_application(VSOMEIP_ROUTING);
if (its_application->init()) {
- its_application->start();
- return 0;
- } else {
- return -1;
+ if (its_application->is_routing()) {
+ its_application->start();
+ return 0;
+ }
+ VSOMEIP_ERROR << "vsomeipd has not been configured as routing - abort";
}
+ return -1;
}
/*
diff --git a/documentation/todo.txt b/documentation/todo.txt
index f93e541..1933fd8 100644
--- a/documentation/todo.txt
+++ b/documentation/todo.txt
@@ -1,19 +1,3 @@
TODO:
-- handle endpoints for multicasts correctly. Especially, delete them if they are no longer needed.
- This should probably be done as part of the redesign of the endpoints.
-
-- implement "Zugverfahren". The so-called "Zugverfahren" allows to specify debouncing times and
- maximum retention times for SOME/IP communication channels, defined by their SOME/IP service
- identifier, SOME/IP method identifier, client instance and service instance. The "Zugverfahren"
- is implemented on server-side.
-
-- define an interface between the vsomeip runtime and the vsomeip configuration. The goal is to
- enable configuration to be done by a configuration file (default) or by an application specific
- (probably generated) code module.
-
- update the EA model to match the current implementation
-
-- create unit tests for serialization/deserialization, configuration, message exchange...
-
-- measure runtimes for exchanging local messages / UDP messages / TCP message
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index e419589..aca749c 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/examples/hello_world/CMakeLists.txt b/examples/hello_world/CMakeLists.txt
index 48d14a4..cb32665 100644
--- a/examples/hello_world/CMakeLists.txt
+++ b/examples/hello_world/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/examples/hello_world/hello_world_client.cpp b/examples/hello_world/hello_world_client.cpp
index 2099eee..8007c32 100644
--- a/examples/hello_world/hello_world_client.cpp
+++ b/examples/hello_world/hello_world_client.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/examples/hello_world/hello_world_service.cpp b/examples/hello_world/hello_world_service.cpp
index 78b895f..b99a401 100644
--- a/examples/hello_world/hello_world_service.cpp
+++ b/examples/hello_world/hello_world_service.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/examples/hello_world/helloworld-local.json b/examples/hello_world/helloworld-local.json
index c2b4203..5aeebb7 100644
--- a/examples/hello_world/helloworld-local.json
+++ b/examples/hello_world/helloworld-local.json
@@ -1,43 +1,36 @@
{
- "unicast" : "134.86.56.94",
- "logging" :
- {
- "level" : "debug",
- "console" : "true"
- },
+ "unicast":"134.86.56.94",
+ "logging":
+ {
+ "level":"debug",
+ "console":"true"
+ },
- "applications" :
- [
- {
- "name" : "hello_world_service",
- "id" : "0x4444"
- },
+ "applications":
+ [
+ {
+ "name":"hello_world_service",
+ "id":"0x4444"
+ },
- {
- "name" : "hello_world_client",
- "id" : "0x5555"
- }
- ],
+ {
+ "name":"hello_world_client",
+ "id":"0x5555"
+ }
+ ],
- "servicegroups" :
- [
- {
- "name" : "default",
- "unicast" : "local",
- "services" :
- [
- {
- "service" : "0x1111",
- "instance" : "0x2222",
- "unreliable" : "30509"
- }
- ]
- }
- ],
+ "services":
+ [
+ {
+ "service":"0x1111",
+ "instance":"0x2222",
+ "unreliable":"30509"
+ }
+ ],
- "routing" : "hello_world_service",
- "service-discovery" :
- {
- "enable" : "false"
- }
-} \ No newline at end of file
+ "routing":"hello_world_service",
+ "service-discovery":
+ {
+ "enable":"false"
+ }
+}
diff --git a/examples/hello_world/readme b/examples/hello_world/readme
index 9b19424..01c2ec9 100644
--- a/examples/hello_world/readme
+++ b/examples/hello_world/readme
@@ -1,4 +1,4 @@
-# Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/examples/notify-sample.cpp b/examples/notify-sample.cpp
index 442f74b..12c9a4c 100644
--- a/examples/notify-sample.cpp
+++ b/examples/notify-sample.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/examples/readme.txt b/examples/readme.txt
index 745c5f2..038544e 100644
--- a/examples/readme.txt
+++ b/examples/readme.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
@@ -8,10 +8,10 @@ the configuration files need to be adapted to match the devices addresses.
To start the request/response-example from the build-directory do:
-HOST1: env VSOMEIP_CONFIGURATION=../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=client-sample ./request-sample
-HOST2: env VSOMEIP_CONFIGURATION=../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=service-sample ./response-sample
+HOST1: env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=client-sample ./request-sample
+HOST1: env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=service-sample ./response-sample
To start the subscribe/notify-example from the build-directory do:
-HOST1: env VSOMEIP_CONFIGURATION=../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=client-sample ./subscribe-sample
-HOST2: env VSOMEIP_CONFIGURATION=../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=service-sample ./notify-sample
+HOST1: env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=client-sample ./subscribe-sample
+HOST1: env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=service-sample ./notify-sample
diff --git a/examples/request-sample.cpp b/examples/request-sample.cpp
index ccdcffe..86834d0 100644
--- a/examples/request-sample.cpp
+++ b/examples/request-sample.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/examples/response-sample.cpp b/examples/response-sample.cpp
index 31adace..c3ef177 100644
--- a/examples/response-sample.cpp
+++ b/examples/response-sample.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/examples/sample-ids.hpp b/examples/sample-ids.hpp
index 2d59164..b1a503d 100644
--- a/examples/sample-ids.hpp
+++ b/examples/sample-ids.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/examples/subscribe-sample.cpp b/examples/subscribe-sample.cpp
index 9a03722..915ea11 100644
--- a/examples/subscribe-sample.cpp
+++ b/examples/subscribe-sample.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -29,6 +29,10 @@ public:
<< "]"
<< std::endl;
+ app_->register_state_handler(
+ std::bind(&client_sample::on_state, this,
+ std::placeholders::_1));
+
app_->register_message_handler(
vsomeip::ANY_SERVICE, SAMPLE_INSTANCE_ID, vsomeip::ANY_METHOD,
std::bind(&client_sample::on_message, this,
@@ -53,6 +57,12 @@ public:
app_->start();
}
+ 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);
+ }
+ }
+
void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) {
std::cout << "Service ["
<< std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance
diff --git a/exportmap.gcc b/exportmap.gcc
index 546738d..a768523 100644
--- a/exportmap.gcc
+++ b/exportmap.gcc
@@ -23,6 +23,7 @@ global:
*vsomeip::message_header_impl::*;
*vsomeip::runtime;
vsomeip::runtime::get*;
+ vsomeip::runtime::set_property*;
*vsomeip::application_impl;
vsomeip::application_impl*;
*vsomeip::eventgroupinfo;
diff --git a/implementation/configuration/include/client.hpp b/implementation/configuration/include/client.hpp
new file mode 100644
index 0000000..fcb4395
--- /dev/null
+++ b/implementation/configuration/include/client.hpp
@@ -0,0 +1,28 @@
+// 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_CFG_CLIENT_HPP
+#define VSOMEIP_CFG_CLIENT_HPP
+
+#include <map>
+#include <memory>
+#include <set>
+
+#include <vsomeip/primitive_types.hpp>
+
+namespace vsomeip {
+namespace cfg {
+
+struct client {
+ service_t service_;
+ instance_t instance_;
+
+ std::map<bool, std::set<uint16_t> > ports_;
+};
+
+} // namespace cfg
+} // namespace vsomeip
+
+#endif // VSOMEIP_CFG_CLIENT_HPP
diff --git a/implementation/configuration/include/configuration.hpp b/implementation/configuration/include/configuration.hpp
index 2f106ee..8dab1b4 100644
--- a/implementation/configuration/include/configuration.hpp
+++ b/implementation/configuration/include/configuration.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -19,6 +19,7 @@
#include <vsomeip/primitive_types.hpp>
#include "internal.hpp"
+#include "trace.hpp"
namespace vsomeip {
@@ -32,6 +33,7 @@ public:
virtual ~configuration() {}
virtual const boost::asio::ip::address & get_unicast_address() const = 0;
+ virtual unsigned short get_diagnosis_address() const = 0;
virtual bool is_v4() const = 0;
virtual bool is_v6() const = 0;
@@ -45,29 +47,36 @@ public:
virtual std::string get_unicast_address(service_t _service,
instance_t _instance) const = 0;
- virtual std::string get_multicast_address(service_t _service,
- instance_t _instance) const = 0;
- virtual uint16_t get_multicast_port(service_t _service,
- instance_t _instance) const = 0;
- virtual uint16_t get_multicast_group(service_t _service,
- instance_t _instance) const = 0;
virtual uint16_t get_reliable_port(service_t _service,
instance_t _instance) const = 0;
- virtual bool is_someip(service_t _service, instance_t _instance) const = 0;
virtual bool has_enabled_magic_cookies(std::string _address,
uint16_t _port) const = 0;
virtual uint16_t get_unreliable_port(service_t _service,
instance_t _instance) const = 0;
+ virtual bool is_someip(service_t _service, instance_t _instance) const = 0;
+
+ virtual bool get_client_port(
+ service_t _service, instance_t _instance, bool _reliable,
+ std::map<bool, std::set<uint16_t> > &_used, uint16_t &_port) const = 0;
+
virtual std::set<std::pair<service_t, instance_t> > get_remote_services() const = 0;
+ virtual bool get_multicast(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup, std::string &_address, uint16_t &_port) const = 0;
+
virtual client_t get_id(const std::string &_name) const = 0;
- virtual std::size_t get_num_dispatchers(const std::string &_name) const = 0;
+ virtual bool is_configured_client_id(client_t _id) const = 0;
+
+ virtual std::size_t get_max_dispatchers(const std::string &_name) const = 0;
+ virtual std::size_t get_max_dispatch_time(const std::string &_name) const = 0;
virtual std::uint32_t get_max_message_size_local() const = 0;
virtual std::uint32_t get_message_size_reliable(const std::string& _address,
std::uint16_t _port) const = 0;
+ virtual bool supports_selective_broadcasts(boost::asio::ip::address _address) const = 0;
+
// Service Discovery configuration
virtual bool is_sd_enabled() const = 0;
@@ -82,6 +91,18 @@ public:
virtual ttl_t get_sd_ttl() const = 0;
virtual int32_t get_sd_cyclic_offer_delay() const = 0;
virtual int32_t get_sd_request_response_delay() const = 0;
+
+ // Trace configuration
+ virtual std::shared_ptr<cfg::trace> get_trace() const = 0;
+
+ // Watchdog
+ virtual bool is_watchdog_enabled() const = 0;
+ virtual uint32_t get_watchdog_timeout() const = 0;
+ virtual uint32_t get_allowed_missing_pongs() const = 0;
+
+ // File permissions
+ virtual std::uint32_t get_umask() const = 0;
+ virtual std::uint32_t get_permissions_shm() const = 0;
};
} // namespace vsomeip
diff --git a/implementation/configuration/include/configuration_impl.hpp b/implementation/configuration/include/configuration_impl.hpp
index a6ca21c..87a1d15 100644
--- a/implementation/configuration/include/configuration_impl.hpp
+++ b/implementation/configuration/include/configuration_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -10,16 +10,31 @@
#include <memory>
#include <mutex>
#include <vector>
+#include <unordered_set>
#include <boost/property_tree/ptree.hpp>
+#include "trace.hpp"
#include "configuration.hpp"
+#include "watchdog.hpp"
namespace vsomeip {
namespace cfg {
+struct client;
struct service;
struct servicegroup;
+struct eventgroup;
+struct watchdog;
+
+struct element {
+ std::string name_;
+ boost::property_tree::ptree tree_;
+
+ bool operator<(const element &_other) const {
+ return (name_ < _other.name_);
+ }
+};
class configuration_impl: public configuration {
public:
@@ -31,10 +46,11 @@ public:
VSOMEIP_EXPORT configuration_impl(const configuration_impl &_cfg);
VSOMEIP_EXPORT virtual ~configuration_impl();
- VSOMEIP_EXPORT void load(const boost::property_tree::ptree &_tree);
- VSOMEIP_EXPORT void load_log(const std::vector<boost::property_tree::ptree> &_trees);
+ VSOMEIP_EXPORT void load(const element &_element);
+ VSOMEIP_EXPORT void load_log(const std::vector<element> &_elements);
VSOMEIP_EXPORT const boost::asio::ip::address & get_unicast_address() const;
+ VSOMEIP_EXPORT unsigned short get_diagnosis_address() const;
VSOMEIP_EXPORT bool is_v4() const;
VSOMEIP_EXPORT bool is_v6() const;
@@ -45,12 +61,6 @@ public:
VSOMEIP_EXPORT boost::log::trivial::severity_level get_loglevel() const;
VSOMEIP_EXPORT std::string get_unicast_address(service_t _service, instance_t _instance) const;
- VSOMEIP_EXPORT std::string get_multicast_address(service_t _service,
- instance_t _instance) const;
- VSOMEIP_EXPORT uint16_t get_multicast_port(service_t _service,
- instance_t _instance) const;
- VSOMEIP_EXPORT uint16_t get_multicast_group(service_t _service,
- instance_t _instance) const;
VSOMEIP_EXPORT uint16_t get_reliable_port(service_t _service, instance_t _instance) const;
VSOMEIP_EXPORT bool has_enabled_magic_cookies(std::string _address, uint16_t _port) const;
@@ -59,17 +69,28 @@ public:
VSOMEIP_EXPORT bool is_someip(service_t _service, instance_t _instance) const;
+ VSOMEIP_EXPORT bool get_client_port(service_t _service, instance_t _instance, bool _reliable,
+ std::map<bool, std::set<uint16_t> > &_used, uint16_t &_port) const;
+
VSOMEIP_EXPORT const std::string & get_routing_host() const;
VSOMEIP_EXPORT client_t get_id(const std::string &_name) const;
- VSOMEIP_EXPORT std::size_t get_num_dispatchers(const std::string &_name) const;
+ VSOMEIP_EXPORT bool is_configured_client_id(client_t _id) const;
+
+ VSOMEIP_EXPORT std::size_t get_max_dispatchers(const std::string &_name) const;
+ VSOMEIP_EXPORT std::size_t get_max_dispatch_time(const std::string &_name) const;
VSOMEIP_EXPORT std::set<std::pair<service_t, instance_t> > get_remote_services() const;
+ VSOMEIP_EXPORT bool get_multicast(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup, std::string &_address, uint16_t &_port) 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;
+
// Service Discovery configuration
VSOMEIP_EXPORT bool is_sd_enabled() const;
@@ -85,31 +106,65 @@ public:
VSOMEIP_EXPORT int32_t get_sd_cyclic_offer_delay() const;
VSOMEIP_EXPORT int32_t get_sd_request_response_delay() const;
+ // Trace configuration
+ VSOMEIP_EXPORT std::shared_ptr<cfg::trace> get_trace() const;
+
+ VSOMEIP_EXPORT bool is_watchdog_enabled() const;
+ VSOMEIP_EXPORT uint32_t get_watchdog_timeout() const;
+ VSOMEIP_EXPORT uint32_t get_allowed_missing_pongs() const;
+
+
+ VSOMEIP_EXPORT std::uint32_t get_umask() const;
+ VSOMEIP_EXPORT std::uint32_t get_permissions_shm() const;
+
private:
- void get_logging_configuration(const boost::property_tree::ptree &_tree);
+ void get_logging_configuration(const element &_element,
+ std::set<std::string> &_warnings);
- void get_someip_configuration(const boost::property_tree::ptree &_tree);
+ void get_someip_configuration(const element &_element);
void get_services_configuration(const boost::property_tree::ptree &_tree);
+ void get_clients_configuration(const boost::property_tree::ptree &_tree);
void get_payload_sizes_configuration(const boost::property_tree::ptree &_tree);
- void get_routing_configuration(const boost::property_tree::ptree &_tree);
- void get_service_discovery_configuration(
- const boost::property_tree::ptree &_tree);
- void get_applications_configuration(const boost::property_tree::ptree &_tree);
+ void get_routing_configuration(const element &_element);
+ void get_service_discovery_configuration(const element &_element);
+ void get_applications_configuration(const element &_tree);
+ void get_trace_configuration(const element &_tree);
+ void get_supports_selective_broadcasts(const boost::property_tree::ptree &_tree);
+ void get_watchdog_configuration(const element &_element);
void get_servicegroup_configuration(
const boost::property_tree::ptree &_tree);
void get_delays_configuration(const boost::property_tree::ptree &_tree);
void get_service_configuration(const boost::property_tree::ptree &_tree,
const std::string &_unicast_address);
+ void get_client_configuration(const boost::property_tree::ptree &_tree);
+ std::set<uint16_t> get_client_port_configuration(
+ const boost::property_tree::ptree &_tree);
void get_event_configuration(std::shared_ptr<service> &_service,
const boost::property_tree::ptree &_tree);
void get_eventgroup_configuration(std::shared_ptr<service> &_service,
const boost::property_tree::ptree &_tree);
void get_application_configuration(
+ const boost::property_tree::ptree &_tree, const std::string &_file_name);
+ void get_trace_channels_configuration(
const boost::property_tree::ptree &_tree);
-
- servicegroup * find_servicegroup(const std::string &_name) const;
- service * find_service(service_t _service, instance_t _instance) const;
+ void get_trace_channel_configuration(
+ const boost::property_tree::ptree &_tree);
+ void get_trace_filters_configuration(
+ const boost::property_tree::ptree &_tree);
+ void get_trace_filter_configuration(
+ const boost::property_tree::ptree &_tree);
+ void get_trace_filter_expressions(
+ const boost::property_tree::ptree &_tree,
+ std::string &_criteria,
+ std::shared_ptr<trace_filter_rule> &_filter_rule);
+ void get_permission_configuration(const element &_element);
+
+ servicegroup *find_servicegroup(const std::string &_name) const;
+ std::shared_ptr<client> find_client(service_t _service, instance_t _instance) const;
+ std::shared_ptr<service> find_service(service_t _service, instance_t _instance) const;
+ std::shared_ptr<eventgroup> find_eventgroup(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) const;
private:
static std::shared_ptr<configuration_impl> the_configuration;
@@ -118,6 +173,7 @@ private:
protected:
// Configuration data
boost::asio::ip::address unicast_;
+ unsigned short diagnosis_;
bool has_console_log_;
bool has_file_log_;
@@ -125,12 +181,17 @@ protected:
std::string logfile_;
boost::log::trivial::severity_level loglevel_;
- std::map<std::string, std::pair<client_t, std::size_t>> applications_;
+ std::map<std::string, std::tuple<client_t, std::size_t, std::size_t>> applications_;
+ std::set<client_t> client_identifiers_;
std::map<service_t,
std::map<instance_t,
std::shared_ptr<service> > > services_;
+ std::map<service_t,
+ std::map<instance_t,
+ std::shared_ptr<client> > > clients_;
+
std::string routing_host_;
bool is_sd_enabled_;
@@ -150,6 +211,42 @@ protected:
std::map<std::string, std::map<std::uint16_t, std::uint32_t>> message_sizes_;
std::uint32_t max_configured_message_size_;
+
+ std::shared_ptr<trace> trace_;
+
+ std::unordered_set<std::string> supported_selective_addresses;
+
+ std::shared_ptr<watchdog> watchdog_;
+
+ enum element_type_e {
+ ET_UNICAST,
+ ET_DIAGNOSIS,
+ ET_LOGGING_CONSOLE,
+ ET_LOGGING_FILE,
+ ET_LOGGING_DLT,
+ ET_LOGGING_LEVEL,
+ ET_ROUTING,
+ ET_SERVICE_DISCOVERY_ENABLE,
+ ET_SERVICE_DISCOVERY_PROTOCOL,
+ ET_SERVICE_DISCOVERY_MULTICAST,
+ ET_SERVICE_DISCOVERY_PORT,
+ ET_SERVICE_DISCOVERY_INITIAL_DELAY_MIN,
+ ET_SERVICE_DISCOVERY_INITIAL_DELAY_MAX,
+ ET_SERVICE_DISCOVERY_REPETITION_BASE_DELAY,
+ ET_SERVICE_DISCOVERY_REPETITION_MAX,
+ ET_SERVICE_DISCOVERY_TTL,
+ ET_SERVICE_DISCOVERY_CYCLIC_OFFER_DELAY,
+ ET_SERVICE_DISCOVERY_REQUEST_RESPONSE_DELAY,
+ ET_WATCHDOG_ENABLE,
+ ET_WATCHDOG_TIMEOUT,
+ ET_WATCHDOG_ALLOWED_MISSING_PONGS,
+ ET_TRACING_ENABLE,
+ ET_MAX = 22
+ };
+
+ bool is_configured_[ET_MAX];
+ std::uint32_t permissions_shm_;
+ std::uint32_t umask_;
};
} // namespace cfg
diff --git a/implementation/configuration/include/event.hpp b/implementation/configuration/include/event.hpp
index e932289..d488ec4 100644
--- a/implementation/configuration/include/event.hpp
+++ b/implementation/configuration/include/event.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/configuration/include/eventgroup.hpp b/implementation/configuration/include/eventgroup.hpp
index 27bf722..93a91a3 100644
--- a/implementation/configuration/include/eventgroup.hpp
+++ b/implementation/configuration/include/eventgroup.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -18,6 +18,8 @@ struct event;
struct eventgroup {
eventgroup_t id_;
std::set<std::shared_ptr<event> > events_;
+ std::string multicast_address_;
+ uint16_t multicast_port_;
};
} // namespace cfg
diff --git a/implementation/configuration/include/internal.hpp.in b/implementation/configuration/include/internal.hpp.in
index 64b7105..d7770c9 100644
--- a/implementation/configuration/include/internal.hpp.in
+++ b/implementation/configuration/include/internal.hpp.in
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -26,20 +26,25 @@
#define VSOMEIP_ROUTING "@VSOMEIP_ROUTING@"
#define VSOMEIP_ROUTING_CLIENT 0
+#define VSOMEIP_ROUTING_INFO_SIZE_INIT 256
#ifdef WIN32
#define VSOMEIP_INTERNAL_BASE_PORT 51234
+#define __func__ __FUNCTION__
#endif
#define VSOMEIP_UNICAST_ADDRESS "@VSOMEIP_UNICAST_ADDRESS@"
#define VSOMEIP_DEFAULT_CONNECT_TIMEOUT 100
+#define VSOMEIP_MAX_CONNECT_TIMEOUT 1000
#define VSOMEIP_DEFAULT_FLUSH_TIMEOUT 1000
-#define VSOMEIP_DEFAULT_WATCHDOG_CYCLE 5000
#define VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT 5000
#define VSOMEIP_DEFAULT_MAX_MISSING_PONGS 3
+#define VSOMEIP_MAX_DISPATCHERS 10
+#define VSOMEIP_MAX_DISPATCH_TIME 100
+
#define VSOMEIP_COMMAND_HEADER_SIZE 7
#define VSOMEIP_COMMAND_TYPE_POS 0
@@ -62,33 +67,53 @@
#define VSOMEIP_UNSUBSCRIBE 0x13
#define VSOMEIP_REQUEST_SERVICE 0x14
#define VSOMEIP_RELEASE_SERVICE 0x15
-
-#define VSOMEIP_SEND 0x17
-#define VSOMEIP_NOTIFY 0x18
-
-#define VSOMEIP_REGISTER_EVENT 0x19
-#define VSOMEIP_UNREGISTER_EVENT 0x1A
-
-#define VSOMEIP_OFFER_SERVICE_COMMAND_SIZE 20
-#define VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE 21
-#define VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE 11
-#define VSOMEIP_SUBSCRIBE_COMMAND_SIZE 19
+#define VSOMEIP_SUBSCRIBE_NACK 0x16
+#define VSOMEIP_SUBSCRIBE_ACK 0x17
+
+#define VSOMEIP_SEND 0x18
+#define VSOMEIP_NOTIFY 0x19
+#define VSOMEIP_NOTIFY_ONE 0x1A
+
+#define VSOMEIP_REGISTER_EVENT 0x1B
+#define VSOMEIP_UNREGISTER_EVENT 0x1C
+#define VSOMEIP_ID_RESPONSE 0x1D
+
+#define VSOMEIP_OFFER_SERVICE_COMMAND_SIZE 16
+#define VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE 17
+#define VSOMEIP_RELEASE_SERVICE_COMMAND_SIZE 11
+#define VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE 16
+#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_REGISTER_EVENT_COMMAND_SIZE 15
-#define VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE 13
+#define VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE 14
-#include <mutex>
+#ifndef WIN32
+#include <pthread.h>
+#endif
#define VSOMEIP_DATA_ID 0x677D
#define VSOMEIP_SHM_NAME "/vsomeip"
#define VSOMEIP_DIAGNOSIS_ADDRESS @VSOMEIP_DIAGNOSIS_ADDRESS@
+#define VSOMEIP_DEFAULT_SHM_PERMISSION 0666
+#define VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS 0000
+
+#define VSOMEIP_MAX_CLIENTS 255
+
namespace vsomeip {
struct configuration_data_t {
- std::mutex mutex_;
- unsigned short next_client_id_;
- unsigned short ref_;
+#ifdef WIN32
+ void* mutex_;
+#else
+ pthread_mutex_t mutex_;
+#endif
+ unsigned short client_base_;
+
+ unsigned short used_client_ids_[VSOMEIP_MAX_CLIENTS];
+ int max_used_client_ids_index_;
};
} // namespace vsomeip
diff --git a/implementation/configuration/include/service.hpp b/implementation/configuration/include/service.hpp
index bbe235e..8e72a02 100644
--- a/implementation/configuration/include/service.hpp
+++ b/implementation/configuration/include/service.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -27,7 +27,6 @@ struct service {
std::string multicast_address_;
uint16_t multicast_port_;
- eventgroup_t multicast_group_;
std::string protocol_;
diff --git a/implementation/configuration/include/trace.hpp b/implementation/configuration/include/trace.hpp
new file mode 100644
index 0000000..cba4da8
--- /dev/null
+++ b/implementation/configuration/include/trace.hpp
@@ -0,0 +1,62 @@
+// 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 CONFIGURATION_INCLUDE_TRACE_HPP_
+#define CONFIGURATION_INCLUDE_TRACE_HPP_
+
+#include <vsomeip/primitive_types.hpp>
+
+#include "../../tracing/include/defines.hpp"
+
+namespace vsomeip {
+namespace cfg {
+
+struct trace_channel {
+
+ trace_channel() :
+ id_(VSOMEIP_TC_DEFAULT_CHANNEL_ID),
+ name_(VSOMEIP_TC_DEFAULT_CHANNEL_NAME) {
+
+ }
+
+ trace_channel_t id_;
+ std::string name_;
+};
+
+struct trace_filter_rule {
+
+ trace_filter_rule() :
+ channel_(VSOMEIP_TC_DEFAULT_CHANNEL_ID),
+ services_(),
+ methods_(),
+ clients_() {
+
+ }
+
+ trace_channel_t channel_;
+ std::vector<service_t> services_;
+ std::vector<method_t> methods_;
+ std::vector<client_t> clients_;
+};
+
+struct trace {
+
+ trace() :
+ channels_(),
+ filter_rules_(),
+ is_enabled_(false) {
+ channels_.push_back(std::make_shared<trace_channel>());
+ }
+
+ std::vector<std::shared_ptr<trace_channel>> channels_;
+ std::vector<std::shared_ptr<trace_filter_rule>> filter_rules_;
+
+ bool is_enabled_;
+};
+
+} // namespace cfg
+} // namespace vsomeip
+
+#endif /* CONFIGURATION_INCLUDE_TRACE_HPP_ */
diff --git a/implementation/configuration/include/watchdog.hpp b/implementation/configuration/include/watchdog.hpp
new file mode 100644
index 0000000..1d5696d
--- /dev/null
+++ b/implementation/configuration/include/watchdog.hpp
@@ -0,0 +1,21 @@
+// 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_WATCHDOG_HPP_
+#define VSOMEIP_CFG_WATCHDOG_HPP_
+
+namespace vsomeip {
+namespace cfg {
+
+struct watchdog {
+ bool is_enabeled_;
+ uint32_t timeout_in_ms_;
+ uint32_t missing_pongs_allowed_;
+};
+
+} // namespace cfg
+} // namespace vsomeip
+
+#endif /* VSOMEIP_CFG_WATCHDOG_HPP_ */
diff --git a/implementation/configuration/src/configuration.cpp b/implementation/configuration/src/configuration.cpp
index 9bc90d4..0994dcd 100644
--- a/implementation/configuration/src/configuration.cpp
+++ b/implementation/configuration/src/configuration.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/configuration/src/configuration_impl.cpp b/implementation/configuration/src/configuration_impl.cpp
index 66a1219..3c78de0 100644
--- a/implementation/configuration/src/configuration_impl.cpp
+++ b/implementation/configuration/src/configuration_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -9,10 +9,6 @@
#define WIN32_LEAN_AND_MEAN
-#if defined ( WIN32 )
-#define __func__ __FUNCTION__
-#endif
-
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
@@ -20,6 +16,7 @@
#include <vsomeip/constants.hpp>
+#include "../include/client.hpp"
#include "../include/configuration_impl.hpp"
#include "../include/event.hpp"
#include "../include/eventgroup.hpp"
@@ -41,9 +38,12 @@ std::shared_ptr<configuration> configuration_impl::get(
std::shared_ptr<configuration> its_configuration;
std::lock_guard<std::mutex> its_lock(mutex_);
+ std::set<std::string> failed_files;
+ static bool has_reading_failed(false);
+
if (!the_configuration) {
the_configuration = std::make_shared<configuration_impl>();
- std::vector<boost::property_tree::ptree> its_tree_set;
+ std::vector<element> its_configuration_elements;
// Load logger configuration first
for (auto i : _input) {
@@ -51,9 +51,13 @@ std::shared_ptr<configuration> configuration_impl::get(
boost::property_tree::ptree its_tree;
try {
boost::property_tree::json_parser::read_json(i, its_tree);
- its_tree_set.push_back(its_tree);
+ its_configuration_elements.push_back({ i, its_tree });
}
- catch (...) {
+ catch (boost::property_tree::json_parser_error &e) {
+#ifdef WIN32
+ e; // silence MSVC warining C4101
+#endif
+ failed_files.insert(i);
}
} else if (utility::is_folder(i)) {
boost::filesystem::path its_path(i);
@@ -66,9 +70,10 @@ std::shared_ptr<configuration> configuration_impl::get(
boost::property_tree::ptree its_tree;
try {
boost::property_tree::json_parser::read_json(its_name, its_tree);
- its_tree_set.push_back(its_tree);
+ its_configuration_elements.push_back({its_name, its_tree});
}
catch (...) {
+ failed_files.insert(its_name);
}
}
}
@@ -76,13 +81,28 @@ std::shared_ptr<configuration> configuration_impl::get(
}
// Load log configuration
- the_configuration->load_log(its_tree_set);
-
- // Load other configuration parts
- for (auto t : its_tree_set)
- the_configuration->load(t);
+ the_configuration->load_log(its_configuration_elements);
+
+ // Check whether reading of configuration file(s) succeeded.
+ if (!failed_files.empty()) {
+ has_reading_failed = true;
+ for (auto its_failed : failed_files)
+ VSOMEIP_ERROR << "Reading of configuration file \""
+ << its_failed << "\" failed.";
+ } else {
+ // Load other configuration parts
+ std::sort(its_configuration_elements.begin(),
+ its_configuration_elements.end());
+ for (auto e : its_configuration_elements)
+ the_configuration->load(e);
+ }
}
+ // There is only one attempt to read the configuration file(s).
+ // If it has failed, we must not return the configuration object.
+ if (has_reading_failed)
+ return nullptr;
+
return the_configuration;
}
@@ -91,6 +111,7 @@ void configuration_impl::reset() {
}
configuration_impl::configuration_impl() :
+ diagnosis_(VSOMEIP_DIAGNOSIS_ADDRESS),
has_console_log_(true),
has_file_log_(false),
has_dlt_log_(false),
@@ -107,18 +128,26 @@ configuration_impl::configuration_impl() :
sd_ttl_(VSOMEIP_SD_DEFAULT_TTL),
sd_cyclic_offer_delay_(VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY),
sd_request_response_delay_(VSOMEIP_SD_DEFAULT_REQUEST_RESPONSE_DELAY),
- max_configured_message_size_(0) {
-
+ max_configured_message_size_(0),
+ trace_(std::make_shared<trace>()),
+ watchdog_(std::make_shared<watchdog>()),
+ permissions_shm_(VSOMEIP_DEFAULT_SHM_PERMISSION),
+ umask_(VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS) {
unicast_ = unicast_.from_string(VSOMEIP_UNICAST_ADDRESS);
+ for (auto i = 0; i < ET_MAX; i++)
+ is_configured_[i] = false;
}
configuration_impl::configuration_impl(const configuration_impl &_other) :
- max_configured_message_size_(0) {
+ max_configured_message_size_(0),
+ permissions_shm_(VSOMEIP_DEFAULT_SHM_PERMISSION),
+ umask_(VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS) {
applications_.insert(_other.applications_.begin(), _other.applications_.end());
services_.insert(_other.services_.begin(), _other.services_.end());
unicast_ = _other.unicast_;
+ diagnosis_ = _other.diagnosis_;
has_console_log_ = _other.has_console_log_;
has_file_log_ = _other.has_file_log_;
@@ -142,72 +171,116 @@ configuration_impl::configuration_impl(const configuration_impl &_other) :
sd_cyclic_offer_delay_= _other.sd_cyclic_offer_delay_;
sd_request_response_delay_= _other.sd_request_response_delay_;
+ trace_ = std::make_shared<trace>(*_other.trace_.get());
+ watchdog_ = std::make_shared<watchdog>(*_other.watchdog_.get());
+
magic_cookies_.insert(_other.magic_cookies_.begin(), _other.magic_cookies_.end());
+
+ for (auto i = 0; i < ET_MAX; i++)
+ is_configured_[i] = _other.is_configured_[i];
}
configuration_impl::~configuration_impl() {
}
-void configuration_impl::load(const boost::property_tree::ptree &_tree) {
+void configuration_impl::load(const element &_element) {
try {
// Read the configuration data
- get_someip_configuration(_tree);
- get_services_configuration(_tree);
- get_payload_sizes_configuration(_tree);
- get_routing_configuration(_tree);
- get_service_discovery_configuration(_tree);
- get_applications_configuration(_tree);
+ get_someip_configuration(_element);
+ get_services_configuration(_element.tree_);
+ get_clients_configuration(_element.tree_);
+ get_payload_sizes_configuration(_element.tree_);
+ get_routing_configuration(_element);
+ get_permission_configuration(_element);
+ get_service_discovery_configuration(_element);
+ get_applications_configuration(_element);
+ get_trace_configuration(_element);
+ get_supports_selective_broadcasts(_element.tree_);
+ get_watchdog_configuration(_element);
} catch (std::exception &e) {
+#ifdef WIN32
+ e; // silence MSVC warning C4101
+#endif
}
}
-void configuration_impl::load_log(const std::vector<boost::property_tree::ptree> &_trees) {
+void configuration_impl::load_log(const std::vector<element> &_elements) {
+ std::set<std::string> its_warnings;
+
// Read the logger configuration(s)
- for (auto t : _trees)
- get_logging_configuration(t);
+ for (auto e : _elements)
+ get_logging_configuration(e, its_warnings);
// Initialize logger
logger_impl::init(the_configuration);
+
+ // Print warnings after(!) logger initialization
+ for (auto w : its_warnings)
+ VSOMEIP_WARNING << w;
}
void configuration_impl::get_logging_configuration(
- const boost::property_tree::ptree &_tree) {
+ const element &_element, std::set<std::string> &_warnings) {
try {
- auto its_logging = _tree.get_child("logging");
+ auto its_logging = _element.tree_.get_child("logging");
for (auto i = its_logging.begin(); i != its_logging.end(); ++i) {
std::string its_key(i->first);
if (its_key == "console") {
- std::string its_value(i->second.data());
- has_console_log_ = (its_value == "true");
+ if (is_configured_[ET_LOGGING_CONSOLE]) {
+ _warnings.insert("Multiple definitions for logging.console."
+ " Ignoring definition from " + _element.name_);
+ } else {
+ std::string its_value(i->second.data());
+ has_console_log_ = (its_value == "true");
+ is_configured_[ET_LOGGING_CONSOLE] = true;
+ }
} else if (its_key == "file") {
- 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") {
- has_file_log_ = (its_sub_value == "true");
- } else if (its_sub_key == "path") {
- logfile_ = its_sub_value;
+ if (is_configured_[ET_LOGGING_FILE]) {
+ _warnings.insert("Multiple definitions for logging.file."
+ " Ignoring definition from " + _element.name_);
+ } else {
+ 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") {
+ has_file_log_ = (its_sub_value == "true");
+ } else if (its_sub_key == "path") {
+ logfile_ = its_sub_value;
+ }
}
+ is_configured_[ET_LOGGING_FILE] = true;
}
} else if (its_key == "dlt") {
- std::string its_value(i->second.data());
- has_dlt_log_ = (its_value == "true");
+ if (is_configured_[ET_LOGGING_DLT]) {
+ _warnings.insert("Multiple definitions for logging.dlt."
+ " Ignoring definition from " + _element.name_);
+ } else {
+ std::string its_value(i->second.data());
+ has_dlt_log_ = (its_value == "true");
+ is_configured_[ET_LOGGING_DLT] = true;
+ }
} else if (its_key == "level") {
- std::string its_value(i->second.data());
- loglevel_
- = (its_value == "trace" ?
- boost::log::trivial::severity_level::trace :
- (its_value == "debug" ?
- boost::log::trivial::severity_level::debug :
- (its_value == "info" ?
- boost::log::trivial::severity_level::info :
- (its_value == "warning" ?
- boost::log::trivial::severity_level::warning :
- (its_value == "error" ?
- boost::log::trivial::severity_level::error :
- (its_value == "fatal" ?
- boost::log::trivial::severity_level::fatal :
- boost::log::trivial::severity_level::info))))));
+ if (is_configured_[ET_LOGGING_LEVEL]) {
+ _warnings.insert("Multiple definitions for logging.level."
+ " Ignoring definition from " + _element.name_);
+ } else {
+ std::string its_value(i->second.data());
+ loglevel_
+ = (its_value == "trace" ?
+ boost::log::trivial::severity_level::trace :
+ (its_value == "debug" ?
+ boost::log::trivial::severity_level::debug :
+ (its_value == "info" ?
+ boost::log::trivial::severity_level::info :
+ (its_value == "warning" ?
+ boost::log::trivial::severity_level::warning :
+ (its_value == "error" ?
+ boost::log::trivial::severity_level::error :
+ (its_value == "fatal" ?
+ boost::log::trivial::severity_level::fatal :
+ boost::log::trivial::severity_level::info))))));
+ is_configured_[ET_LOGGING_LEVEL] = true;
+ }
}
}
} catch (...) {
@@ -215,10 +288,34 @@ void configuration_impl::get_logging_configuration(
}
void configuration_impl::get_someip_configuration(
- const boost::property_tree::ptree &_tree) {
+ const element &_element) {
+ try {
+ if (is_configured_[ET_UNICAST]) {
+ VSOMEIP_WARNING << "Multiple definitions for unicast."
+ "Ignoring definition from " << _element.name_;
+ } else {
+ std::string its_value = _element.tree_.get<std::string>("unicast");
+ unicast_ = unicast_.from_string(its_value);
+ is_configured_[ET_UNICAST] = true;
+ }
+ } catch (...) {
+ }
try {
- std::string its_value = _tree.get<std::string>("unicast");
- unicast_ = unicast_.from_string(its_value);
+ if (is_configured_[ET_DIAGNOSIS]) {
+ VSOMEIP_WARNING << "Multiple definitions for diagnosis."
+ "Ignoring definition from " << _element.name_;
+ } else {
+ std::string its_value = _element.tree_.get<std::string>("diagnosis");
+ std::stringstream its_converter;
+
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
+ its_converter << std::hex << its_value;
+ } else {
+ its_converter << std::dec << its_value;
+ }
+ its_converter >> diagnosis_;
+ is_configured_[ET_DIAGNOSIS] = true;
+ }
} catch (...) {
}
}
@@ -240,6 +337,17 @@ void configuration_impl::get_services_configuration(
}
}
+void configuration_impl::get_clients_configuration(
+ const boost::property_tree::ptree &_tree) {
+ try {
+ auto its_clients = _tree.get_child("clients");
+ for (auto i = its_clients.begin(); i != its_clients.end(); ++i)
+ get_client_configuration(i->second);
+ } catch (...) {
+ // intentionally left empty!
+ }
+}
+
void configuration_impl::get_payload_sizes_configuration(
const boost::property_tree::ptree &_tree) {
const std::string payload_sizes("payload-sizes");
@@ -364,7 +472,6 @@ void configuration_impl::get_service_configuration(
its_service->unicast_address_ = _unicast_address;
its_service->multicast_address_ = "";
its_service->multicast_port_ = ILLEGAL_PORT;
- its_service->multicast_group_ = 0xFFFF; // TODO: use symbolic constant
its_service->protocol_ = "someip";
for (auto i = _tree.begin(); i != _tree.end(); ++i) {
@@ -383,6 +490,9 @@ void configuration_impl::get_service_configuration(
its_converter << its_value;
its_converter >> its_service->reliable_;
}
+ if(!its_service->reliable_) {
+ its_service->reliable_ = ILLEGAL_PORT;
+ }
try {
its_value
= i->second.get_child("enable-magic-cookies").data();
@@ -393,6 +503,9 @@ void configuration_impl::get_service_configuration(
} else if (its_key == "unreliable") {
its_converter << its_value;
its_converter >> its_service->unreliable_;
+ if(!its_service->unreliable_) {
+ its_service->unreliable_ = ILLEGAL_PORT;
+ }
} else if (its_key == "multicast") {
try {
its_value = i->second.get_child("address").data();
@@ -410,7 +523,7 @@ void configuration_impl::get_service_configuration(
get_eventgroup_configuration(its_service, i->second);
} else {
// Trim "its_value"
- if (its_value[0] == '0' && its_value[1] == 'x') {
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
its_converter << std::hex << its_value;
} else {
its_converter << std::dec << its_value;
@@ -429,6 +542,9 @@ void configuration_impl::get_service_configuration(
auto found_instance = found_service->second.find(
its_service->instance_);
if (found_instance != found_service->second.end()) {
+ VSOMEIP_WARNING << "Multiple configurations for service ["
+ << std::hex << its_service->service_ << "."
+ << its_service->instance_ << "]";
is_loaded = false;
}
}
@@ -437,14 +553,84 @@ void configuration_impl::get_service_configuration(
services_[its_service->service_][its_service->instance_] =
its_service;
if (use_magic_cookies) {
- magic_cookies_[its_service->unicast_address_].insert(
- its_service->reliable_);
+ magic_cookies_[get_unicast_address(its_service->service_,
+ its_service->instance_)].insert(its_service->reliable_);
}
}
} catch (...) {
}
}
+void configuration_impl::get_client_configuration(
+ const boost::property_tree::ptree &_tree) {
+ try {
+ bool is_loaded(true);
+
+ std::shared_ptr<client> its_client(std::make_shared<client>());
+
+ for (auto i = _tree.begin(); i != _tree.end(); ++i) {
+ std::string its_key(i->first);
+ std::string its_value(i->second.data());
+ std::stringstream its_converter;
+
+ if (its_key == "reliable") {
+ its_client->ports_[true] = get_client_port_configuration(i->second);
+ } else if (its_key == "unreliable") {
+ its_client->ports_[false] = get_client_port_configuration(i->second);
+ } else {
+ // Trim "its_value"
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
+ its_converter << std::hex << its_value;
+ } else {
+ its_converter << std::dec << its_value;
+ }
+
+ if (its_key == "service") {
+ its_converter >> its_client->service_;
+ } else if (its_key == "instance") {
+ its_converter >> its_client->instance_;
+ }
+ }
+ }
+
+ auto found_service = clients_.find(its_client->service_);
+ if (found_service != clients_.end()) {
+ auto found_instance = found_service->second.find(
+ its_client->instance_);
+ if (found_instance != found_service->second.end()) {
+ VSOMEIP_ERROR << "Multiple client configurations for service ["
+ << std::hex << its_client->service_ << "."
+ << its_client->instance_ << "]";
+ is_loaded = false;
+ }
+ }
+
+ if (is_loaded) {
+ clients_[its_client->service_][its_client->instance_] = its_client;
+ }
+ } catch (...) {
+ }
+}
+
+std::set<uint16_t> configuration_impl::get_client_port_configuration(
+ const boost::property_tree::ptree &_tree) {
+ std::set<uint16_t> its_ports;
+ for (auto i = _tree.begin(); i != _tree.end(); ++i) {
+ std::string its_value(i->second.data());
+ uint16_t its_port_value;
+
+ std::stringstream its_converter;
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
+ its_converter << std::hex << its_value;
+ } else {
+ its_converter << std::dec << its_value;
+ }
+ its_converter >> its_port_value;
+ its_ports.insert(its_port_value);
+ }
+ return its_ports;
+}
+
void configuration_impl::get_event_configuration(
std::shared_ptr<service> &_service,
const boost::property_tree::ptree &_tree) {
@@ -458,7 +644,7 @@ void configuration_impl::get_event_configuration(
std::string its_value(j->second.data());
if (its_key == "event") {
std::stringstream its_converter;
- if (its_value[0] == '0' && its_value[1] == 'x') {
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
its_converter << std::hex << its_value;
} else {
its_converter << std::dec << its_value;
@@ -474,7 +660,10 @@ void configuration_impl::get_event_configuration(
if (its_event_id > 0) {
auto found_event = _service->events_.find(its_event_id);
if (found_event != _service->events_.end()) {
- found_event->second->is_field_ = its_is_field;
+ VSOMEIP_ERROR << "Multiple configurations for event ["
+ << std::hex << _service->service_ << "."
+ << _service->instance_ << "."
+ << its_event_id << "]";
} else {
std::shared_ptr<event> its_event = std::make_shared<event>(
its_event_id, its_is_field, its_is_reliable);
@@ -487,17 +676,16 @@ void configuration_impl::get_event_configuration(
void configuration_impl::get_eventgroup_configuration(
std::shared_ptr<service> &_service,
const boost::property_tree::ptree &_tree) {
- bool is_multicast;
for (auto i = _tree.begin(); i != _tree.end(); ++i) {
- is_multicast = false;
std::shared_ptr<eventgroup> its_eventgroup =
std::make_shared<eventgroup>();
for (auto j = i->second.begin(); j != i->second.end(); ++j) {
+ std::stringstream its_converter;
std::string its_key(j->first);
if (its_key == "eventgroup") {
- std::stringstream its_converter;
+
std::string its_value(j->second.data());
- if (its_value[0] == '0' && its_value[1] == 'x') {
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
its_converter << std::hex << its_value;
} else {
its_converter << std::dec << its_value;
@@ -505,13 +693,25 @@ void configuration_impl::get_eventgroup_configuration(
its_converter >> its_eventgroup->id_;
} else if (its_key == "is_multicast") {
std::string its_value(j->second.data());
- is_multicast = (its_value == "true");
+ if (its_value == "true") {
+ its_eventgroup->multicast_address_ = _service->multicast_address_;
+ its_eventgroup->multicast_port_ = _service->multicast_port_;
+ }
+ } else if (its_key == "multicast") {
+ try {
+ std::string its_value = j->second.get_child("address").data();
+ its_eventgroup->multicast_address_ = its_value;
+ its_value = j->second.get_child("port").data();
+ its_converter << its_value;
+ its_converter >> its_eventgroup->multicast_port_;
+ } catch (...) {
+ }
} else if (its_key == "events") {
for (auto k = j->second.begin(); k != j->second.end(); ++k) {
std::stringstream its_converter;
std::string its_value(k->second.data());
event_t its_event_id(0);
- if (its_value[0] == '0' && its_value[1] == 'x') {
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
its_converter << std::hex << its_value;
} else {
its_converter << std::dec << its_value;
@@ -537,64 +737,170 @@ void configuration_impl::get_eventgroup_configuration(
}
if (its_eventgroup->id_ > 0) {
- if (is_multicast) {
- _service->multicast_group_ = its_eventgroup->id_;
- }
_service->eventgroups_[its_eventgroup->id_] = its_eventgroup;
}
}
}
-void configuration_impl::get_routing_configuration(
- const boost::property_tree::ptree &_tree) {
+void configuration_impl::get_routing_configuration(const element &_element) {
try {
- auto its_routing = _tree.get_child("routing");
- routing_host_ = its_routing.data();
+ if (is_configured_[ET_ROUTING]) {
+ VSOMEIP_WARNING << "Multiple definitions of routing."
+ << " Ignoring definition from " << _element.name_;
+ } else {
+ auto its_routing = _element.tree_.get_child("routing");
+ routing_host_ = its_routing.data();
+ is_configured_[ET_ROUTING] = true;
+ }
} catch (...) {
}
}
+void configuration_impl::get_permission_configuration(const element &_element) {
+ const std::string file_permissions("file-permissions");
+ try {
+ if (_element.tree_.get_child_optional(file_permissions)) {
+ auto its_permissions = _element.tree_.get_child(file_permissions);
+ for (auto i = its_permissions.begin(); i != its_permissions.end();
+ ++i) {
+ std::string its_key(i->first);
+ std::stringstream its_converter;
+ if (its_key == "permissions-shm") {
+ std::string its_value(i->second.data());
+ its_converter << std::oct << its_value;
+ its_converter >> permissions_shm_;
+ } else if (its_key == "umask") {
+ std::string its_value(i->second.data());
+ its_converter << std::oct << its_value;
+ its_converter >> umask_;
+ }
+ }
+ }
+ } catch (...) {
+ }
+}
+
+std::uint32_t configuration_impl::get_umask() const {
+ return umask_;
+}
+
+std::uint32_t configuration_impl::get_permissions_shm() const {
+ return permissions_shm_;
+}
+
void configuration_impl::get_service_discovery_configuration(
- const boost::property_tree::ptree &_tree) {
+ const element &_element) {
try {
- auto its_service_discovery = _tree.get_child("service-discovery");
+ auto its_service_discovery = _element.tree_.get_child("service-discovery");
for (auto i = its_service_discovery.begin();
i != its_service_discovery.end(); ++i) {
std::string its_key(i->first);
std::string its_value(i->second.data());
std::stringstream its_converter;
if (its_key == "enable") {
- is_sd_enabled_ = (its_value == "true");
+ if (is_configured_[ET_SERVICE_DISCOVERY_ENABLE]) {
+ VSOMEIP_WARNING << "Multiple definitions for service_discovery.enabled."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ is_sd_enabled_ = (its_value == "true");
+ is_configured_[ET_SERVICE_DISCOVERY_ENABLE] = true;
+ }
} else if (its_key == "multicast") {
- sd_multicast_ = its_value;
+ if (is_configured_[ET_SERVICE_DISCOVERY_MULTICAST]) {
+ VSOMEIP_WARNING << "Multiple definitions for service_discovery.multicast."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ sd_multicast_ = its_value;
+ is_configured_[ET_SERVICE_DISCOVERY_MULTICAST] = true;
+ }
} else if (its_key == "port") {
- its_converter << its_value;
- its_converter >> sd_port_;
+ if (is_configured_[ET_SERVICE_DISCOVERY_PORT]) {
+ VSOMEIP_WARNING << "Multiple definitions for service_discovery.port."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ its_converter << its_value;
+ its_converter >> sd_port_;
+ if (!sd_port_) {
+ sd_port_ = VSOMEIP_SD_DEFAULT_PORT;
+ } else {
+ is_configured_[ET_SERVICE_DISCOVERY_PORT] = true;
+ }
+ }
} else if (its_key == "protocol") {
- sd_protocol_ = its_value;
+ if (is_configured_[ET_SERVICE_DISCOVERY_PROTOCOL]) {
+ VSOMEIP_WARNING << "Multiple definitions for service_discovery.protocol."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ sd_protocol_ = its_value;
+ is_configured_[ET_SERVICE_DISCOVERY_PROTOCOL] = true;
+ }
} else if (its_key == "initial_delay_min") {
- its_converter << its_value;
- its_converter >> sd_initial_delay_min_;
+ if (is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MIN]) {
+ VSOMEIP_WARNING << "Multiple definitions for service_discovery.initial_delay_min."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ its_converter << its_value;
+ its_converter >> sd_initial_delay_min_;
+ is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MIN] = true;
+ }
} else if (its_key == "initial_delay_max") {
- its_converter << its_value;
- its_converter >> sd_initial_delay_max_;
+ if (is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MAX]) {
+ VSOMEIP_WARNING << "Multiple definitions for service_discovery.initial_delay_max."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ its_converter << its_value;
+ its_converter >> sd_initial_delay_max_;
+ is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MAX] = true;
+ }
} else if (its_key == "repetitions_base_delay") {
- its_converter << its_value;
- its_converter >> sd_repetitions_base_delay_;
+ if (is_configured_[ET_SERVICE_DISCOVERY_REPETITION_BASE_DELAY]) {
+ VSOMEIP_WARNING << "Multiple definitions for service_discovery.repetition_base_delay."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ its_converter << its_value;
+ its_converter >> sd_repetitions_base_delay_;
+ is_configured_[ET_SERVICE_DISCOVERY_REPETITION_BASE_DELAY] = true;
+ }
} else if (its_key == "repetitions_max") {
- int tmp;
- its_converter << its_value;
- its_converter >> tmp;
- sd_repetitions_max_ = (uint8_t)tmp;
+ if (is_configured_[ET_SERVICE_DISCOVERY_REPETITION_MAX]) {
+ VSOMEIP_WARNING << "Multiple definitions for service_discovery.repetition_max."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ int tmp;
+ its_converter << its_value;
+ its_converter >> tmp;
+ sd_repetitions_max_ = (uint8_t)tmp;
+ is_configured_[ET_SERVICE_DISCOVERY_REPETITION_MAX] = true;
+ }
} else if (its_key == "ttl") {
- its_converter << its_value;
- its_converter >> sd_ttl_;
+ if (is_configured_[ET_SERVICE_DISCOVERY_TTL]) {
+ VSOMEIP_WARNING << "Multiple definitions for service_discovery.ttl."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ its_converter << its_value;
+ its_converter >> sd_ttl_;
+ // We do _not_ accept 0 as this would mean "STOP OFFER"
+ if (sd_ttl_ == 0) sd_ttl_ = VSOMEIP_SD_DEFAULT_TTL;
+ else is_configured_[ET_SERVICE_DISCOVERY_TTL] = true;
+ }
} else if (its_key == "cyclic_offer_delay") {
- its_converter << its_value;
- its_converter >> sd_cyclic_offer_delay_;
+ if (is_configured_[ET_SERVICE_DISCOVERY_CYCLIC_OFFER_DELAY]) {
+ VSOMEIP_WARNING << "Multiple definitions for service_discovery.cyclic_offer_delay."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ its_converter << its_value;
+ its_converter >> sd_cyclic_offer_delay_;
+ is_configured_[ET_SERVICE_DISCOVERY_CYCLIC_OFFER_DELAY] = true;
+ }
} else if (its_key == "request_response_delay") {
- its_converter << its_value;
- its_converter >> sd_request_response_delay_;
+ if (is_configured_[ET_SERVICE_DISCOVERY_REQUEST_RESPONSE_DELAY]) {
+ VSOMEIP_WARNING << "Multiple definitions for service_discovery.request_response_delay."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ its_converter << its_value;
+ its_converter >> sd_request_response_delay_;
+ is_configured_[ET_SERVICE_DISCOVERY_REQUEST_RESPONSE_DELAY] = true;
+ }
}
}
} catch (...) {
@@ -602,24 +908,25 @@ void configuration_impl::get_service_discovery_configuration(
}
void configuration_impl::get_applications_configuration(
- const boost::property_tree::ptree &_tree) {
+ const element &_element) {
try {
std::stringstream its_converter;
- auto its_applications = _tree.get_child("applications");
+ auto its_applications = _element.tree_.get_child("applications");
for (auto i = its_applications.begin();
i != its_applications.end();
++i) {
- get_application_configuration(i->second);
+ get_application_configuration(i->second, _element.name_);
}
} catch (...) {
}
}
void configuration_impl::get_application_configuration(
- const boost::property_tree::ptree &_tree) {
+ const boost::property_tree::ptree &_tree, const std::string &_file_name) {
std::string its_name("");
- client_t its_id;
- std::size_t its_num_dispatchers(0);
+ client_t its_id(0);
+ std::size_t its_max_dispatchers(VSOMEIP_MAX_DISPATCHERS);
+ std::size_t its_max_dispatch_time(VSOMEIP_MAX_DISPATCH_TIME);
for (auto i = _tree.begin(); i != _tree.end(); ++i) {
std::string its_key(i->first);
std::string its_value(i->second.data());
@@ -627,23 +934,213 @@ void configuration_impl::get_application_configuration(
if (its_key == "name") {
its_name = its_value;
} else if (its_key == "id") {
- if (its_value[0] == '0' && its_value[1] == 'x') {
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
its_converter << std::hex << its_value;
} else {
its_converter << std::dec << its_value;
}
its_converter >> its_id;
- } else if (its_key == "num_dispatchers") {
- if (its_value[0] == '0' && its_value[1] == 'x') {
+ } else if (its_key == "max_dispatchers") {
+ its_converter << std::dec << its_value;
+ its_converter >> its_max_dispatchers;
+ } else if (its_key == "max_dispatch_time") {
+ its_converter << std::dec << its_value;
+ its_converter >> its_max_dispatch_time;
+ }
+ }
+ if (its_name != "" && its_id != 0) {
+ if (applications_.find(its_name) == applications_.end()) {
+ if (!is_configured_client_id(its_id)) {
+ applications_[its_name]
+ = std::make_tuple(its_id, its_max_dispatchers, its_max_dispatch_time);
+ client_identifiers_.insert(its_id);
+ } else {
+ VSOMEIP_WARNING << "Multiple configurations for application "
+ << its_name << ". Ignoring a configuration from "
+ << _file_name;
+ }
+ } else {
+ VSOMEIP_WARNING << "Multiple configurations for application "
+ << its_name << ". Ignoring a configuration from "
+ << _file_name;
+ }
+ }
+}
+
+void configuration_impl::get_trace_configuration(const element &_element) {
+ try {
+ std::stringstream its_converter;
+ auto its_trace_configuration = _element.tree_.get_child("tracing");
+ for(auto i = its_trace_configuration.begin();
+ i != its_trace_configuration.end();
+ ++i) {
+ std::string its_key(i->first);
+ std::string its_value(i->second.data());
+ if(its_key == "enable") {
+ if (is_configured_[ET_TRACING_ENABLE]) {
+ VSOMEIP_WARNING << "Multiple definitions of tracing.enable."
+ << " Ignoring definition from " << _element.name_;
+ } else {
+ trace_->is_enabled_ = (its_value == "true");
+ is_configured_[ET_TRACING_ENABLE] = true;
+ }
+ } else if(its_key == "channels") {
+ get_trace_channels_configuration(i->second);
+ } else if(its_key == "filters") {
+ get_trace_filters_configuration(i->second);
+ }
+ }
+ } catch (...) {
+ }
+}
+
+void configuration_impl::get_trace_channels_configuration(
+ const boost::property_tree::ptree &_tree) {
+ try {
+ for(auto i = _tree.begin(); i != _tree.end(); ++i) {
+ if(i == _tree.begin())
+ trace_->channels_.clear();
+ get_trace_channel_configuration(i->second);
+ }
+ } catch (...) {
+ }
+}
+
+void configuration_impl::get_trace_channel_configuration(
+ const boost::property_tree::ptree &_tree) {
+ std::shared_ptr<trace_channel> its_channel = std::make_shared<trace_channel>();
+ for(auto i = _tree.begin(); i != _tree.end(); ++i) {
+ std::string its_key = i->first;
+ std::string its_value = i->second.data();
+ if(its_key == "name") {
+ its_channel->name_ = its_value;
+ } else if(its_key == "id") {
+ its_channel->id_ = its_value;
+ }
+ }
+ trace_->channels_.push_back(its_channel);
+}
+
+void configuration_impl::get_trace_filters_configuration(
+ const boost::property_tree::ptree &_tree) {
+ try {
+ for(auto i = _tree.begin(); i != _tree.end(); ++i) {
+ get_trace_filter_configuration(i->second);
+ }
+ } catch (...) {
+ }
+}
+
+void configuration_impl::get_trace_filter_configuration(
+ const boost::property_tree::ptree &_tree) {
+ std::shared_ptr<trace_filter_rule> its_filter_rule = std::make_shared<trace_filter_rule>();
+ for(auto i = _tree.begin(); i != _tree.end(); ++i) {
+ std::string its_key = i->first;
+ std::string its_value = i->second.data();
+ if(its_key == "channel") {
+ its_filter_rule->channel_ = its_value;
+ } else {
+ get_trace_filter_expressions(i->second, its_key, its_filter_rule);
+ }
+ }
+ trace_->filter_rules_.push_back(its_filter_rule);
+}
+
+void configuration_impl::get_trace_filter_expressions(
+ const boost::property_tree::ptree &_tree,
+ std::string &_criteria,
+ std::shared_ptr<trace_filter_rule> &_filter_rule) {
+ for(auto i = _tree.begin(); i != _tree.end(); ++i) {
+ std::string its_value = i->second.data();
+ std::stringstream its_converter;
+
+ if(_criteria == "services") {
+ service_t its_id = NO_TRACE_FILTER_EXPRESSION;
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
+ its_converter << std::hex << its_value;
+ } else {
+ its_converter << std::dec << its_value;
+ }
+ its_converter >> its_id;
+ _filter_rule->services_.push_back(its_id);
+ } else if(_criteria == "methods") {
+ method_t its_id = NO_TRACE_FILTER_EXPRESSION;
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
+ its_converter << std::hex << its_value;
+ } else {
+ its_converter << std::dec << its_value;
+ }
+ its_converter >> its_id;
+ _filter_rule->methods_.push_back(its_id);
+ } else if(_criteria == "clients") {
+ client_t its_id = NO_TRACE_FILTER_EXPRESSION;
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
its_converter << std::hex << its_value;
} else {
its_converter << std::dec << its_value;
}
- its_converter >> its_num_dispatchers;
+ its_converter >> its_id;
+ _filter_rule->clients_.push_back(its_id);
}
}
- if (its_name != "" && its_id != 0) {
- applications_[its_name] = {its_id, its_num_dispatchers};
+}
+
+void configuration_impl::get_supports_selective_broadcasts(const boost::property_tree::ptree &_tree) {
+ try {
+ auto its_service_discovery = _tree.get_child("supports_selective_broadcasts");
+ for (auto i = its_service_discovery.begin();
+ i != its_service_discovery.end(); ++i) {
+ std::string its_key(i->first);
+ std::string its_value(i->second.data());
+ std::stringstream its_converter;
+ if (its_key == "address") {
+ supported_selective_addresses.insert(its_value);
+ }
+ }
+ } catch (...) {
+ }
+}
+
+void configuration_impl::get_watchdog_configuration(const element &_element) {
+ watchdog_->is_enabeled_ = false;
+ watchdog_->timeout_in_ms_ = VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT;
+ watchdog_->missing_pongs_allowed_ = VSOMEIP_DEFAULT_MAX_MISSING_PONGS;
+ try {
+ auto its_service_discovery = _element.tree_.get_child("watchdog");
+ for (auto i = its_service_discovery.begin();
+ i != its_service_discovery.end(); ++i) {
+ std::string its_key(i->first);
+ std::string its_value(i->second.data());
+ std::stringstream its_converter;
+ if (its_key == "enable") {
+ if (is_configured_[ET_WATCHDOG_ENABLE]) {
+ VSOMEIP_WARNING << "Multiple definitions of watchdog.enable."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ watchdog_->is_enabeled_ = (its_value == "true");
+ is_configured_[ET_WATCHDOG_ENABLE] = true;
+ }
+ } else if (its_key == "timeout") {
+ if (is_configured_[ET_WATCHDOG_TIMEOUT]) {
+ VSOMEIP_WARNING << "Multiple definitions of watchdog.timeout."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ its_converter << std::dec << its_value;
+ its_converter >> watchdog_->timeout_in_ms_;
+ is_configured_[ET_WATCHDOG_TIMEOUT] = true;
+ }
+ } else if (its_key == "allowed_missing_pongs") {
+ if (is_configured_[ET_WATCHDOG_ALLOWED_MISSING_PONGS]) {
+ VSOMEIP_WARNING << "Multiple definitions of watchdog.allowed_missing_pongs."
+ " Ignoring definition from " << _element.name_;
+ } else {
+ its_converter << std::dec << its_value;
+ its_converter >> watchdog_->missing_pongs_allowed_;
+ is_configured_[ET_WATCHDOG_ALLOWED_MISSING_PONGS] = true;
+ }
+ }
+ }
+ } catch (...) {
}
}
@@ -652,6 +1149,10 @@ const boost::asio::ip::address & configuration_impl::get_unicast_address() const
return unicast_;
}
+unsigned short configuration_impl::get_diagnosis_address() const {
+ return diagnosis_;
+}
+
bool configuration_impl::is_v4() const {
return unicast_.is_v4();
}
@@ -683,7 +1184,7 @@ boost::log::trivial::severity_level configuration_impl::get_loglevel() const {
std::string configuration_impl::get_unicast_address(service_t _service,
instance_t _instance) const {
std::string its_unicast_address("");
- service *its_service = find_service(_service, _instance);
+ auto its_service = find_service(_service, _instance);
if (its_service) {
its_unicast_address = its_service->unicast_address_;
}
@@ -694,52 +1195,60 @@ std::string configuration_impl::get_unicast_address(service_t _service,
return its_unicast_address;
}
-std::string configuration_impl::get_multicast_address(service_t _service,
- instance_t _instance) const {
- std::string its_multicast_address("");
- service *its_service = find_service(_service, _instance);
- if (its_service)
- its_multicast_address = its_service->multicast_address_;
- return its_multicast_address;
-}
-
-uint16_t configuration_impl::get_multicast_port(service_t _service,
+uint16_t configuration_impl::get_reliable_port(service_t _service,
instance_t _instance) const {
- uint16_t its_multicast_port(ILLEGAL_PORT);
- service *its_service = find_service(_service, _instance);
+ uint16_t its_reliable(ILLEGAL_PORT);
+ auto its_service = find_service(_service, _instance);
if (its_service)
- its_multicast_port = its_service->multicast_port_;
- return its_multicast_port;
-}
+ its_reliable = its_service->reliable_;
-uint16_t configuration_impl::get_multicast_group(service_t _service,
- instance_t _instance) const {
- uint16_t its_multicast_group(0xFFFF);
- service *its_service = find_service(_service, _instance);
- if (its_service)
- its_multicast_group = its_service->multicast_group_;
- return its_multicast_group;
+ return its_reliable;
}
-uint16_t configuration_impl::get_reliable_port(service_t _service,
+uint16_t configuration_impl::get_unreliable_port(service_t _service,
instance_t _instance) const {
- uint16_t its_reliable(ILLEGAL_PORT);
- service *its_service = find_service(_service, _instance);
+ uint16_t its_unreliable = ILLEGAL_PORT;
+ auto its_service = find_service(_service, _instance);
if (its_service)
- its_reliable = its_service->reliable_;
+ its_unreliable = its_service->unreliable_;
- return its_reliable;
+ return its_unreliable;
}
bool configuration_impl::is_someip(service_t _service,
instance_t _instance) const {
- service *its_service = find_service(_service, _instance);
+ auto its_service = find_service(_service, _instance);
if (its_service)
return (its_service->protocol_ == "someip");
return true; // we need to explicitely configure a service to
// be something else than SOME/IP
}
+bool configuration_impl::get_client_port(
+ service_t _service, instance_t _instance, bool _reliable,
+ std::map<bool, std::set<uint16_t> > &_used,
+ uint16_t &_port) const {
+ _port = ILLEGAL_PORT;
+ auto its_client = find_client(_service, _instance);
+
+ // If no client ports are configured, return true
+ if (!its_client || its_client->ports_[_reliable].empty()) {
+ return true;
+ }
+
+ for (auto its_port : its_client->ports_[_reliable]) {
+ // Found free configured port
+ if (_used[_reliable].find(its_port) == _used[_reliable].end()) {
+ _port = its_port;
+ return true;
+ }
+ }
+
+ // Configured ports do exist, but they are all in use
+ VSOMEIP_ERROR << "Cannot find free client port!";
+ return false;
+}
+
bool configuration_impl::has_enabled_magic_cookies(std::string _address,
uint16_t _port) const {
bool has_enabled(false);
@@ -753,16 +1262,6 @@ bool configuration_impl::has_enabled_magic_cookies(std::string _address,
return has_enabled;
}
-uint16_t configuration_impl::get_unreliable_port(service_t _service,
- instance_t _instance) const {
- uint16_t its_unreliable = ILLEGAL_PORT;
-
- service *its_service = find_service(_service, _instance);
- if (its_service)
- its_unreliable = its_service->unreliable_;
-
- return its_unreliable;
-}
const std::string & configuration_impl::get_routing_host() const {
return routing_host_;
@@ -773,22 +1272,38 @@ client_t configuration_impl::get_id(const std::string &_name) const {
auto found_application = applications_.find(_name);
if (found_application != applications_.end()) {
- its_client = found_application->second.first;
+ its_client = std::get<0>(found_application->second);
}
return its_client;
}
-std::size_t configuration_impl::get_num_dispatchers(
+bool configuration_impl::is_configured_client_id(client_t _id) const {
+ return (client_identifiers_.find(_id) != client_identifiers_.end());
+}
+
+std::size_t configuration_impl::get_max_dispatchers(
+ const std::string &_name) const {
+ std::size_t its_max_dispatchers = VSOMEIP_MAX_DISPATCHERS;
+
+ auto found_application = applications_.find(_name);
+ if (found_application != applications_.end()) {
+ its_max_dispatchers = std::get<1>(found_application->second);
+ }
+
+ return its_max_dispatchers;
+}
+
+std::size_t configuration_impl::get_max_dispatch_time(
const std::string &_name) const {
- std::size_t its_num_dispatchers = 0;
+ std::size_t its_max_dispatch_time = VSOMEIP_MAX_DISPATCH_TIME;
auto found_application = applications_.find(_name);
if (found_application != applications_.end()) {
- its_num_dispatchers = found_application->second.second;
+ its_max_dispatch_time = std::get<2>(found_application->second);
}
- return its_num_dispatchers;
+ return its_max_dispatch_time;
}
std::set<std::pair<service_t, instance_t> >
@@ -796,26 +1311,73 @@ 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_ != "")
+ if (j.second->unicast_address_ != "local" &&
+ j.second->unicast_address_ != "" &&
+ j.second->unicast_address_ != unicast_.to_string() &&
+ j.second->unicast_address_ != VSOMEIP_UNICAST_ADDRESS)
its_remote_services.insert(std::make_pair(i.first, j.first));
}
}
return its_remote_services;
}
-service *configuration_impl::find_service(service_t _service,
+bool configuration_impl::get_multicast(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup,
+ std::string &_address, uint16_t &_port) const
+{
+ std::shared_ptr<eventgroup> its_eventgroup
+ = find_eventgroup(_service, _instance, _eventgroup);
+ if (!its_eventgroup)
+ return false;
+
+ if (its_eventgroup->multicast_address_.empty())
+ return false;
+
+ _address = its_eventgroup->multicast_address_;
+ _port = its_eventgroup->multicast_port_;
+ return true;
+}
+
+std::shared_ptr<client> configuration_impl::find_client(service_t _service,
+ instance_t _instance) const {
+ std::shared_ptr<client> its_client;
+ auto find_service = clients_.find(_service);
+ if (find_service != clients_.end()) {
+ auto find_instance = find_service->second.find(_instance);
+ if (find_instance != find_service->second.end()) {
+ its_client = find_instance->second;
+ }
+ }
+ return its_client;
+}
+
+std::shared_ptr<service> configuration_impl::find_service(service_t _service,
instance_t _instance) const {
- service *its_service(0);
+ std::shared_ptr<service> its_service;
auto find_service = services_.find(_service);
if (find_service != services_.end()) {
auto find_instance = find_service->second.find(_instance);
if (find_instance != find_service->second.end()) {
- its_service = find_instance->second.get();
+ its_service = find_instance->second;
}
}
return its_service;
}
+std::shared_ptr<eventgroup> configuration_impl::find_eventgroup(
+ service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup) const {
+ std::shared_ptr<eventgroup> its_eventgroup;
+ auto its_service = find_service(_service, _instance);
+ if (its_service) {
+ auto find_eventgroup = its_service->eventgroups_.find(_eventgroup);
+ if (find_eventgroup != its_service->eventgroups_.end()) {
+ its_eventgroup = find_eventgroup->second;
+ }
+ }
+ return its_eventgroup;
+}
+
std::uint32_t configuration_impl::get_max_message_size_local() const {
uint32_t its_max_message_size = VSOMEIP_MAX_LOCAL_MESSAGE_SIZE;
if (VSOMEIP_MAX_TCP_MESSAGE_SIZE > its_max_message_size) {
@@ -832,7 +1394,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(
@@ -847,6 +1409,10 @@ std::uint32_t configuration_impl::get_message_size_reliable(
return VSOMEIP_MAX_TCP_MESSAGE_SIZE;
}
+bool configuration_impl::supports_selective_broadcasts(boost::asio::ip::address _address) const {
+ return supported_selective_addresses.find(_address.to_string()) != supported_selective_addresses.end();
+}
+
// Service Discovery configuration
bool configuration_impl::is_sd_enabled() const {
return is_sd_enabled_;
@@ -892,5 +1458,24 @@ int32_t configuration_impl::get_sd_request_response_delay() const {
return sd_request_response_delay_;
}
+// Trace configuration
+std::shared_ptr<cfg::trace> configuration_impl::get_trace() const {
+ return trace_;
+}
+
+// Watchdog config
+bool configuration_impl::is_watchdog_enabled() const {
+ return watchdog_->is_enabeled_;
+}
+
+uint32_t configuration_impl::get_watchdog_timeout() const {
+ return watchdog_->timeout_in_ms_;
+}
+
+uint32_t configuration_impl::get_allowed_missing_pongs() const {
+ return watchdog_->missing_pongs_allowed_;
+}
+
+
} // namespace config
} // namespace vsomeip
diff --git a/implementation/endpoints/include/buffer.hpp b/implementation/endpoints/include/buffer.hpp
index 5641117..1dac89a 100644
--- a/implementation/endpoints/include/buffer.hpp
+++ b/implementation/endpoints/include/buffer.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/endpoints/include/client_endpoint_impl.hpp b/implementation/endpoints/include/client_endpoint_impl.hpp
index 29f42a3..f80e385 100644
--- a/implementation/endpoints/include/client_endpoint_impl.hpp
+++ b/implementation/endpoints/include/client_endpoint_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -16,6 +16,8 @@
#include <boost/asio/ip/udp.hpp>
#include <boost/utility.hpp>
+#include <vsomeip/constants.hpp>
+
#include "buffer.hpp"
#include "endpoint_impl.hpp"
@@ -24,22 +26,23 @@ namespace vsomeip {
class endpoint;
class endpoint_host;
-template<typename Protocol, int MaxBufferSize>
-class client_endpoint_impl: public endpoint_impl<MaxBufferSize>,
- public std::enable_shared_from_this<
- client_endpoint_impl<Protocol, MaxBufferSize> > {
+template<typename Protocol>
+class client_endpoint_impl: public endpoint_impl<Protocol>,
+ public std::enable_shared_from_this<client_endpoint_impl<Protocol> > {
public:
+ typedef typename Protocol::endpoint endpoint_type;
typedef typename Protocol::socket socket_type;
- typedef typename Protocol::endpoint endpoint_type;
client_endpoint_impl(std::shared_ptr<endpoint_host> _host,
- endpoint_type _remote, boost::asio::io_service &_io,
+ endpoint_type _local, endpoint_type _remote,
+ boost::asio::io_service &_io,
std::uint32_t _max_message_size);
virtual ~client_endpoint_impl();
- bool send(const uint8_t *_data, uint32_t _size, bool _flush);bool send_to(
- const std::shared_ptr<endpoint_definition> _target,
- const byte_t *_data, uint32_t _size, bool _flush = true);bool flush();
+ bool send(const uint8_t *_data, uint32_t _size, bool _flush);
+ bool send_to(const std::shared_ptr<endpoint_definition> _target,
+ const byte_t *_data, uint32_t _size, bool _flush = true);
+ bool flush();
void stop();
void restart();
@@ -64,6 +67,8 @@ protected:
socket_type socket_;
endpoint_type remote_;
+ uint16_t local_port_;
+
boost::asio::system_timer flush_timer_;
boost::asio::system_timer connect_timer_;
uint32_t connect_timeout_;
@@ -74,6 +79,8 @@ protected:
std::deque<message_buffer_ptr_t> queue_;
std::mutex mutex_;
+
+ bool was_not_connected_;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/endpoint.hpp b/implementation/endpoints/include/endpoint.hpp
index 6acf164..c063f2a 100644
--- a/implementation/endpoints/include/endpoint.hpp
+++ b/implementation/endpoints/include/endpoint.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -33,9 +33,9 @@ public:
virtual void join(const std::string &_address) = 0;
virtual void leave(const std::string &_address) = 0;
- virtual void add_multicast(service_t _service, event_t _event,
+ virtual void add_default_target(service_t _service,
const std::string &_address, uint16_t _port) = 0;
- virtual void remove_multicast(service_t _service, event_t _event) = 0;
+ virtual void remove_default_target(service_t _service) = 0;
virtual bool get_remote_address(boost::asio::ip::address &_address) const = 0;
virtual unsigned short get_local_port() const = 0;
diff --git a/implementation/endpoints/include/endpoint_definition.hpp b/implementation/endpoints/include/endpoint_definition.hpp
index d7fb3a2..e4a3290 100644
--- a/implementation/endpoints/include/endpoint_definition.hpp
+++ b/implementation/endpoints/include/endpoint_definition.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/endpoints/include/endpoint_host.hpp b/implementation/endpoints/include/endpoint_host.hpp
index d526ab4..1c78f39 100644
--- a/implementation/endpoints/include/endpoint_host.hpp
+++ b/implementation/endpoints/include/endpoint_host.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -8,6 +8,8 @@
#include <memory>
+#include <boost/asio/ip/address.hpp>
+
#include <vsomeip/primitive_types.hpp>
namespace vsomeip {
@@ -21,9 +23,11 @@ public:
virtual void on_connect(std::shared_ptr<endpoint> _endpoint) = 0;
virtual void on_disconnect(std::shared_ptr<endpoint> _endpoint) = 0;
virtual void on_message(const byte_t *_data, length_t _length,
- endpoint *_receiver) = 0;
+ endpoint *_receiver, const boost::asio::ip::address &_destination
+ = boost::asio::ip::address()) = 0;
virtual void on_error(const byte_t *_data, length_t _length,
endpoint *_receiver) = 0;
+ virtual void release_port(uint16_t _port, bool _reliable) = 0;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/endpoint_impl.hpp b/implementation/endpoints/include/endpoint_impl.hpp
index 5d8350a..bd05698 100644
--- a/implementation/endpoints/include/endpoint_impl.hpp
+++ b/implementation/endpoints/include/endpoint_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -19,10 +19,13 @@ namespace vsomeip {
class endpoint_host;
-template<int MaxBufferSize>
+template<typename Protocol>
class endpoint_impl: public endpoint {
public:
+ typedef typename Protocol::endpoint endpoint_type;
+
endpoint_impl(std::shared_ptr<endpoint_host> _adapter,
+ endpoint_type _local,
boost::asio::io_service &_io,
std::uint32_t _max_message_size);
virtual ~endpoint_impl();
@@ -33,11 +36,10 @@ public:
// TODO: redesign
void join(const std::string &);
void leave(const std::string &);
- void add_multicast(service_t, event_t, const std::string &, uint16_t);
- void remove_multicast(service_t, event_t);
- // Dummy implementation as we only need this for IP client endpoints
- // TODO: redesign
+ void add_default_target(service_t, const std::string &, uint16_t);
+ void remove_default_target(service_t);
+
bool get_remote_address(boost::asio::ip::address &_address) const;
// Dummy implementations as we only need these for server endpoints
@@ -76,6 +78,10 @@ protected:
std::uint32_t max_message_size_;
uint32_t use_count_;
+
+ bool sending_blocked_;
+
+ endpoint_type local_;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/local_client_endpoint_impl.hpp b/implementation/endpoints/include/local_client_endpoint_impl.hpp
index 97f01ce..a6d777e 100644
--- a/implementation/endpoints/include/local_client_endpoint_impl.hpp
+++ b/implementation/endpoints/include/local_client_endpoint_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -20,17 +20,19 @@
namespace vsomeip {
#ifdef WIN32
-typedef client_endpoint_impl<boost::asio::ip::tcp,
- VSOMEIP_MAX_TCP_MESSAGE_SIZE > local_client_endpoint_base_impl;
+typedef client_endpoint_impl<
+ boost::asio::ip::tcp
+ > local_client_endpoint_base_impl;
#else
-typedef client_endpoint_impl<boost::asio::local::stream_protocol,
- VSOMEIP_MAX_LOCAL_MESSAGE_SIZE> local_client_endpoint_base_impl;
+typedef client_endpoint_impl<
+ boost::asio::local::stream_protocol
+ > local_client_endpoint_base_impl;
#endif
class local_client_endpoint_impl: public local_client_endpoint_base_impl {
public:
local_client_endpoint_impl(std::shared_ptr<endpoint_host> _host,
- endpoint_type _local,
+ endpoint_type _remote,
boost::asio::io_service &_io,
std::uint32_t _max_message_size);
@@ -43,21 +45,10 @@ public:
private:
void send_queued();
- void send_start_tag();
- void send_queued_data();
- void send_end_tag();
-
void send_magic_cookie();
void connect();
void receive();
-
- void send_start_tag_cbk(boost::system::error_code const &_error,
- std::size_t _bytes);
- void send_queued_data_cbk(boost::system::error_code const &_error,
- std::size_t _bytes);
- 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 626b30e..d8f5288 100644
--- a/implementation/endpoints/include/local_server_endpoint_impl.hpp
+++ b/implementation/endpoints/include/local_server_endpoint_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -24,11 +24,13 @@
namespace vsomeip {
#ifdef WIN32
-typedef server_endpoint_impl<boost::asio::ip::tcp,
- VSOMEIP_MAX_TCP_MESSAGE_SIZE > local_server_endpoint_base_impl;
+typedef server_endpoint_impl<
+ boost::asio::ip::tcp
+ > local_server_endpoint_base_impl;
#else
-typedef server_endpoint_impl<boost::asio::local::stream_protocol,
- VSOMEIP_MAX_LOCAL_MESSAGE_SIZE> local_server_endpoint_base_impl;
+typedef server_endpoint_impl<
+ boost::asio::local::stream_protocol
+ > local_server_endpoint_base_impl;
#endif
class local_server_endpoint_impl: public local_server_endpoint_base_impl {
@@ -51,10 +53,12 @@ public:
void send_queued(queue_iterator_type _queue_iterator);
endpoint_type get_remote() const;
- bool get_multicast(service_t, event_t, endpoint_type &) const;
+ bool get_default_target(service_t, endpoint_type &) const;
bool is_local() const;
+ bool queue_message(const byte_t *_data, uint32_t _size);
+
private:
class connection: public boost::enable_shared_from_this<connection> {
@@ -69,6 +73,8 @@ private:
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);
@@ -82,6 +88,8 @@ private:
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);
@@ -94,7 +102,7 @@ private:
#endif
std::map<endpoint_type, connection::ptr> connections_;
- connection *current_;
+ connection::ptr current_;
private:
void remove_connection(connection *_connection);
diff --git a/implementation/endpoints/include/server_endpoint_impl.hpp b/implementation/endpoints/include/server_endpoint_impl.hpp
index c51cb49..15d001b 100644
--- a/implementation/endpoints/include/server_endpoint_impl.hpp
+++ b/implementation/endpoints/include/server_endpoint_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -21,25 +21,26 @@
namespace vsomeip {
-template<typename Protocol, int MaxBufferSize>
-class server_endpoint_impl: public endpoint_impl<MaxBufferSize>,
- public std::enable_shared_from_this<
- server_endpoint_impl<Protocol, MaxBufferSize> > {
+template<typename Protocol>
+class server_endpoint_impl: public endpoint_impl<Protocol>,
+ public std::enable_shared_from_this<server_endpoint_impl<Protocol> > {
public:
typedef typename Protocol::socket socket_type;
typedef typename Protocol::endpoint endpoint_type;
- typedef boost::array<uint8_t, MaxBufferSize> buffer_type;
typedef typename std::map<endpoint_type, std::deque<message_buffer_ptr_t> > queue_type;
typedef typename queue_type::iterator queue_iterator_type;
server_endpoint_impl(std::shared_ptr<endpoint_host> _host,
endpoint_type _local, boost::asio::io_service &_io,
std::uint32_t _max_message_size);
+ virtual ~server_endpoint_impl();
bool is_client() const;
bool is_connected() const;
bool send(const uint8_t *_data, uint32_t _size, bool _flush);
+
+ virtual void stop();
bool flush(endpoint_type _target);
public:
@@ -55,19 +56,19 @@ public:
virtual void send_queued(queue_iterator_type _queue_iterator) = 0;
virtual endpoint_type get_remote() const = 0;
- virtual bool get_multicast(service_t _service, event_t _event,
- endpoint_type &_target) const = 0;
+
+ virtual bool get_default_target(service_t _service,
+ endpoint_type &_target) const = 0;
protected:
std::map<endpoint_type, message_buffer_ptr_t> packetizer_;
queue_type queues_;
+ std::mutex clients_mutex_;
std::map<client_t, std::map<session_t, endpoint_type> > clients_;
boost::asio::system_timer flush_timer_;
- endpoint_type local_;
-
std::mutex mutex_;
};
diff --git a/implementation/endpoints/include/tcp_client_endpoint_impl.hpp b/implementation/endpoints/include/tcp_client_endpoint_impl.hpp
index e5bf987..e6aaa33 100644
--- a/implementation/endpoints/include/tcp_client_endpoint_impl.hpp
+++ b/implementation/endpoints/include/tcp_client_endpoint_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -13,13 +13,15 @@
namespace vsomeip {
-typedef client_endpoint_impl<boost::asio::ip::tcp,
- VSOMEIP_MAX_TCP_MESSAGE_SIZE> tcp_client_endpoint_base_impl;
+typedef client_endpoint_impl<
+ boost::asio::ip::tcp
+ > tcp_client_endpoint_base_impl;
class tcp_client_endpoint_impl: public tcp_client_endpoint_base_impl {
public:
tcp_client_endpoint_impl(std::shared_ptr<endpoint_host> _host,
endpoint_type _local,
+ endpoint_type _remote,
boost::asio::io_service &_io,
std::uint32_t _max_message_size);
virtual ~tcp_client_endpoint_impl();
diff --git a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp
index 7295868..16197cc 100644
--- a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp
+++ b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -12,12 +12,14 @@
#include <boost/enable_shared_from_this.hpp>
#include <vsomeip/defines.hpp>
+#include <vsomeip/export.hpp>
#include "server_endpoint_impl.hpp"
namespace vsomeip {
-typedef server_endpoint_impl<boost::asio::ip::tcp,
- VSOMEIP_MAX_TCP_MESSAGE_SIZE> tcp_server_endpoint_base_impl;
+typedef server_endpoint_impl<
+ boost::asio::ip::tcp
+ > tcp_server_endpoint_base_impl;
class tcp_server_endpoint_impl: public tcp_server_endpoint_base_impl {
@@ -35,9 +37,12 @@ public:
const byte_t *_data, uint32_t _size, bool _flush);
void send_queued(queue_iterator_type _queue_iterator);
+ VSOMEIP_EXPORT bool is_established(std::shared_ptr<endpoint_definition> _endpoint);
+
endpoint_type get_remote() const;
bool get_remote_address(boost::asio::ip::address &_address) const;
- bool get_multicast(service_t, event_t, endpoint_type &) const;
+ unsigned short get_remote_port() const;
+ bool get_default_target(service_t, endpoint_type &) const;
unsigned short get_local_port() const;
bool is_reliable() const;
diff --git a/implementation/endpoints/include/udp_client_endpoint_impl.hpp b/implementation/endpoints/include/udp_client_endpoint_impl.hpp
index 4a51db6..07d2179 100644
--- a/implementation/endpoints/include/udp_client_endpoint_impl.hpp
+++ b/implementation/endpoints/include/udp_client_endpoint_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -19,13 +19,15 @@ namespace vsomeip {
class endpoint_adapter;
-typedef client_endpoint_impl<boost::asio::ip::udp,
- VSOMEIP_MAX_UDP_MESSAGE_SIZE> udp_client_endpoint_base_impl;
+typedef client_endpoint_impl<
+ boost::asio::ip::udp
+ > udp_client_endpoint_base_impl;
class udp_client_endpoint_impl: virtual public udp_client_endpoint_base_impl {
public:
udp_client_endpoint_impl(std::shared_ptr<endpoint_host> _host,
+ endpoint_type _local,
endpoint_type _remote,
boost::asio::io_service &_io);
virtual ~udp_client_endpoint_impl();
@@ -46,7 +48,6 @@ private:
void receive();
receive_buffer_t recv_buffer_;
- size_t recv_buffer_size_;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/udp_server_endpoint_impl.hpp b/implementation/endpoints/include/udp_server_endpoint_impl.hpp
index c03a7b4..907e022 100644
--- a/implementation/endpoints/include/udp_server_endpoint_impl.hpp
+++ b/implementation/endpoints/include/udp_server_endpoint_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -7,15 +7,17 @@
#define VSOMEIP_INTERNAL_UDP_SERVICE_IMPL_HPP
#include <boost/asio/io_service.hpp>
-#include <boost/asio/ip/udp.hpp>
+#include <boost/asio/ip/udp_ext.hpp>
#include <vsomeip/defines.hpp>
+
#include "server_endpoint_impl.hpp"
namespace vsomeip {
-typedef server_endpoint_impl<boost::asio::ip::udp,
- VSOMEIP_MAX_UDP_MESSAGE_SIZE> udp_server_endpoint_base_impl;
+typedef server_endpoint_impl<
+ boost::asio::ip::udp_ext
+ > udp_server_endpoint_base_impl;
class udp_server_endpoint_impl: public udp_server_endpoint_base_impl {
@@ -37,14 +39,15 @@ public:
endpoint_type get_remote() const;
bool get_remote_address(boost::asio::ip::address &_address) const;
- bool get_multicast(service_t _service, event_t _event,
- endpoint_type &_target) const;
+ unsigned short get_remote_port() const;
void join(const std::string &_address);
void leave(const std::string &_address);
- void add_multicast(service_t _service, instance_t _instance,
- const std::string &_address, uint16_t _port);
- void remove_multicast(service_t _service, instance_t _instance);
+
+ void add_default_target(service_t _service,
+ const std::string &_address, uint16_t _port);
+ void remove_default_target(service_t _service);
+ bool get_default_target(service_t _service, endpoint_type &_target) const;
unsigned short get_local_port() const;
bool is_local() const;
@@ -53,18 +56,21 @@ public:
public:
void receive_cbk(boost::system::error_code const &_error,
- std::size_t _size);
+ std::size_t _size,
+ boost::asio::ip::address const &_destination);
private:
void set_broadcast();
+ bool is_joined(const std::string &_address) const;
private:
socket_type socket_;
endpoint_type remote_;
- std::map<service_t, std::map<instance_t, endpoint_type> > multicasts_;
+
+ std::map<service_t, endpoint_type> default_targets_;
+ std::set<std::string> joined_;
receive_buffer_t recv_buffer_;
- size_t recv_buffer_size_;
std::mutex stop_mutex_;
};
diff --git a/implementation/endpoints/include/virtual_server_endpoint_impl.hpp b/implementation/endpoints/include/virtual_server_endpoint_impl.hpp
index 12484f5..2fd7005 100644
--- a/implementation/endpoints/include/virtual_server_endpoint_impl.hpp
+++ b/implementation/endpoints/include/virtual_server_endpoint_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -35,9 +35,9 @@ public:
void join(const std::string &_address);
void leave(const std::string &_address);
- void add_multicast(service_t _service, event_t _event,
+ void add_default_target(service_t _service,
const std::string &_address, uint16_t _port);
- void remove_multicast(service_t _service, event_t _event);
+ void remove_default_target(service_t _service);
bool get_remote_address(boost::asio::ip::address &_address) const;
unsigned short get_local_port() const;
diff --git a/implementation/endpoints/src/client_endpoint_impl.cpp b/implementation/endpoints/src/client_endpoint_impl.cpp
index 6ed812a..f68bad7 100644
--- a/implementation/endpoints/src/client_endpoint_impl.cpp
+++ b/implementation/endpoints/src/client_endpoint_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -23,46 +23,74 @@
namespace vsomeip {
-template<typename Protocol, int MaxBufferSize>
-client_endpoint_impl<Protocol, MaxBufferSize>::client_endpoint_impl(
- std::shared_ptr<endpoint_host> _host, endpoint_type _remote,
- boost::asio::io_service &_io, std::uint32_t _max_message_size)
- : endpoint_impl<MaxBufferSize>(_host, _io, _max_message_size),
+template<typename Protocol>
+client_endpoint_impl<Protocol>::client_endpoint_impl(
+ std::shared_ptr<endpoint_host> _host,
+ endpoint_type _local,
+ endpoint_type _remote,
+ boost::asio::io_service &_io,
+ std::uint32_t _max_message_size)
+ : endpoint_impl<Protocol>(_host, _local, _io, _max_message_size),
socket_(_io), remote_(_remote),
flush_timer_(_io), connect_timer_(_io),
connect_timeout_(VSOMEIP_DEFAULT_CONNECT_TIMEOUT), // TODO: use config variable
is_connected_(false),
- packetizer_(std::make_shared<message_buffer_t>()) {
+ packetizer_(std::make_shared<message_buffer_t>()),
+ was_not_connected_(false) {
}
-template<typename Protocol, int MaxBufferSize>
-client_endpoint_impl<Protocol, MaxBufferSize>::~client_endpoint_impl() {
+template<typename Protocol>
+client_endpoint_impl<Protocol>::~client_endpoint_impl() {
}
-template<typename Protocol, int MaxBufferSize>
-bool client_endpoint_impl<Protocol, MaxBufferSize>::is_client() const {
+template<typename Protocol>
+bool client_endpoint_impl<Protocol>::is_client() const {
return true;
}
-template<typename Protocol, int MaxBufferSize>
-bool client_endpoint_impl<Protocol, MaxBufferSize>::is_connected() const {
+template<typename Protocol>
+bool client_endpoint_impl<Protocol>::is_connected() const {
return is_connected_;
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::stop() {
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::stop() {
if (socket_.is_open()) {
- socket_.close();
+ connect_timer_.cancel();
+ connect_timeout_ = VSOMEIP_DEFAULT_CONNECT_TIMEOUT;
+ endpoint_impl<Protocol>::sending_blocked_ = true;
+ bool send_queue_empty(false);
+ std::uint32_t times_slept(0);
+
+ while (times_slept <= 50) {
+ mutex_.lock();
+ send_queue_empty = (queue_.size() == 0);
+ mutex_.unlock();
+ if (send_queue_empty) {
+ break;
+ } else {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ times_slept++;
+ }
+ }
+
+ boost::system::error_code its_error;
+ socket_.close(its_error);
}
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::restart() {
- receive();
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::restart() {
+ is_connected_ = false;
+ connect_timer_.expires_from_now(
+ std::chrono::milliseconds(connect_timeout_));
+ connect_timer_.async_wait(
+ std::bind(&client_endpoint_impl<Protocol>::wait_connect_cbk,
+ this->shared_from_this(), std::placeholders::_1));
}
-template<typename Protocol, int MaxBufferSize>
-bool client_endpoint_impl<Protocol, MaxBufferSize>::send_to(
+template<typename Protocol>
+bool client_endpoint_impl<Protocol>::send_to(
const std::shared_ptr<endpoint_definition> _target, const byte_t *_data,
uint32_t _size, bool _flush) {
(void)_target;
@@ -70,16 +98,18 @@ bool client_endpoint_impl<Protocol, MaxBufferSize>::send_to(
(void)_size;
(void)_flush;
- VSOMEIP_ERROR<< "Clients endpoints must not be used to "
- << "send to explicitely specified targets";
+ VSOMEIP_ERROR << "Clients endpoints must not be used to "
+ << "send to explicitely specified targets";
return false;
}
-template<typename Protocol, int MaxBufferSize>
-bool client_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data,
+template<typename Protocol>
+bool client_endpoint_impl<Protocol>::send(const uint8_t *_data,
uint32_t _size, bool _flush) {
std::lock_guard<std::mutex> its_lock(mutex_);
- bool is_flushing(false);
+ if (endpoint_impl<Protocol>::sending_blocked_) {
+ return false;
+ }
#if 0
std::stringstream msg;
msg << "cei::send: ";
@@ -89,9 +119,10 @@ bool client_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data,
VSOMEIP_DEBUG << msg.str();
#endif
- if (packetizer_->size() + _size > endpoint_impl<MaxBufferSize>::max_message_size_) {
+ const bool queue_size_zero_on_entry(queue_.empty());
+ if (packetizer_->size() + _size > endpoint_impl<Protocol>::max_message_size_
+ && !packetizer_->empty()) {
queue_.push_back(packetizer_);
- is_flushing = true;
packetizer_ = std::make_shared<message_buffer_t>();
}
@@ -100,28 +131,26 @@ bool client_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data,
if (_flush) {
flush_timer_.cancel();
queue_.push_back(packetizer_);
- is_flushing = true;
packetizer_ = std::make_shared<message_buffer_t>();
} else {
flush_timer_.expires_from_now(
std::chrono::milliseconds(VSOMEIP_DEFAULT_FLUSH_TIMEOUT)); // TODO: use config variable
flush_timer_.async_wait(
std::bind(
- &client_endpoint_impl<
- Protocol, MaxBufferSize>::flush_cbk,
+ &client_endpoint_impl<Protocol>::flush_cbk,
this->shared_from_this(),
std::placeholders::_1));
}
- if (is_flushing && queue_.size() == 1) { // no writing in progress
+ if (queue_size_zero_on_entry && !queue_.empty()) { // no writing in progress
send_queued();
}
return (true);
}
-template<typename Protocol, int MaxBufferSize>
-bool client_endpoint_impl<Protocol, MaxBufferSize>::flush() {
+template<typename Protocol>
+bool client_endpoint_impl<Protocol>::flush() {
bool is_successful(true);
if (!packetizer_->empty()) {
@@ -138,23 +167,26 @@ bool client_endpoint_impl<Protocol, MaxBufferSize>::flush() {
return is_successful;
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::connect_cbk(
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::connect_cbk(
boost::system::error_code const &_error) {
std::shared_ptr<endpoint_host> its_host = this->host_.lock();
if (its_host) {
- if (_error) {
- socket_.close();
+ if (_error && _error != boost::asio::error::already_connected) {
+ if(socket_.is_open()) {
+ boost::system::error_code its_error;
+ socket_.close(its_error);
+ }
connect_timer_.expires_from_now(
std::chrono::milliseconds(connect_timeout_));
connect_timer_.async_wait(
- std::bind(&client_endpoint_impl<
- Protocol, MaxBufferSize>::wait_connect_cbk,
+ std::bind(&client_endpoint_impl<Protocol>::wait_connect_cbk,
this->shared_from_this(), std::placeholders::_1));
- // next time we wait longer
- connect_timeout_ <<= 1;
+ // Double the timeout as long as the maximum allowed is larger
+ if (connect_timeout_ < VSOMEIP_MAX_CONNECT_TIMEOUT)
+ connect_timeout_ <<= 1;
if (is_connected_) {
is_connected_ = false;
@@ -170,37 +202,54 @@ void client_endpoint_impl<Protocol, MaxBufferSize>::connect_cbk(
}
receive();
+
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ if (queue_.size() > 0 && was_not_connected_) {
+ was_not_connected_ = false;
+ send_queued();
+ }
}
}
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::wait_connect_cbk(
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::wait_connect_cbk(
boost::system::error_code const &_error) {
if (!_error) {
connect();
}
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::send_cbk(
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::send_cbk(
boost::system::error_code const &_error, std::size_t _bytes) {
(void)_bytes;
if (!_error) {
std::lock_guard<std::mutex> its_lock(mutex_);
- queue_.pop_front();
if (queue_.size() > 0) {
+ queue_.pop_front();
send_queued();
}
} else if (_error == boost::asio::error::broken_pipe) {
is_connected_ = false;
- socket_.close();
+ if (endpoint_impl<Protocol>::sending_blocked_) {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ queue_.clear();
+ }
+ if (socket_.is_open()) {
+ boost::system::error_code its_error;
+ socket_.close(its_error);
+ }
+ connect();
+ } else if (_error == boost::asio::error::not_connected
+ || _error == boost::asio::error::bad_descriptor) {
+ was_not_connected_ = true;
connect();
}
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::flush_cbk(
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::flush_cbk(
boost::system::error_code const &_error) {
if (!_error) {
(void) flush();
@@ -209,13 +258,9 @@ void client_endpoint_impl<Protocol, MaxBufferSize>::flush_cbk(
// Instantiate template
#ifndef WIN32
-template class client_endpoint_impl<boost::asio::local::stream_protocol,
-VSOMEIP_MAX_LOCAL_MESSAGE_SIZE> ;
+template class client_endpoint_impl<boost::asio::local::stream_protocol>;
#endif
-template class client_endpoint_impl<boost::asio::ip::tcp,
-VSOMEIP_MAX_TCP_MESSAGE_SIZE> ;
-template class client_endpoint_impl<boost::asio::ip::udp,
-VSOMEIP_MAX_UDP_MESSAGE_SIZE> ;
-
+template class client_endpoint_impl<boost::asio::ip::tcp>;
+template class client_endpoint_impl<boost::asio::ip::udp>;
} // namespace vsomeip
diff --git a/implementation/endpoints/src/endpoint_definition.cpp b/implementation/endpoints/src/endpoint_definition.cpp
index d748aa3..fe7e7d6 100644
--- a/implementation/endpoints/src/endpoint_definition.cpp
+++ b/implementation/endpoints/src/endpoint_definition.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/endpoints/src/endpoint_impl.cpp b/implementation/endpoints/src/endpoint_impl.cpp
index 5b0e088..109cff8 100644
--- a/implementation/endpoints/src/endpoint_impl.cpp
+++ b/implementation/endpoints/src/endpoint_impl.cpp
@@ -1,8 +1,13 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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 <boost/asio/ip/tcp.hpp>
+#include <boost/asio/ip/udp.hpp>
+#include <boost/asio/ip/udp_ext.hpp>
+#include <boost/asio/local/stream_protocol.hpp>
+
#include <vsomeip/constants.hpp>
#include <vsomeip/defines.hpp>
@@ -12,33 +17,38 @@
namespace vsomeip {
-template<int MaxBufferSize>
-endpoint_impl<MaxBufferSize>::endpoint_impl(
- std::shared_ptr<endpoint_host> _host, boost::asio::io_service &_io,
- std::uint32_t _max_message_size)
+template<typename Protocol>
+endpoint_impl<Protocol>::endpoint_impl(
+ std::shared_ptr<endpoint_host> _host,
+ endpoint_type _local,
+ boost::asio::io_service &_io,
+ std::uint32_t _max_message_size)
: service_(_io),
host_(_host),
is_supporting_magic_cookies_(false),
has_enabled_magic_cookies_(false),
- max_message_size_(_max_message_size) {
+ max_message_size_(_max_message_size),
+ use_count_(0),
+ sending_blocked_(false),
+ local_(_local) {
}
-template<int MaxBufferSize>
-endpoint_impl<MaxBufferSize>::~endpoint_impl() {
+template<typename Protocol>
+endpoint_impl<Protocol>::~endpoint_impl() {
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::enable_magic_cookies() {
+template<typename Protocol>
+void endpoint_impl<Protocol>::enable_magic_cookies() {
has_enabled_magic_cookies_ = is_supporting_magic_cookies_;
}
-template<int MaxBufferSize>
-bool endpoint_impl<MaxBufferSize>::is_magic_cookie() const {
+template<typename Protocol>
+bool endpoint_impl<Protocol>::is_magic_cookie() const {
return false;
}
-template<int MaxBufferSize>
-uint32_t endpoint_impl<MaxBufferSize>::find_magic_cookie(
+template<typename Protocol>
+uint32_t endpoint_impl<Protocol>::find_magic_cookie(
byte_t *_buffer, size_t _size) {
bool is_found(false);
uint32_t its_offset = 0xFFFFFFFF;
@@ -86,64 +96,67 @@ uint32_t endpoint_impl<MaxBufferSize>::find_magic_cookie(
return (is_found ? its_offset : 0xFFFFFFFF);
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::join(const std::string &) {
+template<typename Protocol>
+void endpoint_impl<Protocol>::join(const std::string &) {
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::leave(const std::string &) {
+template<typename Protocol>
+void endpoint_impl<Protocol>::leave(const std::string &) {
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::add_multicast(
- service_t, event_t, const std::string &, uint16_t) {
+template<typename Protocol>
+void endpoint_impl<Protocol>::add_default_target(
+ service_t, const std::string &, uint16_t) {
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::remove_multicast(service_t, event_t) {
+template<typename Protocol>
+void endpoint_impl<Protocol>::remove_default_target(service_t) {
}
-template<int MaxBufferSize>
-bool endpoint_impl<MaxBufferSize>::get_remote_address(
+template<typename Protocol>
+bool endpoint_impl<Protocol>::get_remote_address(
boost::asio::ip::address &_address) const {
(void)_address;
return false;
}
-template<int MaxBufferSize>
-unsigned short endpoint_impl<MaxBufferSize>::get_local_port() const {
+template<typename Protocol>
+unsigned short endpoint_impl<Protocol>::get_local_port() const {
return 0;
}
-template<int MaxBufferSize>
-unsigned short endpoint_impl<MaxBufferSize>::get_remote_port() const {
+template<typename Protocol>
+unsigned short endpoint_impl<Protocol>::get_remote_port() const {
return 0;
}
-template<int MaxBufferSize>
-bool endpoint_impl<MaxBufferSize>::is_reliable() const {
+template<typename Protocol>
+bool endpoint_impl<Protocol>::is_reliable() const {
return false;
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::increment_use_count() {
+template<typename Protocol>
+void endpoint_impl<Protocol>::increment_use_count() {
use_count_++;
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::decrement_use_count() {
+template<typename Protocol>
+void endpoint_impl<Protocol>::decrement_use_count() {
if (use_count_ > 0)
use_count_--;
}
-template<int MaxBufferSize>
-uint32_t endpoint_impl<MaxBufferSize>::get_use_count() {
+template<typename Protocol>
+uint32_t endpoint_impl<Protocol>::get_use_count() {
return use_count_;
}
// Instantiate template
-template class endpoint_impl< VSOMEIP_MAX_LOCAL_MESSAGE_SIZE> ;
-template class endpoint_impl< VSOMEIP_MAX_TCP_MESSAGE_SIZE> ;
-template class endpoint_impl< VSOMEIP_MAX_UDP_MESSAGE_SIZE> ;
+#ifndef WIN32
+template class endpoint_impl<boost::asio::local::stream_protocol>;
+#endif
+template class endpoint_impl<boost::asio::ip::tcp>;
+template class endpoint_impl<boost::asio::ip::udp>;
+template class endpoint_impl<boost::asio::ip::udp_ext>;
} // namespace vsomeip
diff --git a/implementation/endpoints/src/local_client_endpoint_impl.cpp b/implementation/endpoints/src/local_client_endpoint_impl.cpp
index 116287f..62dba82 100644
--- a/implementation/endpoints/src/local_client_endpoint_impl.cpp
+++ b/implementation/endpoints/src/local_client_endpoint_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -17,9 +17,13 @@
namespace vsomeip {
local_client_endpoint_impl::local_client_endpoint_impl(
- std::shared_ptr< endpoint_host > _host, endpoint_type _remote,
- boost::asio::io_service &_io, std::uint32_t _max_message_size)
- : local_client_endpoint_base_impl(_host, _remote, _io, _max_message_size) {
+ std::shared_ptr< endpoint_host > _host,
+ endpoint_type _remote,
+ boost::asio::io_service &_io,
+ std::uint32_t _max_message_size)
+ : local_client_endpoint_base_impl(_host, _remote, _remote, _io, _max_message_size) {
+ // Using _remote for the local(!) endpoint is ok,
+ // because we have no bind for local endpoints!
is_supporting_magic_cookies_ = false;
}
@@ -32,69 +36,65 @@ bool local_client_endpoint_impl::is_local() const {
}
void local_client_endpoint_impl::start() {
- connect();
+ if (socket_.is_open()) {
+ sending_blocked_ = false;
+ boost::system::error_code its_error;
+ socket_.cancel(its_error);
+ socket_.close(its_error);
+ restart();
+ } else {
+ connect();
+ }
}
void local_client_endpoint_impl::connect() {
- socket_.open(remote_.protocol());
-
- boost::system::error_code error;
- error = socket_.connect(remote_, error);
- connect_cbk(error);
+ boost::system::error_code its_error;
+ socket_.open(remote_.protocol(), its_error);
+
+ if (!its_error || its_error == boost::asio::error::already_open) {
+ socket_.set_option(boost::asio::socket_base::reuse_address(true));
+ boost::system::error_code error;
+ error = socket_.connect(remote_, error);
+ connect_cbk(error);
+ } else {
+ VSOMEIP_WARNING << "local_client_endpoint::connect: Error opening socket: "
+ << its_error.message();
+ }
}
void local_client_endpoint_impl::receive() {
- 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
- )
- );
}
void local_client_endpoint_impl::send_queued() {
static byte_t its_start_tag[] = { 0x67, 0x37, 0x6D, 0x07 };
+ static byte_t its_end_tag[] = { 0x07, 0x6D, 0x37, 0x67 };
+ std::vector<boost::asio::const_buffer> bufs;
+
+ message_buffer_ptr_t its_buffer;
+ if(queue_.size()) {
+ its_buffer = queue_.front();
+ } else {
+ return;
+ }
+
+#if 0
+std::stringstream msg;
+msg << "lce<" << this << ">::sq: ";
+for (std::size_t i = 0; i < its_buffer->size(); i++)
+ msg << std::setw(2) << std::setfill('0') << std::hex
+ << (int)(*its_buffer)[i] << " ";
+VSOMEIP_DEBUG << msg.str();
+#endif
+
+ bufs.push_back(boost::asio::buffer(its_start_tag));
+ bufs.push_back(boost::asio::buffer(*its_buffer));
+ bufs.push_back(boost::asio::buffer(its_end_tag));
boost::asio::async_write(
socket_,
- boost::asio::buffer(
- its_start_tag,
- sizeof(its_start_tag)
- ),
- std::bind(
- &local_client_endpoint_impl::send_start_tag_cbk,
- std::dynamic_pointer_cast<
- local_client_endpoint_impl
- >(shared_from_this()),
- std::placeholders::_1,
- std::placeholders::_2
- )
- );
-}
-
-void local_client_endpoint_impl::send_queued_data() {
- std::lock_guard<std::mutex> its_lock(mutex_);
- message_buffer_ptr_t its_buffer = queue_.front();
- #if 0
- std::stringstream msg;
- msg << "lce<" << this << ">::sq: ";
- for (std::size_t i = 0; i < its_buffer->size(); i++)
- msg << std::setw(2) << std::setfill('0') << std::hex
- << (int)(*its_buffer)[i] << " ";
- VSOMEIP_DEBUG << msg.str();
- #endif
-
- boost::asio::async_write(
- socket_,
- boost::asio::buffer(*its_buffer),
+ bufs,
std::bind(
- &local_client_endpoint_impl::send_queued_data_cbk,
+ &client_endpoint_impl::send_cbk,
std::dynamic_pointer_cast<
local_client_endpoint_impl
>(shared_from_this()),
@@ -104,51 +104,7 @@ void local_client_endpoint_impl::send_queued_data() {
);
}
-void local_client_endpoint_impl::send_end_tag() {
- static byte_t its_end_tag[] = { 0x07, 0x6D, 0x37, 0x67 };
-
- boost::asio::async_write(
- socket_,
- boost::asio::buffer(
- its_end_tag,
- sizeof(its_end_tag)
- ),
- std::bind(
- &client_endpoint_impl::send_cbk,
- shared_from_this(),
- std::placeholders::_1,
- std::placeholders::_2
- )
- );
-}
-
void local_client_endpoint_impl::send_magic_cookie() {
}
-void local_client_endpoint_impl::send_start_tag_cbk(
- boost::system::error_code const &_error, std::size_t _bytes) {
- (void)_bytes;
- if (_error)
- send_cbk(_error, 0);
-
- send_queued_data();
-}
-
-void local_client_endpoint_impl::send_queued_data_cbk(
- boost::system::error_code const &_error, std::size_t _bytes) {
- (void)_bytes;
- if (_error)
- send_cbk(_error, 0);
-
- send_end_tag();
-}
-
-void local_client_endpoint_impl::receive_cbk(
- boost::system::error_code const &_error, std::size_t _bytes) {
- (void)_error;
- (void)_bytes;
- 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 b392cec..e67a646 100644
--- a/implementation/endpoints/src/local_server_endpoint_impl.cpp
+++ b/implementation/endpoints/src/local_server_endpoint_impl.cpp
@@ -1,11 +1,10 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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 <deque>
#include <iomanip>
-#include <iostream>
#include <sstream>
#include <boost/asio/write.hpp>
@@ -22,7 +21,7 @@ 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) {
+ acceptor_(_io, _local), current_(nullptr) {
is_supporting_magic_cookies_ = false;
}
@@ -34,22 +33,27 @@ bool local_server_endpoint_impl::is_local() const {
}
void local_server_endpoint_impl::start() {
- connection::ptr new_connection = connection::create(this, max_message_size_);
+ current_ = connection::create(this, max_message_size_);
acceptor_.async_accept(
- new_connection->get_socket(),
+ current_->get_socket(),
std::bind(
&local_server_endpoint_impl::accept_cbk,
std::dynamic_pointer_cast<
local_server_endpoint_impl
>(shared_from_this()),
- new_connection,
+ current_,
std::placeholders::_1
)
);
}
void local_server_endpoint_impl::stop() {
+ if (acceptor_.is_open()) {
+ boost::system::error_code its_error;
+ acceptor_.close(its_error);
+ }
+ server_endpoint_impl::stop();
}
bool local_server_endpoint_impl::send_to(
@@ -77,13 +81,21 @@ 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 {
- return current_->get_socket().remote_endpoint();
+ boost::system::error_code its_error;
+ return current_->get_socket().remote_endpoint(its_error);
}
-bool local_server_endpoint_impl::get_multicast(
- service_t, event_t,
+bool local_server_endpoint_impl::get_default_target(
+ service_t,
local_server_endpoint_impl::endpoint_type &) const {
return false;
}
@@ -107,10 +119,12 @@ void local_server_endpoint_impl::accept_cbk(
if (!_error) {
socket_type &new_connection_socket = _connection->get_socket();
- endpoint_type remote = new_connection_socket.remote_endpoint();
-
- connections_[remote] = _connection;
- _connection->start();
+ boost::system::error_code its_error;
+ endpoint_type remote = new_connection_socket.remote_endpoint(its_error);
+ if(!its_error) {
+ connections_[remote] = _connection;
+ _connection->start();
+ }
}
start();
@@ -120,6 +134,8 @@ void local_server_endpoint_impl::accept_cbk(
// 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),
@@ -185,6 +201,20 @@ 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() {
}
@@ -241,6 +271,12 @@ void local_server_endpoint_impl::connection::receive_cbk(
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();
+ }
+
#if 0
std::stringstream local_msg;
local_msg << "lse::c<" << this << ">rcb::thunk: ";
diff --git a/implementation/endpoints/src/server_endpoint_impl.cpp b/implementation/endpoints/src/server_endpoint_impl.cpp
index b67ecec..c8e513b 100644
--- a/implementation/endpoints/src/server_endpoint_impl.cpp
+++ b/implementation/endpoints/src/server_endpoint_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -8,7 +8,7 @@
#include <boost/asio/buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
-#include <boost/asio/ip/udp.hpp>
+#include <boost/asio/ip/udp_ext.hpp>
#include <boost/asio/local/stream_protocol.hpp>
#include <vsomeip/defines.hpp>
@@ -21,26 +21,34 @@
namespace vsomeip {
-template<typename Protocol, int MaxBufferSize>
-server_endpoint_impl<Protocol, MaxBufferSize>::server_endpoint_impl(
+template<typename Protocol>
+server_endpoint_impl<Protocol>::server_endpoint_impl(
std::shared_ptr<endpoint_host> _host, endpoint_type _local,
boost::asio::io_service &_io, std::uint32_t _max_message_size)
- : endpoint_impl<MaxBufferSize>(_host, _io, _max_message_size),
- flush_timer_(_io), local_(_local) {
+ : endpoint_impl<Protocol>(_host, _local, _io, _max_message_size),
+ flush_timer_(_io) {
}
-template<typename Protocol, int MaxBufferSize>
-bool server_endpoint_impl<Protocol, MaxBufferSize>::is_client() const {
+template<typename Protocol>
+server_endpoint_impl<Protocol>::~server_endpoint_impl() {
+}
+
+template<typename Protocol>
+void server_endpoint_impl<Protocol>::stop() {
+}
+
+template<typename Protocol>
+bool server_endpoint_impl<Protocol>::is_client() const {
return false;
}
-template<typename Protocol, int MaxBufferSize>
-bool server_endpoint_impl<Protocol, MaxBufferSize>::is_connected() const {
+template<typename Protocol>
+bool server_endpoint_impl<Protocol>::is_connected() const {
return true;
}
-template<typename Protocol, int MaxBufferSize>
-bool server_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data,
+template<typename Protocol>
+bool server_endpoint_impl<Protocol>::send(const uint8_t *_data,
uint32_t _size, bool _flush) {
#if 0
std::stringstream msg;
@@ -52,6 +60,10 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data,
endpoint_type its_target;
bool is_valid_target(false);
+ if(endpoint_impl<Protocol>::sending_blocked_) {
+ return false;
+ }
+
if (VSOMEIP_SESSION_POS_MAX < _size) {
std::lock_guard<std::mutex> its_lock(mutex_);
@@ -66,6 +78,7 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data,
std::memcpy(&its_session, &_data[VSOMEIP_SESSION_POS_MIN],
sizeof(session_t));
+ clients_mutex_.lock();
auto found_client = clients_.find(its_client);
if (found_client != clients_.end()) {
auto found_session = found_client->second.find(its_session);
@@ -74,12 +87,9 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data,
is_valid_target = true;
}
} else {
- event_t its_event = VSOMEIP_BYTES_TO_WORD(
- _data[VSOMEIP_METHOD_POS_MIN],
- _data[VSOMEIP_METHOD_POS_MAX]);
- is_valid_target
- = get_multicast(its_service, its_event, its_target);
+ is_valid_target = get_default_target(its_service, its_target);
}
+ clients_mutex_.unlock();
if (is_valid_target) {
is_valid_target = send_intern(its_target, _data, _size, _flush);
@@ -88,15 +98,18 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data,
return is_valid_target;
}
-template<typename Protocol, int MaxBufferSize>
-bool server_endpoint_impl<Protocol, MaxBufferSize>::send_intern(
+template<typename Protocol>
+bool server_endpoint_impl<Protocol>::send_intern(
endpoint_type _target, const byte_t *_data, uint32_t _size,
bool _flush) {
- bool is_flushing(false);
message_buffer_ptr_t target_packetizer;
queue_iterator_type target_queue_iterator;
+ if(endpoint_impl<Protocol>::sending_blocked_) {
+ return false;
+ }
+
auto found_packetizer = packetizer_.find(_target);
if (found_packetizer != packetizer_.end()) {
target_packetizer = found_packetizer->second;
@@ -115,10 +128,13 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send_intern(
}
// TODO compare against value from configuration here
- if (target_packetizer->size() + _size > endpoint_impl<MaxBufferSize>::max_message_size_) {
+ const bool queue_size_zero_on_entry(target_queue_iterator->second.empty());
+ if (target_packetizer->size() + _size
+ > endpoint_impl<Protocol>::max_message_size_
+ && !target_packetizer->empty()) {
target_queue_iterator->second.push_back(target_packetizer);
- is_flushing = true;
- packetizer_[_target] = std::make_shared<message_buffer_t>();
+ target_packetizer = std::make_shared<message_buffer_t>();
+ packetizer_[_target] = target_packetizer;
}
target_packetizer->insert(target_packetizer->end(), _data, _data + _size);
@@ -126,29 +142,26 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send_intern(
if (_flush) {
flush_timer_.cancel();
target_queue_iterator->second.push_back(target_packetizer);
- is_flushing = true;
packetizer_[_target] = std::make_shared<message_buffer_t>();
} else {
std::chrono::milliseconds flush_timeout(VSOMEIP_DEFAULT_FLUSH_TIMEOUT);
flush_timer_.expires_from_now(flush_timeout); // TODO: use configured value
flush_timer_.async_wait(
- std::bind(&server_endpoint_impl<
- Protocol, MaxBufferSize
- >::flush_cbk,
+ std::bind(&server_endpoint_impl<Protocol>::flush_cbk,
this->shared_from_this(),
_target,
std::placeholders::_1));
}
- if (is_flushing && target_queue_iterator->second.size() == 1) { // no writing in progress
+ if (queue_size_zero_on_entry && !target_queue_iterator->second.empty()) { // no writing in progress
send_queued(target_queue_iterator);
}
return true;
}
-template<typename Protocol, int MaxBufferSize>
-bool server_endpoint_impl<Protocol, MaxBufferSize>::flush(
+template<typename Protocol>
+bool server_endpoint_impl<Protocol>::flush(
endpoint_type _target) {
bool is_flushed = false;
std::lock_guard<std::mutex> its_lock(mutex_);
@@ -161,14 +174,14 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::flush(
return is_flushed;
}
-template<typename Protocol, int MaxBufferSize>
-void server_endpoint_impl<Protocol, MaxBufferSize>::connect_cbk(
+template<typename Protocol>
+void server_endpoint_impl<Protocol>::connect_cbk(
boost::system::error_code const &_error) {
(void)_error;
}
-template<typename Protocol, int MaxBufferSize>
-void server_endpoint_impl<Protocol, MaxBufferSize>::send_cbk(
+template<typename Protocol>
+void server_endpoint_impl<Protocol>::send_cbk(
queue_iterator_type _queue_iterator, boost::system::error_code const &_error,
std::size_t _bytes) {
(void)_bytes;
@@ -182,8 +195,8 @@ void server_endpoint_impl<Protocol, MaxBufferSize>::send_cbk(
}
}
-template<typename Protocol, int MaxBufferSize>
-void server_endpoint_impl<Protocol, MaxBufferSize>::flush_cbk(
+template<typename Protocol>
+void server_endpoint_impl<Protocol>::flush_cbk(
endpoint_type _target, const boost::system::error_code &_error_code) {
if (!_error_code) {
(void) flush(_target);
@@ -192,15 +205,9 @@ void server_endpoint_impl<Protocol, MaxBufferSize>::flush_cbk(
// Instantiate template
#ifndef WIN32
-template class server_endpoint_impl<
- boost::asio::local::stream_protocol,
- VSOMEIP_MAX_LOCAL_MESSAGE_SIZE> ;
+template class server_endpoint_impl<boost::asio::local::stream_protocol>;
#endif
-template class server_endpoint_impl<
- boost::asio::ip::tcp,
- VSOMEIP_MAX_TCP_MESSAGE_SIZE> ;
-template class server_endpoint_impl<
- boost::asio::ip::udp,
- VSOMEIP_MAX_UDP_MESSAGE_SIZE> ;
+template class server_endpoint_impl<boost::asio::ip::tcp>;
+template class server_endpoint_impl<boost::asio::ip::udp_ext>;
} // namespace vsomeip
diff --git a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp
index 26c7424..d31a38b 100644
--- a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp
+++ b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -20,15 +20,22 @@ namespace ip = boost::asio::ip;
namespace vsomeip {
tcp_client_endpoint_impl::tcp_client_endpoint_impl(
- std::shared_ptr< endpoint_host > _host, endpoint_type _remote,
- boost::asio::io_service &_io, std::uint32_t _max_message_size)
- : tcp_client_endpoint_base_impl(_host, _remote, _io, _max_message_size),
+ std::shared_ptr< endpoint_host > _host,
+ endpoint_type _local,
+ endpoint_type _remote,
+ boost::asio::io_service &_io,
+ std::uint32_t _max_message_size)
+ : tcp_client_endpoint_base_impl(_host, _local, _remote, _io, _max_message_size),
recv_buffer_(_max_message_size, 0),
recv_buffer_size_(0) {
is_supporting_magic_cookies_ = true;
}
tcp_client_endpoint_impl::~tcp_client_endpoint_impl() {
+ std::shared_ptr<endpoint_host> its_host = host_.lock();
+ if (its_host) {
+ its_host->release_port(local_.port(), true);
+ }
}
bool tcp_client_endpoint_impl::is_local() const {
@@ -40,19 +47,41 @@ void tcp_client_endpoint_impl::start() {
}
void tcp_client_endpoint_impl::connect() {
- socket_.open(remote_.protocol());
+ boost::system::error_code its_error;
+ socket_.open(remote_.protocol(), its_error);
- // Nagle algorithm off
- socket_.set_option(ip::tcp::no_delay(true));
+ if (!its_error || its_error == boost::asio::error::already_open) {
+ // Nagle algorithm off
+ socket_.set_option(ip::tcp::no_delay(true));
- socket_.async_connect(
- remote_,
- std::bind(
- &tcp_client_endpoint_base_impl::connect_cbk,
- shared_from_this(),
- std::placeholders::_1
- )
- );
+ // Enable SO_REUSEADDR to avoid bind problems with services going offline
+ // and coming online again and the user has specified only a small number
+ // of ports in the clients section for one service instance
+ socket_.set_option(boost::asio::socket_base::reuse_address(true));
+
+ // In case a client endpoint port was configured,
+ // bind to it before connecting
+ if (local_.port() != ILLEGAL_PORT) {
+ boost::system::error_code its_bind_error;
+ socket_.bind(local_, its_bind_error);
+ if(its_bind_error) {
+ VSOMEIP_WARNING << "tcp_client_endpoint::connect: "
+ "Error binding socket: " << its_bind_error.message();
+ }
+ }
+
+ socket_.async_connect(
+ remote_,
+ std::bind(
+ &tcp_client_endpoint_base_impl::connect_cbk,
+ shared_from_this(),
+ std::placeholders::_1
+ )
+ );
+ } else {
+ VSOMEIP_WARNING << "tcp_client_endpoint::connect: Error opening socket: "
+ << its_error.message();
+ }
}
void tcp_client_endpoint_impl::receive() {
@@ -73,7 +102,12 @@ void tcp_client_endpoint_impl::receive() {
}
void tcp_client_endpoint_impl::send_queued() {
- message_buffer_ptr_t its_buffer = queue_.front();
+ message_buffer_ptr_t its_buffer;
+ if(queue_.size()) {
+ its_buffer = queue_.front();
+ } else {
+ return;
+ }
if (has_enabled_magic_cookies_)
send_magic_cookie(its_buffer);
@@ -107,11 +141,13 @@ bool tcp_client_endpoint_impl::get_remote_address(
}
unsigned short tcp_client_endpoint_impl::get_local_port() const {
- return socket_.local_endpoint().port();
+ boost::system::error_code its_error;
+ return socket_.local_endpoint(its_error).port();
}
unsigned short tcp_client_endpoint_impl::get_remote_port() const {
- return socket_.remote_endpoint().port();
+ boost::system::error_code its_error;
+ return socket_.remote_endpoint(its_error).port();
}
bool tcp_client_endpoint_impl::is_reliable() const {
@@ -195,9 +231,22 @@ void tcp_client_endpoint_impl::receive_cbk(
has_full_message = true; // trigger next loop
}
} else if (current_message_size > max_message_size_) {
- VSOMEIP_ERROR << "Message exceeds maximum message size. "
- << "Resetting receiver.";
- recv_buffer_size_ = 0;
+ if (has_enabled_magic_cookies_) {
+ VSOMEIP_ERROR << "Received a TCP message which exceeds "
+ << "maximum message size ("
+ << std::dec << current_message_size
+ << "). Magic Cookies are enabled: "
+ << "Resetting receiver.";
+ recv_buffer_size_ = 0;
+ } else {
+ VSOMEIP_ERROR << "Received a TCP message which exceeds "
+ << "maximum message size ("
+ << std::dec << current_message_size
+ << ") Magic cookies are disabled: "
+ << "Client will be disabled!";
+ recv_buffer_size_ = 0;
+ return;
+ }
}
} while (has_full_message && recv_buffer_size_);
if (its_iteration_gap) {
@@ -206,7 +255,7 @@ void tcp_client_endpoint_impl::receive_cbk(
recv_buffer_[i] = recv_buffer_[i + its_iteration_gap];
}
}
- restart();
+ receive();
} 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 0084d8e..fc31850 100644
--- a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp
+++ b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -46,28 +46,61 @@ void tcp_server_endpoint_impl::start() {
}
void tcp_server_endpoint_impl::stop() {
+ server_endpoint_impl::stop();
for (auto& i : connections_)
i.second->stop();
- acceptor_.close();
+ if(acceptor_.is_open()) {
+ boost::system::error_code its_error;
+ acceptor_.close(its_error);
+ }
}
bool tcp_server_endpoint_impl::send_to(
const std::shared_ptr<endpoint_definition> _target,
const byte_t *_data,
uint32_t _size, bool _flush) {
+ std::lock_guard<std::mutex> its_lock(mutex_);
endpoint_type its_target(_target->get_address(), _target->get_port());
return send_intern(its_target, _data, _size, _flush);
}
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())
+ 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();
+ }
+}
+
+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());
+ }
+ return is_connected;
}
tcp_server_endpoint_impl::endpoint_type
tcp_server_endpoint_impl::get_remote() const {
- return current_->get_socket().remote_endpoint();
+ boost::system::error_code its_error;
+ return current_->get_socket().remote_endpoint(its_error);
}
bool tcp_server_endpoint_impl::get_remote_address(
@@ -77,9 +110,7 @@ bool tcp_server_endpoint_impl::get_remote_address(
boost::system::error_code its_error;
tcp_server_endpoint_impl::endpoint_type its_endpoint =
current_->get_socket().remote_endpoint(its_error);
- if (its_error) {
- return false;
- } else {
+ if (!its_error) {
boost::asio::ip::address its_address = its_endpoint.address();
if (!its_address.is_unspecified()) {
_address = its_address;
@@ -90,7 +121,19 @@ bool tcp_server_endpoint_impl::get_remote_address(
return false;
}
-bool tcp_server_endpoint_impl::get_multicast(service_t, event_t,
+unsigned short tcp_server_endpoint_impl::get_remote_port() const {
+ if (current_) {
+ boost::system::error_code its_error;
+ tcp_server_endpoint_impl::endpoint_type its_endpoint =
+ current_->get_socket().remote_endpoint(its_error);
+ if (!its_error) {
+ return its_endpoint.port();
+ }
+ }
+ return 0;
+}
+
+bool tcp_server_endpoint_impl::get_default_target(service_t,
tcp_server_endpoint_impl::endpoint_type &) const {
return false;
}
@@ -100,17 +143,23 @@ void tcp_server_endpoint_impl::accept_cbk(connection::ptr _connection,
if (!_error) {
socket_type &new_connection_socket = _connection->get_socket();
- endpoint_type remote = new_connection_socket.remote_endpoint();
-
- connections_[remote] = _connection;
- _connection->start();
-
+ boost::system::error_code its_error;
+ endpoint_type remote = new_connection_socket.remote_endpoint(its_error);
+ if(!its_error) {
+ connections_[remote] = _connection;
+ _connection->start();
+ }
+ }
+ if (_error != boost::asio::error::operation_aborted) {
start();
+ } else {
+ VSOMEIP_DEBUG << "Endpoint was stopped, don't starting again";
}
}
unsigned short tcp_server_endpoint_impl::get_local_port() const {
- return acceptor_.local_endpoint().port();
+ boost::system::error_code its_error;
+ return acceptor_.local_endpoint(its_error).port();
}
bool tcp_server_endpoint_impl::is_reliable() const {
@@ -163,8 +212,10 @@ 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()) {
- socket_.shutdown(socket_.shutdown_both);
- socket_.close();
+ 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);
}
}
@@ -172,8 +223,9 @@ void tcp_server_endpoint_impl::connection::send_queued(
queue_iterator_type _queue_iterator) {
message_buffer_ptr_t its_buffer = _queue_iterator->second.front();
- if (server_->has_enabled_magic_cookies_)
+ if (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,
@@ -240,20 +292,27 @@ void tcp_server_endpoint_impl::connection::receive_cbk(
}
}
if (needs_forwarding) {
- if (utility::is_request(recv_buffer_[VSOMEIP_MESSAGE_TYPE_POS])) {
+ if (utility::is_request(
+ recv_buffer_[its_iteration_gap
+ + VSOMEIP_MESSAGE_TYPE_POS])) {
client_t its_client;
std::memcpy(&its_client,
- &recv_buffer_[VSOMEIP_CLIENT_POS_MIN],
+ &recv_buffer_[its_iteration_gap + VSOMEIP_CLIENT_POS_MIN],
sizeof(client_t));
session_t its_session;
std::memcpy(&its_session,
- &recv_buffer_[VSOMEIP_SESSION_POS_MIN],
+ &recv_buffer_[its_iteration_gap + VSOMEIP_SESSION_POS_MIN],
sizeof(session_t));
{
std::lock_guard<std::mutex> its_lock(stop_mutex_);
if (socket_.is_open()) {
- server_->clients_[its_client][its_session] =
- socket_.remote_endpoint();
+ 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;
+ }
+ server_->clients_mutex_.unlock();
server_->current_ = this;
}
}
@@ -290,10 +349,22 @@ void tcp_server_endpoint_impl::connection::receive_cbk(
}
}
} else if (current_message_size > max_message_size_) {
- VSOMEIP_ERROR << "Message exceeds maximum message size ("
- << std::dec << current_message_size
- << "). Resetting receiver.";
- recv_buffer_size_ = 0;
+ if (server_->has_enabled_magic_cookies_) {
+ VSOMEIP_ERROR << "Received a TCP message which exceeds "
+ << "maximum message size ("
+ << std::dec << current_message_size
+ << "). Magic Cookies are enabled: "
+ << "Resetting receiver.";
+ recv_buffer_size_ = 0;
+ } else {
+ VSOMEIP_ERROR << "Received a TCP message which exceeds "
+ << "maximum message size ("
+ << std::dec << current_message_size
+ << ") Magic cookies are disabled: "
+ << "Connection will be disabled!";
+ recv_buffer_size_ = 0;
+ return;
+ }
}
} while (has_full_message && recv_buffer_size_);
if (its_iteration_gap) {
@@ -317,6 +388,7 @@ client_t tcp_server_endpoint_impl::get_client(std::shared_ptr<endpoint_definitio
}
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]) {
auto endpoint = its_session.second;
diff --git a/implementation/endpoints/src/udp_client_endpoint_impl.cpp b/implementation/endpoints/src/udp_client_endpoint_impl.cpp
index a5a90cc..a6029db 100644
--- a/implementation/endpoints/src/udp_client_endpoint_impl.cpp
+++ b/implementation/endpoints/src/udp_client_endpoint_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -16,14 +16,20 @@
namespace vsomeip {
udp_client_endpoint_impl::udp_client_endpoint_impl(
- std::shared_ptr< endpoint_host > _host, endpoint_type _remote,
+ std::shared_ptr< endpoint_host > _host,
+ endpoint_type _local,
+ endpoint_type _remote,
boost::asio::io_service &_io)
- : udp_client_endpoint_base_impl(_host, _remote, _io, VSOMEIP_MAX_UDP_MESSAGE_SIZE),
- recv_buffer_(VSOMEIP_MAX_UDP_MESSAGE_SIZE, 0),
- recv_buffer_size_(0) {
+ : udp_client_endpoint_base_impl(_host, _local, _remote, _io,
+ VSOMEIP_MAX_UDP_MESSAGE_SIZE),
+ recv_buffer_(VSOMEIP_MAX_UDP_MESSAGE_SIZE, 0) {
}
udp_client_endpoint_impl::~udp_client_endpoint_impl() {
+ std::shared_ptr<endpoint_host> its_host = host_.lock();
+ if (its_host) {
+ its_host->release_port(local_.port(), false);
+ }
}
bool udp_client_endpoint_impl::is_local() const {
@@ -31,7 +37,13 @@ bool udp_client_endpoint_impl::is_local() const {
}
void udp_client_endpoint_impl::connect() {
- socket_.async_connect(
+ // In case a client endpoint port was configured,
+ // bind to it before connecting
+ if (local_.port() != ILLEGAL_PORT) {
+ socket_.bind(local_);
+ }
+
+ socket_.async_connect(
remote_,
std::bind(
&udp_client_endpoint_base_impl::connect_cbk,
@@ -42,12 +54,23 @@ void udp_client_endpoint_impl::connect() {
}
void udp_client_endpoint_impl::start() {
- socket_.open(remote_.protocol());
- connect();
+ boost::system::error_code its_error;
+ socket_.open(remote_.protocol(), its_error);
+ if (!its_error || its_error == boost::asio::error::already_open) {
+ connect();
+ } else {
+ VSOMEIP_WARNING << "udp_client_endpoint::connect: Error opening socket: "
+ << its_error.message();
+ }
}
void udp_client_endpoint_impl::send_queued() {
- message_buffer_ptr_t its_buffer = queue_.front();
+ message_buffer_ptr_t its_buffer;
+ if(queue_.size()) {
+ its_buffer = queue_.front();
+ } else {
+ return;
+ }
#if 0
std::stringstream msg;
msg << "ucei<" << remote_.address() << ":"
@@ -69,13 +92,8 @@ void udp_client_endpoint_impl::send_queued() {
}
void udp_client_endpoint_impl::receive() {
- 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_from(
- boost::asio::buffer(&recv_buffer_[recv_buffer_size_], buffer_size),
+ boost::asio::buffer(&recv_buffer_[0], max_message_size_),
remote_,
std::bind(
&udp_client_endpoint_impl::receive_cbk,
@@ -95,11 +113,13 @@ bool udp_client_endpoint_impl::get_remote_address(
}
unsigned short udp_client_endpoint_impl::get_local_port() const {
- return socket_.local_endpoint().port();
+ boost::system::error_code its_error;
+ return socket_.local_endpoint(its_error).port();
}
unsigned short udp_client_endpoint_impl::get_remote_port() const {
- return socket_.remote_endpoint().port();
+ boost::system::error_code its_error;
+ return socket_.remote_endpoint(its_error).port();
}
void udp_client_endpoint_impl::receive_cbk(
@@ -114,17 +134,15 @@ void udp_client_endpoint_impl::receive_cbk(
<< (int) recv_buffer_[i] << " ";
VSOMEIP_DEBUG << msg.str();
#endif
- recv_buffer_size_ += _bytes;
uint32_t current_message_size
= utility::get_message_size(&this->recv_buffer_[0],
- (uint32_t) recv_buffer_size_);
+ (uint32_t) _bytes);
if (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE &&
current_message_size <= _bytes) {
its_host->on_message(&recv_buffer_[0], current_message_size, this);
} else {
VSOMEIP_ERROR << "Received a unreliable vSomeIP message with bad length field";
}
- recv_buffer_size_ = 0;
}
if (!_error) {
receive();
diff --git a/implementation/endpoints/src/udp_server_endpoint_impl.cpp b/implementation/endpoints/src/udp_server_endpoint_impl.cpp
index 4593c1f..8b3fd30 100644
--- a/implementation/endpoints/src/udp_server_endpoint_impl.cpp
+++ b/implementation/endpoints/src/udp_server_endpoint_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -8,9 +8,11 @@
#include <boost/asio/ip/multicast.hpp>
+
#include "../include/endpoint_definition.hpp"
#include "../include/endpoint_host.hpp"
#include "../include/udp_server_endpoint_impl.hpp"
+#include "../../configuration/include/configuration.hpp"
#include "../../logging/include/logger.hpp"
#include "../../utility/include/byteorder.hpp"
#include "../../utility/include/utility.hpp"
@@ -24,22 +26,37 @@ udp_server_endpoint_impl::udp_server_endpoint_impl(
std::shared_ptr< endpoint_host > _host,
endpoint_type _local,
boost::asio::io_service &_io)
- : server_endpoint_impl<
- ip::udp, VSOMEIP_MAX_UDP_MESSAGE_SIZE
- >(_host, _local, _io, VSOMEIP_MAX_UDP_MESSAGE_SIZE),
+ : server_endpoint_impl<ip::udp_ext>(
+ _host, _local, _io, VSOMEIP_MAX_UDP_MESSAGE_SIZE),
socket_(_io, _local.protocol()),
- recv_buffer_(VSOMEIP_MAX_UDP_MESSAGE_SIZE, 0),
- recv_buffer_size_(0) {
+ recv_buffer_(VSOMEIP_MAX_UDP_MESSAGE_SIZE, 0) {
boost::system::error_code ec;
boost::asio::socket_base::reuse_address optionReuseAddress(true);
socket_.set_option(optionReuseAddress);
+ if (_local.address().is_v4()) {
+ boost::asio::ip::address_v4 its_unicast_address
+ = configuration::get()->get_unicast_address().to_v4();
+ boost::asio::ip::multicast::outbound_interface option(its_unicast_address);
+ socket_.set_option(option);
+ }
+
socket_.bind(_local, ec);
boost::asio::detail::throw_error(ec, "bind");
boost::asio::socket_base::broadcast option(true);
socket_.set_option(option);
+
+#ifdef WIN32
+ const char* optval("0001");
+ ::setsockopt(socket_.native(), IPPROTO_IP, IP_PKTINFO,
+ optval, sizeof(optval));
+#else
+ int optval(1);
+ ::setsockopt(socket_.native(), IPPROTO_IP, IP_PKTINFO,
+ &optval, sizeof(optval));
+#endif
}
udp_server_endpoint_impl::~udp_server_endpoint_impl() {
@@ -55,28 +72,26 @@ void udp_server_endpoint_impl::start() {
void udp_server_endpoint_impl::stop() {
std::lock_guard<std::mutex> its_lock(stop_mutex_);
+ server_endpoint_impl::stop();
if (socket_.is_open()) {
- socket_.close();
+ boost::system::error_code its_error;
+ socket_.close(its_error);
}
}
void udp_server_endpoint_impl::receive() {
- if (recv_buffer_size_ == max_message_size_) {
- // Overrun -> Reset buffer
- recv_buffer_size_ = 0;
- }
std::lock_guard<std::mutex> its_lock(stop_mutex_);
if(socket_.is_open()) {
- size_t buffer_size = max_message_size_ - recv_buffer_size_;
socket_.async_receive_from(
- boost::asio::buffer(&recv_buffer_[recv_buffer_size_], buffer_size),
+ boost::asio::buffer(&recv_buffer_[0], max_message_size_),
remote_,
std::bind(
&udp_server_endpoint_impl::receive_cbk,
std::dynamic_pointer_cast<
udp_server_endpoint_impl >(shared_from_this()),
std::placeholders::_1,
- std::placeholders::_2
+ std::placeholders::_2,
+ std::placeholders::_3
)
);
}
@@ -89,8 +104,9 @@ void udp_server_endpoint_impl::restart() {
bool udp_server_endpoint_impl::send_to(
const std::shared_ptr<endpoint_definition> _target,
const byte_t *_data, uint32_t _size, bool _flush) {
- endpoint_type its_target(_target->get_address(), _target->get_port());
- return send_intern(its_target, _data, _size, _flush);
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ endpoint_type its_target(_target->get_address(), _target->get_port());
+ return send_intern(its_target, _data, _size, _flush);
}
void udp_server_endpoint_impl::send_queued(
@@ -134,36 +150,31 @@ bool udp_server_endpoint_impl::get_remote_address(
return true;
}
-bool udp_server_endpoint_impl::get_multicast(service_t _service, event_t _event,
- udp_server_endpoint_impl::endpoint_type &_target) const {
- bool is_valid(false);
- auto find_service = multicasts_.find(_service);
- if (find_service != multicasts_.end()) {
- auto find_event = find_service->second.find(_event);
- if (find_event != find_service->second.end()) {
- _target = find_event->second;
- is_valid = true;
- }
- }
- return is_valid;
+unsigned short udp_server_endpoint_impl::get_remote_port() const {
+ return remote_.port();
+}
+
+bool udp_server_endpoint_impl::is_joined(const std::string &_address) const {
+ return (joined_.find(_address) != joined_.end());
}
void udp_server_endpoint_impl::join(const std::string &_address) {
try {
- if (local_.address().is_v4()) {
- socket_.set_option(
- boost::asio::ip::udp::socket::reuse_address(true));
- socket_.set_option(
- boost::asio::ip::multicast::enable_loopback(false));
- socket_.set_option(boost::asio::ip::multicast::join_group(
- boost::asio::ip::address::from_string(_address).to_v4()));
- } else if (local_.address().is_v6()) {
- socket_.set_option(
- boost::asio::ip::udp::socket::reuse_address(true));
- socket_.set_option(
- boost::asio::ip::multicast::enable_loopback(false));
- socket_.set_option(boost::asio::ip::multicast::join_group(
- boost::asio::ip::address::from_string(_address).to_v6()));
+ if (!is_joined(_address)) {
+ if (local_.address().is_v4()) {
+ socket_.set_option(ip::udp_ext::socket::reuse_address(true));
+ socket_.set_option(
+ boost::asio::ip::multicast::enable_loopback(false));
+ socket_.set_option(boost::asio::ip::multicast::join_group(
+ boost::asio::ip::address::from_string(_address).to_v4()));
+ } else if (local_.address().is_v6()) {
+ socket_.set_option(ip::udp_ext::socket::reuse_address(true));
+ socket_.set_option(
+ boost::asio::ip::multicast::enable_loopback(false));
+ socket_.set_option(boost::asio::ip::multicast::join_group(
+ boost::asio::ip::address::from_string(_address).to_v6()));
+ }
+ joined_.insert(_address);
}
}
catch (const std::exception &e) {
@@ -173,12 +184,15 @@ void udp_server_endpoint_impl::join(const std::string &_address) {
void udp_server_endpoint_impl::leave(const std::string &_address) {
try {
- if (local_.address().is_v4()) {
- socket_.set_option(boost::asio::ip::multicast::leave_group(
- boost::asio::ip::address::from_string(_address)));
- } else if (local_.address().is_v6()) {
- socket_.set_option(boost::asio::ip::multicast::leave_group(
- boost::asio::ip::address::from_string(_address)));
+ if (is_joined(_address)) {
+ if (local_.address().is_v4()) {
+ socket_.set_option(boost::asio::ip::multicast::leave_group(
+ boost::asio::ip::address::from_string(_address)));
+ } else if (local_.address().is_v6()) {
+ socket_.set_option(boost::asio::ip::multicast::leave_group(
+ boost::asio::ip::address::from_string(_address)));
+ }
+ joined_.erase(_address);
}
}
catch (const std::exception &e) {
@@ -186,36 +200,41 @@ void udp_server_endpoint_impl::leave(const std::string &_address) {
}
}
-void udp_server_endpoint_impl::add_multicast(
- service_t _service, instance_t _instance,
- const std::string &_address, uint16_t _port) {
+void udp_server_endpoint_impl::add_default_target(
+ service_t _service, const std::string &_address, uint16_t _port) {
endpoint_type its_endpoint(
- boost::asio::ip::address::from_string(_address), _port);
- multicasts_[_service][_instance] = its_endpoint;
+ boost::asio::ip::address::from_string(_address), _port);
+ default_targets_[_service] = its_endpoint;
}
-void udp_server_endpoint_impl::remove_multicast(
- service_t _service, instance_t _instance) {
- auto found_service = multicasts_.find(_service);
- if (found_service != multicasts_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- found_service->second.erase(_instance);
- }
+void udp_server_endpoint_impl::remove_default_target(service_t _service) {
+ default_targets_.erase(_service);
+}
+
+bool udp_server_endpoint_impl::get_default_target(service_t _service,
+ udp_server_endpoint_impl::endpoint_type &_target) const {
+ bool is_valid(false);
+ auto find_service = default_targets_.find(_service);
+ if (find_service != default_targets_.end()) {
+ _target = find_service->second;
+ is_valid = true;
}
+ return is_valid;
}
unsigned short udp_server_endpoint_impl::get_local_port() const {
- return socket_.local_endpoint().port();
+ boost::system::error_code its_error;
+ return socket_.local_endpoint(its_error).port();
}
// TODO: find a better way to structure the receive functions
void udp_server_endpoint_impl::receive_cbk(
- boost::system::error_code const &_error, std::size_t _bytes) {
+ boost::system::error_code const &_error, std::size_t _bytes,
+ boost::asio::ip::address const &_destination) {
#if 0
std::stringstream msg;
msg << "usei::rcb(" << _error.message() << "): ";
- for (std::size_t i = 0; i < _bytes + recv_buffer_size_; ++i)
+ for (std::size_t i = 0; i < _bytes; ++i)
msg << std::hex << std::setw(2) << std::setfill('0')
<< (int) recv_buffer_[i] << " ";
VSOMEIP_DEBUG << msg.str();
@@ -223,34 +242,50 @@ void udp_server_endpoint_impl::receive_cbk(
std::shared_ptr<endpoint_host> its_host = this->host_.lock();
if (its_host) {
if (!_error && 0 < _bytes) {
- recv_buffer_size_ += _bytes;
- uint32_t current_message_size
- = utility::get_message_size(&this->recv_buffer_[0],
- (uint32_t) recv_buffer_size_);
- if (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE &&
- current_message_size <= _bytes) {
- if (utility::is_request(
- recv_buffer_[VSOMEIP_MESSAGE_TYPE_POS])) {
- client_t its_client;
- std::memcpy(&its_client,
- &recv_buffer_[VSOMEIP_CLIENT_POS_MIN],
- sizeof(client_t));
- session_t its_session;
- std::memcpy(&its_session,
- &recv_buffer_[VSOMEIP_SESSION_POS_MIN],
- sizeof(session_t));
- clients_[its_client][its_session] = remote_;
+ std::size_t remaining_bytes = _bytes;
+ std::size_t i = 0;
+ do {
+ uint32_t current_message_size
+ = utility::get_message_size(&this->recv_buffer_[i],
+ (uint32_t) remaining_bytes);
+ if (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE &&
+ current_message_size <= remaining_bytes) {
+ remaining_bytes -= current_message_size;
+ if (utility::is_request(
+ recv_buffer_[i + VSOMEIP_MESSAGE_TYPE_POS])) {
+ client_t its_client;
+ std::memcpy(&its_client,
+ &recv_buffer_[i + VSOMEIP_CLIENT_POS_MIN],
+ sizeof(client_t));
+ session_t its_session;
+ std::memcpy(&its_session,
+ &recv_buffer_[i + VSOMEIP_SESSION_POS_MIN],
+ sizeof(session_t));
+ clients_mutex_.lock();
+ clients_[its_client][its_session] = remote_;
+ clients_mutex_.unlock();
+ }
+ service_t its_service = VSOMEIP_BYTES_TO_WORD(recv_buffer_[i + VSOMEIP_SERVICE_POS_MIN],
+ recv_buffer_[i + VSOMEIP_SERVICE_POS_MAX]);
+ if (its_service != VSOMEIP_SD_SERVICE ||
+ (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE &&
+ current_message_size >= remaining_bytes)) {
+ its_host->on_message(&recv_buffer_[i], current_message_size, this, _destination);
+ } else {
+ //ignore messages for service discovery with shorter SomeIP length
+ VSOMEIP_ERROR << "Received an unreliable vSomeIP SD message with too short length field";
+ }
+ i += current_message_size;
+ } else {
+ VSOMEIP_ERROR << "Received an unreliable vSomeIP message with bad length field";
+ service_t its_service = VSOMEIP_BYTES_TO_WORD(recv_buffer_[VSOMEIP_SERVICE_POS_MIN],
+ recv_buffer_[VSOMEIP_SERVICE_POS_MAX]);
+ if (its_service != VSOMEIP_SD_SERVICE) {
+ its_host->on_error(&recv_buffer_[i], (uint32_t)remaining_bytes, this);
+ }
+ remaining_bytes = 0;
}
- its_host->on_message(&recv_buffer_[0], current_message_size, this);
- } else {
- VSOMEIP_ERROR << "Received a unreliable vSomeIP message with bad length field";
- service_t its_service = VSOMEIP_BYTES_TO_WORD(recv_buffer_[VSOMEIP_SERVICE_POS_MIN],
- recv_buffer_[VSOMEIP_SERVICE_POS_MAX]);
- if (its_service != VSOMEIP_SD_SERVICE) {
- its_host->on_error(&recv_buffer_[0], (uint32_t)_bytes, this);
- }
- }
- recv_buffer_size_ = 0;
+ } while (remaining_bytes > 0);
restart();
} else {
receive();
@@ -260,6 +295,7 @@ void udp_server_endpoint_impl::receive_cbk(
client_t udp_server_endpoint_impl::get_client(std::shared_ptr<endpoint_definition> _endpoint) {
endpoint_type endpoint(_endpoint->get_address(), _endpoint->get_port());
+ std::lock_guard<std::mutex> its_lock(clients_mutex_);
for (auto its_client : clients_) {
for (auto its_session : clients_[its_client.first]) {
if (endpoint == its_session.second) {
diff --git a/implementation/endpoints/src/virtual_server_endpoint_impl.cpp b/implementation/endpoints/src/virtual_server_endpoint_impl.cpp
index 7700874..516619f 100644
--- a/implementation/endpoints/src/virtual_server_endpoint_impl.cpp
+++ b/implementation/endpoints/src/virtual_server_endpoint_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -60,19 +60,17 @@ void virtual_server_endpoint_impl::leave(const std::string &_address) {
(void)_address;
}
-void virtual_server_endpoint_impl::add_multicast(
- service_t _service, event_t _event,
+void virtual_server_endpoint_impl::add_default_target(
+ service_t _service,
const std::string &_address, uint16_t _port) {
(void)_service;
- (void)_event;
(void)_address;
(void)_port;
}
-void virtual_server_endpoint_impl::remove_multicast(
- service_t _service, event_t _event) {
+void virtual_server_endpoint_impl::remove_default_target(
+ service_t _service) {
(void)_service;
- (void)_event;
}
bool virtual_server_endpoint_impl::get_remote_address(
diff --git a/implementation/helper/boost/asio/basic_datagram_socket_ext.hpp b/implementation/helper/boost/asio/basic_datagram_socket_ext.hpp
new file mode 100644
index 0000000..c9a9123
--- /dev/null
+++ b/implementation/helper/boost/asio/basic_datagram_socket_ext.hpp
@@ -0,0 +1,954 @@
+//
+// basic_datagram_socket_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_BASIC_DATAGRAM_SOCKET_EXT_HPP
+#define BOOST_ASIO_BASIC_DATAGRAM_SOCKET_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <iostream>
+
+#include <boost/asio/detail/config.hpp>
+#include <cstddef>
+#include <boost/asio/basic_socket.hpp>
+#include <boost/asio/datagram_socket_service_ext.hpp>
+#include <boost/asio/detail/handler_type_requirements_ext.hpp>
+#include <boost/asio/detail/throw_error.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+#include <boost/asio/error.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+
+/// Provides datagram-oriented socket functionality.
+/**
+ * The basic_datagram_socket class template provides asynchronous and blocking
+ * datagram-oriented socket functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Protocol,
+ typename DatagramSocketService = datagram_socket_service_ext<Protocol> >
+class basic_datagram_socket_ext
+ : public basic_socket<Protocol, DatagramSocketService>
+{
+public:
+ /// (Deprecated: Use native_handle_type.) The native representation of a
+ /// socket.
+ typedef typename DatagramSocketService::native_handle_type native_type;
+
+ /// The native representation of a socket.
+ typedef typename DatagramSocketService::native_handle_type native_handle_type;
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ /// Construct a basic_datagram_socket without opening it.
+ /**
+ * This constructor creates a datagram socket without opening it. The open()
+ * function must be called before data can be sent or received on the socket.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ */
+ explicit basic_datagram_socket_ext(boost::asio::io_service& io_service)
+ : basic_socket<Protocol, DatagramSocketService>(io_service)
+ {
+ }
+
+ /// Construct and open a basic_datagram_socket.
+ /**
+ * This constructor creates and opens a datagram socket.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_datagram_socket_ext(boost::asio::io_service& io_service,
+ const protocol_type& protocol)
+ : basic_socket<Protocol, DatagramSocketService>(io_service, protocol)
+ {
+ }
+
+ /// Construct a basic_datagram_socket, opening it and binding it to the given
+ /// local endpoint.
+ /**
+ * This constructor creates a datagram socket and automatically opens it bound
+ * to the specified endpoint on the local machine. The protocol used is the
+ * protocol associated with the given endpoint.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the datagram
+ * socket will be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_datagram_socket_ext(boost::asio::io_service& io_service,
+ const endpoint_type& endpoint)
+ : basic_socket<Protocol, DatagramSocketService>(io_service, endpoint)
+ {
+ }
+
+ /// Construct a basic_datagram_socket on an existing native socket.
+ /**
+ * This constructor creates a datagram socket object to hold an existing
+ * native socket.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket The new underlying socket implementation.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_datagram_socket_ext(boost::asio::io_service& io_service,
+ const protocol_type& protocol, const native_handle_type& native_socket)
+ : basic_socket<Protocol, DatagramSocketService>(
+ io_service, protocol, native_socket)
+ {
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Move-construct a basic_datagram_socket from another.
+ /**
+ * This constructor moves a datagram socket from one object to another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(io_service&) constructor.
+ */
+ basic_datagram_socket_ext(basic_datagram_socket_ext&& other)
+ : basic_socket<Protocol, DatagramSocketService>(
+ BOOST_ASIO_MOVE_CAST(basic_datagram_socket_ext)(other))
+ {
+ }
+
+ /// Move-assign a basic_datagram_socket from another.
+ /**
+ * This assignment operator moves a datagram socket from one object to
+ * another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(io_service&) constructor.
+ */
+ basic_datagram_socket_ext& operator=(basic_datagram_socket_ext&& other)
+ {
+ basic_socket<Protocol, DatagramSocketService>::operator=(
+ BOOST_ASIO_MOVE_CAST(basic_datagram_socket_ext)(other));
+ return *this;
+ }
+
+ /// Move-construct a basic_datagram_socket from a socket of another protocol
+ /// type.
+ /**
+ * This constructor moves a datagram socket from one object to another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(io_service&) constructor.
+ */
+ template <typename Protocol1, typename DatagramSocketService1>
+ basic_datagram_socket_ext(
+ basic_datagram_socket_ext<Protocol1, DatagramSocketService1>&& other,
+ typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
+ : basic_socket<Protocol, DatagramSocketService>(
+ BOOST_ASIO_MOVE_CAST2(basic_datagram_socket_ext<
+ Protocol1, DatagramSocketService1>)(other))
+ {
+ }
+
+ /// Move-assign a basic_datagram_socket from a socket of another protocol
+ /// type.
+ /**
+ * This assignment operator moves a datagram socket from one object to
+ * another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(io_service&) constructor.
+ */
+ template <typename Protocol1, typename DatagramSocketService1>
+ typename enable_if<is_convertible<Protocol1, Protocol>::value,
+ basic_datagram_socket_ext>::type& operator=(
+ basic_datagram_socket_ext<Protocol1, DatagramSocketService1>&& other)
+ {
+ basic_socket<Protocol, DatagramSocketService>::operator=(
+ BOOST_ASIO_MOVE_CAST2(basic_datagram_socket_ext<
+ Protocol1, DatagramSocketService1>)(other));
+ return *this;
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One ore more data buffers to be sent on the socket.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code socket.send(boost::asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().send(
+ this->get_implementation(), buffers, 0, ec);
+ boost::asio::detail::throw_error(ec, "send");
+ return s;
+ }
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One ore more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().send(
+ this->get_implementation(), buffers, flags, ec);
+ boost::asio::detail::throw_error(ec, "send");
+ return s;
+ }
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return this->get_service().send(
+ this->get_implementation(), buffers, flags, ec);
+ }
+
+ /// Start an asynchronous send on a connected socket.
+ /**
+ * This function is used to asynchronously send data on the datagram socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @note The async_send operation can only be used with a connected socket.
+ * Use the async_send_to function to send data on an unconnected datagram
+ * socket.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_send(boost::asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send(const ConstBufferSequence& buffers,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a WriteHandler.
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ return this->get_service().async_send(this->get_implementation(),
+ buffers, 0, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+ }
+
+ /// Start an asynchronous send on a connected socket.
+ /**
+ * This function is used to asynchronously send data on the datagram socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @note The async_send operation can only be used with a connected socket.
+ * Use the async_send_to function to send data on an unconnected datagram
+ * socket.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a WriteHandler.
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ return this->get_service().async_send(this->get_implementation(),
+ buffers, flags, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * boost::asio::ip::udp::endpoint destination(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.send_to(boost::asio::buffer(data, size), destination);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().send_to(
+ this->get_implementation(), buffers, destination, 0, ec);
+ boost::asio::detail::throw_error(ec, "send_to");
+ return s;
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().send_to(
+ this->get_implementation(), buffers, destination, flags, ec);
+ boost::asio::detail::throw_error(ec, "send_to");
+ return s;
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes sent.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ return this->get_service().send_to(this->get_implementation(),
+ buffers, destination, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send a datagram to the specified
+ * remote endpoint. The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ * Copies will be made of the endpoint as required.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * boost::asio::ip::udp::endpoint destination(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.async_send_to(
+ * boost::asio::buffer(data, size), destination, handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a WriteHandler.
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ return this->get_service().async_send_to(
+ this->get_implementation(), buffers, destination, 0,
+ BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send a datagram to the specified
+ * remote endpoint. The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ * Copies will be made of the endpoint as required.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a WriteHandler.
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ return this->get_service().async_send_to(
+ this->get_implementation(), buffers, destination, flags,
+ BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code socket.receive(boost::asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().receive(
+ this->get_implementation(), buffers, 0, ec);
+ boost::asio::detail::throw_error(ec, "receive");
+ return s;
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().receive(
+ this->get_implementation(), buffers, flags, ec);
+ boost::asio::detail::throw_error(ec, "receive");
+ return s;
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes received.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return this->get_service().receive(
+ this->get_implementation(), buffers, flags, ec);
+ }
+
+ /// Start an asynchronous receive on a connected socket.
+ /**
+ * This function is used to asynchronously receive data from the datagram
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @note The async_receive operation can only be used with a connected socket.
+ * Use the async_receive_from function to receive data on an unconnected
+ * datagram socket.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.async_receive(boost::asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t))
+ async_receive(const MutableBufferSequence& buffers,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a ReadHandler.
+ BOOST_ASIO_READ_HANDLER_CHECK_EXT(ReadHandler, handler) type_check;
+
+ return this->get_service().async_receive(this->get_implementation(),
+ buffers, 0, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+ }
+
+ /// Start an asynchronous receive on a connected socket.
+ /**
+ * This function is used to asynchronously receive data from the datagram
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @note The async_receive operation can only be used with a connected socket.
+ * Use the async_receive_from function to receive data on an unconnected
+ * datagram socket.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t))
+ async_receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a ReadHandler.
+ BOOST_ASIO_READ_HANDLER_CHECK_EXT(ReadHandler, handler) type_check;
+
+ return this->get_service().async_receive(this->get_implementation(),
+ buffers, flags, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * boost::asio::ip::udp::endpoint sender_endpoint;
+ * socket.receive_from(
+ * boost::asio::buffer(data, size), sender_endpoint);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().receive_from(
+ this->get_implementation(), buffers, sender_endpoint, 0, ec);
+ boost::asio::detail::throw_error(ec, "receive_from");
+ return s;
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().receive_from(
+ this->get_implementation(), buffers, sender_endpoint, flags, ec);
+ boost::asio::detail::throw_error(ec, "receive_from");
+ return s;
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes received.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ return this->get_service().receive_from(this->get_implementation(),
+ buffers, sender_endpoint, flags, ec);
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive a datagram. The function
+ * call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram. Ownership of the sender_endpoint object
+ * is retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code socket.async_receive_from(
+ * boost::asio::buffer(data, size), sender_endpoint, handler); @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address))
+ async_receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a ReadHandler.
+ BOOST_ASIO_READ_HANDLER_CHECK_EXT(ReadHandler, handler) type_check;
+
+ return this->get_service().async_receive_from(
+ this->get_implementation(), buffers, sender_endpoint, 0,
+ BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive a datagram. The function
+ * call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram. Ownership of the sender_endpoint object
+ * is retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address))
+ async_receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a ReadHandler.
+ BOOST_ASIO_READ_HANDLER_CHECK_EXT(ReadHandler, handler) type_check;
+
+ return this->get_service().async_receive_from(
+ this->get_implementation(), buffers, sender_endpoint, flags,
+ BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+ }
+};
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_BASIC_DATAGRAM_SOCKET_HPP
diff --git a/implementation/helper/boost/asio/datagram_socket_service_ext.hpp b/implementation/helper/boost/asio/datagram_socket_service_ext.hpp
new file mode 100644
index 0000000..3ce03d8
--- /dev/null
+++ b/implementation/helper/boost/asio/datagram_socket_service_ext.hpp
@@ -0,0 +1,437 @@
+//
+// datagram_socket_service_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_EXT_ASIO_DATAGRAM_SOCKET_SERVICE_EXT_HPP
+#define BOOST_EXT_ASIO_DATAGRAM_SOCKET_SERVICE_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <iostream>
+
+#include <boost/asio/detail/config.hpp>
+#include <cstddef>
+#include <boost/asio/async_result.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+# include <boost/asio/detail/null_socket_service.hpp>
+#elif defined(BOOST_ASIO_HAS_IOCP)
+# include "detail/win_iocp_socket_service_ext.hpp"
+#else
+# include "detail/reactive_socket_service_ext.hpp"
+#endif
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+
+/// Default service implementation for a datagram socket.
+template <typename Protocol>
+class datagram_socket_service_ext
+#if defined(GENERATING_DOCUMENTATION)
+ : public boost::asio::io_service::service
+#else
+ : public boost::asio::detail::service_base<datagram_socket_service_ext<Protocol> >
+#endif
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The unique service identifier.
+ static boost::asio::io_service::id id;
+#endif
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+private:
+ // The type of the platform-specific implementation.
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+ typedef detail::null_socket_service<Protocol> service_impl_type;
+#elif defined(BOOST_ASIO_HAS_IOCP)
+ typedef detail::win_iocp_socket_service_ext<Protocol> service_impl_type;
+#else
+ typedef detail::reactive_socket_service_ext<Protocol> service_impl_type;
+#endif
+
+public:
+ /// The type of a datagram socket.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined implementation_type;
+#else
+ typedef typename service_impl_type::implementation_type implementation_type;
+#endif
+
+ /// (Deprecated: Use native_handle_type.) The native socket type.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_type;
+#else
+ typedef typename service_impl_type::native_handle_type native_type;
+#endif
+
+ /// The native socket type.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_handle_type;
+#else
+ typedef typename service_impl_type::native_handle_type native_handle_type;
+#endif
+
+ /// Construct a new datagram socket service for the specified io_service.
+ explicit datagram_socket_service_ext(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ datagram_socket_service_ext<Protocol> >(io_service),
+ service_impl_(io_service)
+ {
+ }
+
+ /// Construct a new datagram socket implementation.
+ void construct(implementation_type& impl)
+ {
+ service_impl_.construct(impl);
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Move-construct a new datagram socket implementation.
+ void move_construct(implementation_type& impl,
+ implementation_type& other_impl)
+ {
+ service_impl_.move_construct(impl, other_impl);
+ }
+
+ /// Move-assign from another datagram socket implementation.
+ void move_assign(implementation_type& impl,
+ datagram_socket_service_ext& other_service,
+ implementation_type& other_impl)
+ {
+ service_impl_.move_assign(impl, other_service.service_impl_, other_impl);
+ }
+
+ /// Move-construct a new datagram socket implementation from another protocol
+ /// type.
+ template <typename Protocol1>
+ void converting_move_construct(implementation_type& impl,
+ typename datagram_socket_service_ext<
+ Protocol1>::implementation_type& other_impl,
+ typename enable_if<is_convertible<
+ Protocol1, Protocol>::value>::type* = 0)
+ {
+ service_impl_.template converting_move_construct<Protocol1>(
+ impl, other_impl);
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+ /// Destroy a datagram socket implementation.
+ void destroy(implementation_type& impl)
+ {
+ service_impl_.destroy(impl);
+ }
+
+ // Open a new datagram socket implementation.
+ boost::system::error_code open(implementation_type& impl,
+ const protocol_type& protocol, boost::system::error_code& ec)
+ {
+ if (protocol.type() == BOOST_ASIO_OS_DEF(SOCK_DGRAM))
+ service_impl_.open(impl, protocol, ec);
+ else
+ ec = boost::asio::error::invalid_argument;
+ return ec;
+ }
+
+ /// Assign an existing native socket to a datagram socket.
+ boost::system::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_handle_type& native_socket,
+ boost::system::error_code& ec)
+ {
+ return service_impl_.assign(impl, protocol, native_socket, ec);
+ }
+
+ /// Determine whether the socket is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return service_impl_.is_open(impl);
+ }
+
+ /// Close a datagram socket implementation.
+ boost::system::error_code close(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ return service_impl_.close(impl, ec);
+ }
+
+ /// (Deprecated: Use native_handle().) Get the native socket implementation.
+ native_type native(implementation_type& impl)
+ {
+ return service_impl_.native_handle(impl);
+ }
+
+ /// Get the native socket implementation.
+ native_handle_type native_handle(implementation_type& impl)
+ {
+ return service_impl_.native_handle(impl);
+ }
+
+ /// Cancel all asynchronous operations associated with the socket.
+ boost::system::error_code cancel(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ return service_impl_.cancel(impl, ec);
+ }
+
+ /// Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return service_impl_.at_mark(impl, ec);
+ }
+
+ /// Determine the number of bytes available for reading.
+ std::size_t available(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return service_impl_.available(impl, ec);
+ }
+
+ // Bind the datagram socket to the specified local endpoint.
+ boost::system::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, boost::system::error_code& ec)
+ {
+ return service_impl_.bind(impl, endpoint, ec);
+ }
+
+ /// Connect the datagram socket to the specified endpoint.
+ boost::system::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, boost::system::error_code& ec)
+ {
+ return service_impl_.connect(impl, peer_endpoint, ec);
+ }
+
+ /// Start an asynchronous connect.
+ template <typename ConnectHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
+ void (boost::system::error_code))
+ async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint,
+ BOOST_ASIO_MOVE_ARG(ConnectHandler) handler)
+ {
+ detail::async_result_init<
+ ConnectHandler, void (boost::system::error_code)> init(
+ BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler));
+
+ service_impl_.async_connect(impl, peer_endpoint, init.handler);
+
+ return init.result.get();
+ }
+
+ /// Set a socket option.
+ template <typename SettableSocketOption>
+ boost::system::error_code set_option(implementation_type& impl,
+ const SettableSocketOption& option, boost::system::error_code& ec)
+ {
+ return service_impl_.set_option(impl, option, ec);
+ }
+
+ /// Get a socket option.
+ template <typename GettableSocketOption>
+ boost::system::error_code get_option(const implementation_type& impl,
+ GettableSocketOption& option, boost::system::error_code& ec) const
+ {
+ return service_impl_.get_option(impl, option, ec);
+ }
+
+ /// Perform an IO control command on the socket.
+ template <typename IoControlCommand>
+ boost::system::error_code io_control(implementation_type& impl,
+ IoControlCommand& command, boost::system::error_code& ec)
+ {
+ return service_impl_.io_control(impl, command, ec);
+ }
+
+ /// Gets the non-blocking mode of the socket.
+ bool non_blocking(const implementation_type& impl) const
+ {
+ return service_impl_.non_blocking(impl);
+ }
+
+ /// Sets the non-blocking mode of the socket.
+ boost::system::error_code non_blocking(implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ return service_impl_.non_blocking(impl, mode, ec);
+ }
+
+ /// Gets the non-blocking mode of the native socket implementation.
+ bool native_non_blocking(const implementation_type& impl) const
+ {
+ return service_impl_.native_non_blocking(impl);
+ }
+
+ /// Sets the non-blocking mode of the native socket implementation.
+ boost::system::error_code native_non_blocking(implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ return service_impl_.native_non_blocking(impl, mode, ec);
+ }
+
+ /// Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return service_impl_.local_endpoint(impl, ec);
+ }
+
+ /// Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return service_impl_.remote_endpoint(impl, ec);
+ }
+
+ /// Disable sends or receives on the socket.
+ boost::system::error_code shutdown(implementation_type& impl,
+ socket_base::shutdown_type what, boost::system::error_code& ec)
+ {
+ return service_impl_.shutdown(impl, what, ec);
+ }
+
+ /// Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ std::size_t send(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return service_impl_.send(impl, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send(implementation_type& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ detail::async_result_init<
+ WriteHandler, void (boost::system::error_code, std::size_t)> init(
+ BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+
+ service_impl_.async_send(impl, buffers, flags, init.handler);
+
+ return init.result.get();
+ }
+
+ /// Send a datagram to the specified endpoint.
+ template <typename ConstBufferSequence>
+ std::size_t send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers, const endpoint_type& destination,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return service_impl_.send_to(impl, buffers, destination, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers, const endpoint_type& destination,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ detail::async_result_init<
+ WriteHandler, void (boost::system::error_code, std::size_t)> init(
+ BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+
+ service_impl_.async_send_to(impl, buffers,
+ destination, flags, init.handler);
+
+ return init.result.get();
+ }
+
+ /// Receive some data from the peer.
+ template <typename MutableBufferSequence>
+ std::size_t receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return service_impl_.receive(impl, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous receive.
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t))
+ async_receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ detail::async_result_init<
+ ReadHandler, void (boost::system::error_code, std::size_t)> init(
+ BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+
+ service_impl_.async_receive(impl, buffers, flags, init.handler);
+
+ return init.result.get();
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return service_impl_.receive_from(impl, buffers, sender_endpoint, flags,
+ ec);
+ }
+
+ /// Start an asynchronous receive that will get the endpoint of the sender.
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address))
+ async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ detail::async_result_init<
+ ReadHandler, void (boost::system::error_code, std::size_t)> init(
+ BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+
+ service_impl_.async_receive_from(impl, buffers,
+ sender_endpoint, flags, init.handler);
+
+ return init.result.get();
+ }
+
+private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
+ // The platform-specific implementation.
+ service_impl_type service_impl_;
+};
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DATAGRAM_SOCKET_SERVICE_HPP
diff --git a/implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp b/implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp
new file mode 100644
index 0000000..d81fb42
--- /dev/null
+++ b/implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp
@@ -0,0 +1,516 @@
+//
+// detail/handler_type_requirements_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_HPP
+#define BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+// Older versions of gcc have difficulty compiling the sizeof expressions where
+// we test the handler type requirements. We'll disable checking of handler type
+// requirements for those compilers, but otherwise enable it by default.
+#if !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+# if !defined(__GNUC__) || (__GNUC__ >= 4)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS 1
+# endif // !defined(__GNUC__) || (__GNUC__ >= 4)
+#endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+
+// With C++0x we can use a combination of enhanced SFINAE and static_assert to
+// generate better template error messages. As this technique is not yet widely
+// portable, we'll only enable it for tested compilers.
+#if !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1600)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // (_MSC_VER >= 1600)
+# endif // defined(BOOST_ASIO_MSVC)
+# if defined(__clang__)
+# if __has_feature(__cxx_static_assert__)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // __has_feature(cxx_static_assert)
+# endif // defined(__clang__)
+#endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+# include <boost/asio/handler_type.hpp>
+#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+// Newer gcc, clang need special treatment to suppress unused typedef warnings.
+#if defined(__clang__)
+# if defined(__apple_build_version__)
+# if (__clang_major__ >= 7)
+# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif // (__clang_major__ >= 7)
+# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \
+ || (__clang_major__ > 3)
+# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6))
+ // || (__clang_major__ > 3)
+#elif defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#endif // defined(__GNUC__)
+#if !defined(BOOST_ASIO_UNUSED_TYPEDEF)
+# define BOOST_ASIO_UNUSED_TYPEDEF
+#endif // !defined(BOOST_ASIO_UNUSED_TYPEDEF)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+# if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+template <typename Handler>
+auto zero_arg_handler_test(Handler h, void*)
+ -> decltype(
+ sizeof(Handler(static_cast<const Handler&>(h))),
+ ((h)()),
+ char(0));
+
+template <typename Handler>
+char (&zero_arg_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1>
+auto one_arg_handler_test(Handler h, Arg1* a1)
+ -> decltype(
+ sizeof(Handler(static_cast<const Handler&>(h))),
+ ((h)(*a1)),
+ char(0));
+
+template <typename Handler>
+char (&one_arg_handler_test(Handler h, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2>
+auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2)
+ -> decltype(
+ sizeof(Handler(static_cast<const Handler&>(h))),
+ ((h)(*a1, *a2)),
+ char(0));
+
+template <typename Handler>
+char (&two_arg_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+auto three_arg_handler_test(Handler h, Arg1* a1, Arg2* a2, Arg3* a3)
+ -> decltype(
+ sizeof(Handler(static_cast<const Handler&>(h))),
+ ((h)(*a1, *a2, *a3)),
+ char(0));
+
+template <typename Handler>
+char (&three_arg_handler_test(Handler, ...))[2];
+
+# define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \
+ static_assert(expr, msg);
+
+# else // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+# define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg)
+
+# endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+template <typename T> T& lvref();
+template <typename T> T& lvref(T);
+template <typename T> const T& clvref();
+template <typename T> const T& clvref(T);
+template <typename T> char argbyv(T);
+
+#if 0
+template <int>
+struct handler_type_requirements
+{
+};
+#endif
+
+#define BOOST_ASIO_COMPLETION_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void()) asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::zero_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), 0)) == 1, \
+ "CompletionHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()(), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_READ_HANDLER_CHECK_EXT( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t, \
+ boost::asio::ip::address)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::three_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const std::size_t*>(0), \
+ static_cast<const boost::asio::ip::address*>(0))) == 1, \
+ "ReadHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>(), \
+ boost::asio::detail::lvref<const boost::asio::ip::address>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+
+#define BOOST_ASIO_WRITE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const std::size_t*>(0))) == 1, \
+ "WriteHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::one_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0))) == 1, \
+ "AcceptHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::one_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0))) == 1, \
+ "ConnectHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, iter_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const iter_type*>(0))) == 1, \
+ "ComposedConnectHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const iter_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, iter_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const iter_type*>(0))) == 1, \
+ "ResolveHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const iter_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WAIT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::one_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0))) == 1, \
+ "WaitHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SIGNAL_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, int)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const int*>(0))) == 1, \
+ "SignalHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const int>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::one_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0))) == 1, \
+ "HandshakeHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const std::size_t*>(0))) == 1, \
+ "BufferedHandshakeHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SHUTDOWN_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::one_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0))) == 1, \
+ "ShutdownHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#else // !defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#define BOOST_ASIO_COMPLETION_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_READ_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WRITE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WAIT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SIGNAL_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SHUTDOWN_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#endif // !defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp b/implementation/helper/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp
new file mode 100644
index 0000000..fe50185
--- /dev/null
+++ b/implementation/helper/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp
@@ -0,0 +1,270 @@
+//
+// detail/reactive_socket_service_base_ext.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_IPP
+#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP) \
+ && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#include <boost/asio/detail/reactive_socket_service_base_ext.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+reactive_socket_service_base_ext::reactive_socket_service_base_ext(
+ boost::asio::io_service& io_service)
+ : reactor_(use_service<reactor>(io_service))
+{
+ reactor_.init_task();
+}
+
+void reactive_socket_service_base_ext::shutdown_service()
+{
+}
+
+void reactive_socket_service_base_ext::construct(
+ reactive_socket_service_base_ext::base_implementation_type& impl)
+{
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+}
+
+void reactive_socket_service_base_ext::base_move_construct(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactive_socket_service_base_ext::base_implementation_type& other_impl)
+{
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = invalid_socket;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ reactor_.move_descriptor(impl.socket_,
+ impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_socket_service_base_ext::base_move_assign(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactive_socket_service_base_ext& other_service,
+ reactive_socket_service_base_ext::base_implementation_type& other_impl)
+{
+ destroy(impl);
+
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = invalid_socket;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ other_service.reactor_.move_descriptor(impl.socket_,
+ impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_socket_service_base_ext::destroy(
+ reactive_socket_service_base_ext::base_implementation_type& impl)
+{
+ if (impl.socket_ != invalid_socket)
+ {
+ BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close"));
+
+ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
+ (impl.state_ & socket_ops::possible_dup) == 0);
+
+ boost::system::error_code ignored_ec;
+ socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+ }
+}
+
+boost::system::error_code reactive_socket_service_base_ext::close(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close"));
+
+ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
+ (impl.state_ & socket_ops::possible_dup) == 0);
+ }
+
+ socket_ops::close(impl.socket_, impl.state_, false, ec);
+
+ // The descriptor is closed by the OS even if close() returns an error.
+ //
+ // (Actually, POSIX says the state of the descriptor is unspecified. On
+ // Linux the descriptor is apparently closed anyway; e.g. see
+ // http://lkml.org/lkml/2005/9/10/129
+ // We'll just have to assume that other OSes follow the same behaviour. The
+ // known exception is when Windows's closesocket() function fails with
+ // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close().
+ construct(impl);
+
+ return ec;
+}
+
+boost::system::error_code reactive_socket_service_base_ext::cancel(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ boost::system::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "cancel"));
+
+ reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
+ ec = boost::system::error_code();
+ return ec;
+}
+
+boost::system::error_code reactive_socket_service_base_ext::do_open(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ int af, int type, int protocol, boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ socket_holder sock(socket_ops::socket(af, type, protocol, ec));
+ if (sock.get() == invalid_socket)
+ return ec;
+
+ if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = sock.release();
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ ec = boost::system::error_code();
+ return ec;
+}
+
+boost::system::error_code reactive_socket_service_base_ext::do_assign(
+ reactive_socket_service_base_ext::base_implementation_type& impl, int type,
+ const reactive_socket_service_base_ext::native_handle_type& native_socket,
+ boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(
+ native_socket, impl.reactor_data_))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = native_socket;
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ impl.state_ |= socket_ops::possible_dup;
+ ec = boost::system::error_code();
+ return ec;
+}
+
+void reactive_socket_service_base_ext::start_op(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ int op_type, reactor_op* op, bool is_continuation,
+ bool is_non_blocking, bool noop)
+{
+ if (!noop)
+ {
+ if ((impl.state_ & socket_ops::non_blocking)
+ || socket_ops::set_internal_non_blocking(
+ impl.socket_, impl.state_, true, op->ec_))
+ {
+ reactor_.start_op(op_type, impl.socket_,
+ impl.reactor_data_, op, is_continuation, is_non_blocking);
+ return;
+ }
+ }
+
+ reactor_.post_immediate_completion(op, is_continuation);
+}
+
+void reactive_socket_service_base_ext::start_accept_op(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactor_op* op, bool is_continuation, bool peer_is_open)
+{
+ if (!peer_is_open)
+ start_op(impl, reactor::read_op, op, true, is_continuation, false);
+ else
+ {
+ op->ec_ = boost::asio::error::already_open;
+ reactor_.post_immediate_completion(op, is_continuation);
+ }
+}
+
+void reactive_socket_service_base_ext::start_connect_op(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactor_op* op, bool is_continuation,
+ const socket_addr_type* addr, size_t addrlen)
+{
+ if ((impl.state_ & socket_ops::non_blocking)
+ || socket_ops::set_internal_non_blocking(
+ impl.socket_, impl.state_, true, op->ec_))
+ {
+ if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
+ {
+ if (op->ec_ == boost::asio::error::in_progress
+ || op->ec_ == boost::asio::error::would_block)
+ {
+ op->ec_ = boost::system::error_code();
+ reactor_.start_op(reactor::connect_op, impl.socket_,
+ impl.reactor_data_, op, is_continuation, false);
+ return;
+ }
+ }
+ }
+
+ reactor_.post_immediate_completion(op, is_continuation);
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_IPP
diff --git a/implementation/helper/boost/asio/detail/impl/socket_ops_ext.ipp b/implementation/helper/boost/asio/detail/impl/socket_ops_ext.ipp
new file mode 100644
index 0000000..cf80670
--- /dev/null
+++ b/implementation/helper/boost/asio/detail/impl/socket_ops_ext.ipp
@@ -0,0 +1,210 @@
+//
+// detail/impl/socket_ops_ext.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_IPP
+#define BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_IPP
+
+#include <boost/asio/detail/impl/socket_ops.ipp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+signed_size_type recvfrom(socket_type s, buf* bufs, size_t count,
+ int flags, socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec, boost::asio::ip::address& da)
+{
+ clear_last_error();
+#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+ GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
+ LPFN_WSARECVMSG WSARecvMsg;
+ DWORD NumberOfBytes;
+
+ error_wrapper(WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID,
+ &WSARecvMsg, sizeof WSARecvMsg,
+ &NumberOfBytes, NULL, NULL), ec);
+ if (ec.value() == SOCKET_ERROR) {
+ WSARecvMsg = NULL;
+ return 0;
+ }
+
+ WSABUF wsaBuf;
+ WSAMSG msg;
+ char controlBuffer[1024];
+ msg.name = addr;
+ msg.namelen = *addrlen;
+ wsaBuf.buf = bufs->buf;
+ wsaBuf.len = bufs->len;
+ msg.lpBuffers = &wsaBuf;
+ msg.dwBufferCount = count;
+ msg.Control.len = sizeof controlBuffer;
+ msg.Control.buf = controlBuffer;
+ msg.dwFlags = flags;
+
+ DWORD dwNumberOfBytesRecvd;
+ signed_size_type result = error_wrapper(WSARecvMsg(s, &msg, &dwNumberOfBytesRecvd, NULL, NULL), ec);
+
+ if (result >= 0) {
+ ec = boost::system::error_code();
+
+ // Find destination address
+ for (LPWSACMSGHDR cmsg = WSA_CMSG_FIRSTHDR(&msg);
+ cmsg != NULL;
+ cmsg = WSA_CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level != IPPROTO_IP || cmsg->cmsg_type != IP_PKTINFO)
+ continue;
+
+ struct in_pktinfo *pi = (struct in_pktinfo *) WSA_CMSG_DATA(cmsg);
+ if (pi)
+ {
+ da = boost::asio::ip::address_v4(ntohl(pi->ipi_addr.s_addr));
+ }
+ }
+ } else {
+ dwNumberOfBytesRecvd = -1;
+ }
+ return dwNumberOfBytesRecvd;
+#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+ char cmbuf[0x100];
+ msghdr msg = msghdr();
+ init_msghdr_msg_name(msg.msg_name, addr);
+ msg.msg_namelen = static_cast<int>(*addrlen);
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = static_cast<int>(count);
+ msg.msg_control = cmbuf;
+ msg.msg_controllen = sizeof(cmbuf);
+ signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec);
+ *addrlen = msg.msg_namelen;
+ if (result >= 0) {
+ ec = boost::system::error_code();
+
+ // Find destination address
+ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level != IPPROTO_IP || cmsg->cmsg_type != IP_PKTINFO)
+ continue;
+
+ struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cmsg);
+ if (pi)
+ {
+ da = boost::asio::ip::address_v4(ntohl(pi->ipi_addr.s_addr));
+ }
+ }
+ }
+ return result;
+#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,
+ size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec, boost::asio::ip::address& da)
+{
+ if (s == invalid_socket)
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ signed_size_type bytes = socket_ops::recvfrom(
+ s, bufs, count, flags, addr, addrlen, ec, da);
+
+ // Check if operation succeeded.
+ if (bytes >= 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(s, 0, ec) < 0)
+ return 0;
+ }
+}
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ boost::system::error_code& ec, boost::asio::ip::address& da)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (cancel_token.expired())
+ ec = boost::asio::error::operation_aborted;
+ else
+ ec = boost::asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
+}
+
+#else // defined(BOOST_ASIO_HAS_IOCP)
+
+bool non_blocking_recvfrom(socket_type s,
+ buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec, size_t& bytes_transferred, boost::asio::ip::address& da)
+{
+ for (;;)
+ {
+ // Read some data.
+ signed_size_type bytes = socket_ops::recvfrom(
+ s, bufs, count, flags, addr, addrlen, ec, da);
+
+ // Retry operation if interrupted by signal.
+ if (ec == boost::asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = boost::system::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_IPP
diff --git a/implementation/helper/boost/asio/detail/reactive_socket_recv_op_ext.hpp b/implementation/helper/boost/asio/detail/reactive_socket_recv_op_ext.hpp
new file mode 100644
index 0000000..c4f4547
--- /dev/null
+++ b/implementation/helper/boost/asio/detail/reactive_socket_recv_op_ext.hpp
@@ -0,0 +1,126 @@
+//
+// detail/reactive_socket_recv_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/reactor_op_ext.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recv_op_base_ext : public reactor_op_ext
+{
+public:
+ reactive_socket_recv_op_base_ext(socket_type socket,
+ socket_ops::state_type state, const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op_ext(&reactive_socket_recv_op_base_ext::do_perform, complete_func),
+ socket_(socket),
+ state_(state),
+ buffers_(buffers),
+ flags_(flags)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_recv_op_base_ext* o(
+ static_cast<reactive_socket_recv_op_base_ext*>(base));
+
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ return socket_ops::non_blocking_recv(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ (o->state_ & socket_ops::stream_oriented) != 0,
+ o->ec_, o->bytes_transferred_);
+ }
+
+private:
+ socket_type socket_;
+ socket_ops::state_type state_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler>
+class reactive_socket_recv_op_ext :
+ public reactive_socket_recv_op_base_ext<MutableBufferSequence>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op_ext);
+
+ reactive_socket_recv_op_ext(socket_type socket,
+ socket_ops::state_type state, const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ : reactive_socket_recv_op_base_ext<MutableBufferSequence>(socket, state,
+ buffers, flags, &reactive_socket_recv_op_ext::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recv_op_ext* o(static_cast<reactive_socket_recv_op_ext*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((o));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder3<Handler, boost::system::error_code, std::size_t, boost::asio::ip::address>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->da_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3_));
+ boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp b/implementation/helper/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp
new file mode 100644
index 0000000..afa6a66
--- /dev/null
+++ b/implementation/helper/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp
@@ -0,0 +1,136 @@
+//
+// detail/reactive_socket_recvfrom_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/reactor_op_ext.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint>
+class reactive_socket_recvfrom_op_base_ext : public reactor_op_ext
+{
+public:
+ reactive_socket_recvfrom_op_base_ext(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op_ext(&reactive_socket_recvfrom_op_base_ext::do_perform, complete_func),
+ socket_(socket),
+ protocol_type_(protocol_type),
+ buffers_(buffers),
+ sender_endpoint_(endpoint),
+ flags_(flags)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_recvfrom_op_base_ext* o(
+ static_cast<reactive_socket_recvfrom_op_base_ext*>(base));
+
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ std::size_t addr_len = o->sender_endpoint_.capacity();
+ bool result = socket_ops::non_blocking_recvfrom(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ o->sender_endpoint_.data(), &addr_len,
+ o->ec_, o->bytes_transferred_, o->da_);
+
+ if (result && !o->ec_)
+ o->sender_endpoint_.resize(addr_len);
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ int protocol_type_;
+ MutableBufferSequence buffers_;
+ Endpoint& sender_endpoint_;
+ socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Endpoint, typename Handler>
+class reactive_socket_recvfrom_op_ext :
+ public reactive_socket_recvfrom_op_base_ext<MutableBufferSequence, Endpoint>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op_ext);
+
+ reactive_socket_recvfrom_op_ext(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, Handler& handler)
+ : reactive_socket_recvfrom_op_base_ext<MutableBufferSequence, Endpoint>(
+ socket, protocol_type, buffers, endpoint, flags,
+ &reactive_socket_recvfrom_op_ext::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recvfrom_op_ext* o(
+ static_cast<reactive_socket_recvfrom_op_ext*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((o));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder3<Handler, boost::system::error_code, std::size_t, boost::asio::ip::address>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->da_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3_));
+ boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp b/implementation/helper/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp
new file mode 100644
index 0000000..ba0a714
--- /dev/null
+++ b/implementation/helper/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp
@@ -0,0 +1,128 @@
+//
+// detail/reactive_socket_recvmsg_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/reactor_op_ext.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+#include <boost/asio/socket_base.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recvmsg_op_base_ext : public reactor_op_ext
+{
+public:
+ reactive_socket_recvmsg_op_base_ext(socket_type socket,
+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, func_type complete_func)
+ : reactor_op_ext(&reactive_socket_recvmsg_op_base_ext::do_perform, complete_func),
+ socket_(socket),
+ buffers_(buffers),
+ in_flags_(in_flags),
+ out_flags_(out_flags)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_recvmsg_op_base_ext* o(
+ static_cast<reactive_socket_recvmsg_op_base_ext*>(base));
+
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ return socket_ops::non_blocking_recvmsg(o->socket_,
+ bufs.buffers(), bufs.count(),
+ o->in_flags_, o->out_flags_,
+ o->ec_, o->bytes_transferred_);
+ }
+
+private:
+ socket_type socket_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags in_flags_;
+ socket_base::message_flags& out_flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler>
+class reactive_socket_recvmsg_op_ext :
+ public reactive_socket_recvmsg_op_base_ext<MutableBufferSequence>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op_ext);
+
+ reactive_socket_recvmsg_op_ext(socket_type socket,
+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler)
+ : reactive_socket_recvmsg_op_base_ext<MutableBufferSequence>(socket, buffers,
+ in_flags, out_flags, &reactive_socket_recvmsg_op_ext::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recvmsg_op_ext* o(
+ static_cast<reactive_socket_recvmsg_op_ext*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((o));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder3<Handler, boost::system::error_code, std::size_t, boost::asio::ip::address>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->da_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3_));
+ boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/reactive_socket_service_base_ext.hpp b/implementation/helper/boost/asio/detail/reactive_socket_service_base_ext.hpp
new file mode 100644
index 0000000..cd0b19f
--- /dev/null
+++ b/implementation/helper/boost/asio/detail/reactive_socket_service_base_ext.hpp
@@ -0,0 +1,455 @@
+//
+// detail/reactive_socket_service_base_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <iostream>
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP) \
+ && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/socket_base.hpp>
+#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/reactive_null_buffers_op.hpp>
+#include <boost/asio/detail/reactive_socket_recv_op_ext.hpp>
+#include <boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp>
+#include <boost/asio/detail/reactive_socket_send_op.hpp>
+#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
+#include <boost/asio/detail/socket_holder.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class reactive_socket_service_base_ext
+{
+public:
+ // The native type of a socket.
+ typedef socket_type native_handle_type;
+
+ // The implementation type of the socket.
+ struct base_implementation_type
+ {
+ // The native socket representation.
+ socket_type socket_;
+
+ // The current state of the socket.
+ socket_ops::state_type state_;
+
+ // Per-descriptor data used by the reactor.
+ reactor::per_descriptor_data reactor_data_;
+ };
+
+ // Constructor.
+ BOOST_ASIO_DECL reactive_socket_service_base_ext(
+ boost::asio::io_service& io_service);
+
+ // Destroy all user-defined handler objects owned by the service.
+ BOOST_ASIO_DECL void shutdown_service();
+
+ // Construct a new socket implementation.
+ BOOST_ASIO_DECL void construct(base_implementation_type& impl);
+
+ // Move-construct a new socket implementation.
+ BOOST_ASIO_DECL void base_move_construct(base_implementation_type& impl,
+ base_implementation_type& other_impl);
+
+ // Move-assign from another socket implementation.
+ BOOST_ASIO_DECL void base_move_assign(base_implementation_type& impl,
+ reactive_socket_service_base_ext& other_service,
+ base_implementation_type& other_impl);
+
+ // Destroy a socket implementation.
+ BOOST_ASIO_DECL void destroy(base_implementation_type& impl);
+
+ // Determine whether the socket is open.
+ bool is_open(const base_implementation_type& impl) const
+ {
+ return impl.socket_ != invalid_socket;
+ }
+
+ // Destroy a socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code close(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
+ // Get the native socket representation.
+ native_handle_type native_handle(base_implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Cancel all operations associated with the socket.
+ BOOST_ASIO_DECL boost::system::error_code cancel(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const base_implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return socket_ops::sockatmark(impl.socket_, ec);
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const base_implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return socket_ops::available(impl.socket_, ec);
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ boost::system::error_code listen(base_implementation_type& impl,
+ int backlog, boost::system::error_code& ec)
+ {
+ socket_ops::listen(impl.socket_, backlog, ec);
+ return ec;
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ boost::system::error_code io_control(base_implementation_type& impl,
+ IO_Control_Command& command, boost::system::error_code& ec)
+ {
+ socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the socket.
+ bool non_blocking(const base_implementation_type& impl) const
+ {
+ return (impl.state_ & socket_ops::user_set_non_blocking) != 0;
+ }
+
+ // Sets the non-blocking mode of the socket.
+ boost::system::error_code non_blocking(base_implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the native socket implementation.
+ bool native_non_blocking(const base_implementation_type& impl) const
+ {
+ return (impl.state_ & socket_ops::internal_non_blocking) != 0;
+ }
+
+ // Sets the non-blocking mode of the native socket implementation.
+ boost::system::error_code native_non_blocking(base_implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);
+ return ec;
+ }
+
+ // Disable sends or receives on the socket.
+ boost::system::error_code shutdown(base_implementation_type& impl,
+ socket_base::shutdown_type what, boost::system::error_code& ec)
+ {
+ socket_ops::shutdown(impl.socket_, what, ec);
+ return ec;
+ }
+
+ // Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ size_t send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_send(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, impl.state_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_send_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, buffers, flags, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, true,
+ ((impl.state_ & socket_ops::stream_oriented)
+ && buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence>::all_empty(buffers)));
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_send(null_buffers)"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_recv(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recv_op_ext<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation,
+ (flags & socket_base::message_out_of_band) == 0,
+ ((impl.state_ & socket_ops::stream_oriented)
+ && buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(buffers)));
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_receive(null_buffers)"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive some data with associated flags. Returns the number of bytes
+ // received.
+ template <typename MutableBufferSequence>
+ size_t receive_with_flags(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_recvmsg(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), in_flags, out_flags, ec);
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_with_flags(base_implementation_type& impl,
+ const null_buffers&, socket_base::message_flags,
+ socket_base::message_flags& out_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, ec);
+
+ // Clear out_flags, since we cannot give it any other sensible value when
+ // performing a null_buffers operation.
+ out_flags = 0;
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive_with_flags(base_implementation_type& impl,
+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recvmsg_op_ext<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, buffers, in_flags, out_flags, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_receive_with_flags"));
+
+ start_op(impl,
+ (in_flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation,
+ (in_flags & socket_base::message_out_of_band) == 0, false);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive_with_flags(base_implementation_type& impl,
+ const null_buffers&, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl,
+ "async_receive_with_flags(null_buffers)"));
+
+ // Clear out_flags, since we cannot give it any other sensible value when
+ // performing a null_buffers operation.
+ out_flags = 0;
+
+ start_op(impl,
+ (in_flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+protected:
+ // Open a new socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code do_open(
+ base_implementation_type& impl, int af,
+ int type, int protocol, boost::system::error_code& ec);
+
+ // Assign a native socket to a socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code do_assign(
+ base_implementation_type& impl, int type,
+ const native_handle_type& native_socket, boost::system::error_code& ec);
+
+ // Start the asynchronous read or write operation.
+ BOOST_ASIO_DECL void start_op(base_implementation_type& impl, int op_type,
+ reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);
+
+ // Start the asynchronous accept operation.
+ BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl,
+ reactor_op* op, bool is_continuation, bool peer_is_open);
+
+ // Start the asynchronous connect operation.
+ BOOST_ASIO_DECL void start_connect_op(base_implementation_type& impl,
+ reactor_op* op, bool is_continuation,
+ const socket_addr_type* addr, size_t addrlen);
+
+ // The selector that performs event demultiplexing for the service.
+ reactor& reactor_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_ASIO_HEADER_ONLY)
+# include <boost/asio/detail/impl/reactive_socket_service_base_ext.ipp>
+#endif // defined(BOOST_ASIO_HEADER_ONLY)
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/reactive_socket_service_ext.hpp b/implementation/helper/boost/asio/detail/reactive_socket_service_ext.hpp
new file mode 100644
index 0000000..a13e5c8
--- /dev/null
+++ b/implementation/helper/boost/asio/detail/reactive_socket_service_ext.hpp
@@ -0,0 +1,462 @@
+//
+// detail/reactive_socket_service_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <iostream>
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/socket_base.hpp>
+#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/reactive_null_buffers_op.hpp>
+#include <boost/asio/detail/reactive_socket_accept_op.hpp>
+#include <boost/asio/detail/reactive_socket_connect_op.hpp>
+#include <boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp>
+#include <boost/asio/detail/reactive_socket_sendto_op.hpp>
+#include <boost/asio/detail/reactive_socket_service_base_ext.hpp>
+#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
+#include <boost/asio/detail/socket_holder.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class reactive_socket_service_ext :
+ public reactive_socket_service_base_ext
+{
+public:
+ // The protocol type.
+ typedef Protocol protocol_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The native type of a socket.
+ typedef socket_type native_handle_type;
+
+ // The implementation type of the socket.
+ struct implementation_type :
+ reactive_socket_service_base_ext::base_implementation_type
+ {
+ // Default constructor.
+ implementation_type()
+ : protocol_(endpoint_type().protocol())
+ {
+ }
+
+ // The protocol associated with the socket.
+ protocol_type protocol_;
+ };
+
+ // Constructor.
+ reactive_socket_service_ext(boost::asio::io_service& io_service)
+ : reactive_socket_service_base_ext(io_service)
+ {
+ }
+
+ // Move-construct a new socket implementation.
+ void move_construct(implementation_type& impl,
+ implementation_type& other_impl)
+ {
+ this->base_move_construct(impl, other_impl);
+
+ impl.protocol_ = other_impl.protocol_;
+ other_impl.protocol_ = endpoint_type().protocol();
+ }
+
+ // Move-assign from another socket implementation.
+ void move_assign(implementation_type& impl,
+ reactive_socket_service_base_ext& other_service,
+ implementation_type& other_impl)
+ {
+ this->base_move_assign(impl, other_service, other_impl);
+
+ impl.protocol_ = other_impl.protocol_;
+ other_impl.protocol_ = endpoint_type().protocol();
+ }
+
+ // Move-construct a new socket implementation from another protocol type.
+ template <typename Protocol1>
+ void converting_move_construct(implementation_type& impl,
+ typename reactive_socket_service_ext<
+ Protocol1>::implementation_type& other_impl)
+ {
+ this->base_move_construct(impl, other_impl);
+
+ impl.protocol_ = protocol_type(other_impl.protocol_);
+ other_impl.protocol_ = typename Protocol1::endpoint().protocol();
+ }
+
+ // Open a new socket implementation.
+ boost::system::error_code open(implementation_type& impl,
+ const protocol_type& protocol, boost::system::error_code& ec)
+ {
+ if (!do_open(impl, protocol.family(),
+ protocol.type(), protocol.protocol(), ec))
+ impl.protocol_ = protocol;
+ return ec;
+ }
+
+ // Assign a native socket to a socket implementation.
+ boost::system::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_handle_type& native_socket,
+ boost::system::error_code& ec)
+ {
+ if (!do_assign(impl, protocol.type(), native_socket, ec))
+ impl.protocol_ = protocol;
+ return ec;
+ }
+
+ // Get the native socket representation.
+ native_handle_type native_handle(implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Bind the socket to the specified local endpoint.
+ boost::system::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, boost::system::error_code& ec)
+ {
+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code set_option(implementation_type& impl,
+ const Option& option, boost::system::error_code& ec)
+ {
+ socket_ops::setsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), option.size(impl.protocol_), ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code get_option(const implementation_type& impl,
+ Option& option, boost::system::error_code& ec) const
+ {
+ std::size_t size = option.size(impl.protocol_);
+ socket_ops::getsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), &size, ec);
+ if (!ec)
+ option.resize(impl.protocol_, size);
+ return ec;
+ }
+
+ // Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getpeername(impl.socket_,
+ endpoint.data(), &addr_len, false, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Send a datagram to the specified endpoint. Returns the number of bytes
+ // sent.
+ template <typename ConstBufferSequence>
+ size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_sendto(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags,
+ destination.data(), destination.size(), ec);
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send_to(implementation_type& impl, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags,
+ boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, impl.state_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_sendto_op<ConstBufferSequence,
+ endpoint_type, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send_to"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, true, false);
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send_to(implementation_type& impl, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_send_to(null_buffers)"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive a datagram with the endpoint of the sender. Returns the number of
+ // bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ std::size_t addr_len = sender_endpoint.capacity();
+ std::size_t bytes_recvd = socket_ops::sync_recvfrom(
+ impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
+ flags, sender_endpoint.data(), &addr_len, ec);
+
+ if (!ec)
+ sender_endpoint.resize(addr_len);
+
+ return bytes_recvd;
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_from(implementation_type& impl, const null_buffers&,
+ endpoint_type& sender_endpoint, socket_base::message_flags,
+ boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, ec);
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received and
+ // the sender_endpoint object must both be valid for the lifetime of the
+ // asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recvfrom_op_ext<MutableBufferSequence,
+ endpoint_type, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ int protocol = impl.protocol_.type();
+ p.p = new (p.v) op(impl.socket_, protocol,
+ buffers, sender_endpoint, flags, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_receive_from"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, true, false);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive_from(implementation_type& impl,
+ const null_buffers&, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_receive_from(null_buffers)"));
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Accept a new connection.
+ template <typename Socket>
+ boost::system::error_code accept(implementation_type& impl,
+ Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec)
+ {
+ // We cannot accept a socket that is already open.
+ if (peer.is_open())
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
+ socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
+ impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
+ peer_endpoint ? &addr_len : 0, ec));
+
+ // On success, assign new connection to peer socket object.
+ if (new_socket.get() != invalid_socket)
+ {
+ if (peer_endpoint)
+ peer_endpoint->resize(addr_len);
+ if (!peer.assign(impl.protocol_, new_socket.get(), ec))
+ new_socket.release();
+ }
+
+ return ec;
+ }
+
+ // Start an asynchronous accept. The peer and peer_endpoint objects
+ // must be valid until the accept's handler is invoked.
+ template <typename Socket, typename Handler>
+ void async_accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_accept_op<Socket, Protocol, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, impl.state_, peer,
+ impl.protocol_, peer_endpoint, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_accept"));
+
+ start_accept_op(impl, p.p, is_continuation, peer.is_open());
+ p.v = p.p = 0;
+ }
+
+ // Connect the socket to the specified endpoint.
+ boost::system::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, boost::system::error_code& ec)
+ {
+ socket_ops::sync_connect(impl.socket_,
+ peer_endpoint.data(), peer_endpoint.size(), ec);
+ return ec;
+ }
+
+ // Start an asynchronous connect.
+ template <typename Handler>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_connect_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect"));
+
+ start_connect_op(impl, p.p, is_continuation,
+ peer_endpoint.data(), peer_endpoint.size());
+ p.v = p.p = 0;
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/reactor_op_ext.hpp b/implementation/helper/boost/asio/detail/reactor_op_ext.hpp
new file mode 100644
index 0000000..575fba2
--- /dev/null
+++ b/implementation/helper/boost/asio/detail/reactor_op_ext.hpp
@@ -0,0 +1,42 @@
+//
+// detail/reactor_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTOR_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTOR_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/reactor_op.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class reactor_op_ext
+ : public reactor_op
+{
+public:
+ // The destination address
+ boost::asio::ip::address da_;
+
+ reactor_op_ext(perform_func_type perform_func, func_type complete_func)
+ : reactor_op(perform_func, complete_func)
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_REACTOR_OP_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/socket_ops_ext.hpp b/implementation/helper/boost/asio/detail/socket_ops_ext.hpp
new file mode 100644
index 0000000..9280830
--- /dev/null
+++ b/implementation/helper/boost/asio/detail/socket_ops_ext.hpp
@@ -0,0 +1,62 @@
+//
+// detail/socket_ops_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_HPP
+#define BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/socket_ops.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+BOOST_ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs,
+ size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec,
+ boost::asio::ip::address& da);
+
+BOOST_ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state,
+ buf* bufs, size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec, boost::asio::ip::address& da);
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+BOOST_ASIO_DECL void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ boost::system::error_code& ec,
+ boost::asio::ip::address& da);
+
+#else // defined(BOOST_ASIO_HAS_IOCP)
+
+BOOST_ASIO_DECL bool non_blocking_recvfrom(socket_type s,
+ buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec, size_t& bytes_transferred,
+ boost::asio::ip::address& da);
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+
+#if defined(BOOST_ASIO_HEADER_ONLY)
+# include <boost/asio/detail/impl/socket_ops_ext.ipp>
+#endif // defined(BOOST_ASIO_HEADER_ONLY)
+
+#endif // BOOST_EXT_ASIO_DETAIL_SOCKET_OPS_HPP
diff --git a/implementation/helper/boost/asio/ip/udp_ext.hpp b/implementation/helper/boost/asio/ip/udp_ext.hpp
new file mode 100644
index 0000000..d5f054e
--- /dev/null
+++ b/implementation/helper/boost/asio/ip/udp_ext.hpp
@@ -0,0 +1,115 @@
+//
+// ip/udp_ext.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_IP_UDP_EXT_HPP
+#define BOOST_ASIO_IP_UDP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/basic_datagram_socket_ext.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/ip/basic_endpoint.hpp>
+#include <boost/asio/ip/basic_resolver.hpp>
+#include <boost/asio/ip/basic_resolver_iterator.hpp>
+#include <boost/asio/ip/basic_resolver_query.hpp>
+#include <boost/asio/ip/udp.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace ip {
+
+/// Encapsulates the flags needed for UDP.
+/**
+ * The boost::asio::ip::udp_ext class contains flags necessary for UDP sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol, InternetProtocol.
+ */
+class udp_ext
+{
+public:
+ /// The type of a UDP endpoint.
+ typedef basic_endpoint<udp> endpoint;
+
+ /// Construct to represent the IPv4 UDP protocol.
+ static udp_ext v4()
+ {
+ return udp_ext(BOOST_ASIO_OS_DEF(AF_INET));
+ }
+
+ /// Construct to represent the IPv6 UDP protocol.
+ static udp_ext v6()
+ {
+ return udp_ext(BOOST_ASIO_OS_DEF(AF_INET6));
+ }
+
+ /// Obtain an identifier for the type of the protocol.
+ int type() const
+ {
+ return BOOST_ASIO_OS_DEF(SOCK_DGRAM);
+ }
+
+ /// Obtain an identifier for the protocol.
+ int protocol() const
+ {
+ return BOOST_ASIO_OS_DEF(IPPROTO_UDP);
+ }
+
+ /// Obtain an identifier for the protocol family.
+ int family() const
+ {
+ return family_;
+ }
+
+ /// The UDP socket type.
+ typedef basic_datagram_socket_ext<udp> socket;
+
+ /// The UDP resolver type.
+ typedef basic_resolver<udp> resolver;
+
+ /// Compare two protocols for equality.
+ friend bool operator==(const udp_ext& p1, const udp_ext& p2)
+ {
+ return p1.family_ == p2.family_;
+ }
+
+ /// Compare two protocols for inequality.
+ friend bool operator!=(const udp_ext& p1, const udp_ext& p2)
+ {
+ return p1.family_ != p2.family_;
+ }
+
+private:
+ // Construct with a specific family.
+ explicit udp_ext(int protocol_family)
+ : family_(protocol_family)
+ {
+ }
+
+ int family_;
+};
+
+} // namespace ip
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_IP_UDP_EXT_HPP
diff --git a/implementation/logging/include/defines.hpp b/implementation/logging/include/defines.hpp
new file mode 100644
index 0000000..bef1a72
--- /dev/null
+++ b/implementation/logging/include/defines.hpp
@@ -0,0 +1,15 @@
+// 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 LOGGING_DEFINES_HPP_
+#define LOGGING_DEFINES_HPP_
+
+#define VSOMEIP_LOG_DEFAULT_APPLICATION_ID "VSIP"
+#define VSOMEIP_LOG_DEFAULT_APPLICATION_NAME "vSomeIP application"
+
+#define VSOMEIP_LOG_DEFAULT_CONTEXT_ID "VSIP"
+#define VSOMEIP_LOG_DEFAULT_CONTEXT_NAME "vSomeIP context"
+
+#endif /* LOGGING_DEFINES_HPP_ */
diff --git a/implementation/logging/include/dlt_sink_backend.hpp b/implementation/logging/include/dlt_sink_backend.hpp
index 1b7fd09..2031158 100644
--- a/implementation/logging/include/dlt_sink_backend.hpp
+++ b/implementation/logging/include/dlt_sink_backend.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -27,12 +27,14 @@ class dlt_sink_backend :
>::type
> {
public:
- dlt_sink_backend();
+ dlt_sink_backend(const std::string &_app_id,
+ const std::string &_context_id);
virtual ~dlt_sink_backend();
void consume(const logging::record_view &rec);
private:
+
#ifdef USE_DLT
DltLogLevelType level_as_dlt(logging::trivial::severity_level _level);
DLT_DECLARE_CONTEXT(dlt_);
diff --git a/implementation/logging/include/logger.hpp b/implementation/logging/include/logger.hpp
index 555f15e..7bbc00a 100644
--- a/implementation/logging/include/logger.hpp
+++ b/implementation/logging/include/logger.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/logging/include/logger_impl.hpp b/implementation/logging/include/logger_impl.hpp
index ddc4eb2..3916874 100644
--- a/implementation/logging/include/logger_impl.hpp
+++ b/implementation/logging/include/logger_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -43,7 +43,8 @@ public:
private:
void enable_console();
void enable_file(const std::string &_path);
- void enable_dlt();
+ void enable_dlt(const std::string &_app_id,
+ const std::string &_context_id);
private:
boost::log::sources::severity_logger<
diff --git a/implementation/logging/src/dlt_sink_backend.cpp b/implementation/logging/src/dlt_sink_backend.cpp
index b4d2864..9da5ae9 100644
--- a/implementation/logging/src/dlt_sink_backend.cpp
+++ b/implementation/logging/src/dlt_sink_backend.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -10,23 +10,28 @@
#endif
#include <boost/log/expressions.hpp>
+#include "../include/defines.hpp"
namespace expressions = boost::log::expressions;
namespace vsomeip
{
-dlt_sink_backend::dlt_sink_backend() {
+dlt_sink_backend::dlt_sink_backend(const std::string &_app_id,
+ const std::string &_context_id) {
+ (void)_app_id;
#ifdef USE_DLT
- DLT_REGISTER_APP("vSIP", "vSomeIP application");
- DLT_REGISTER_CONTEXT(dlt_, "vSIP", "vSomeIP context");
+ DLT_REGISTER_CONTEXT_LL_TS(dlt_, _context_id.c_str(),
+ VSOMEIP_LOG_DEFAULT_CONTEXT_NAME, DLT_LOG_DEBUG,
+ DLT_TRACE_STATUS_ON);
+#else
+ (void)_context_id;
#endif
}
dlt_sink_backend::~dlt_sink_backend() {
#ifdef USE_DLT
DLT_UNREGISTER_CONTEXT(dlt_);
- DLT_UNREGISTER_APP();
#endif
}
diff --git a/implementation/logging/src/logger.cpp b/implementation/logging/src/logger.cpp
index 03f05aa..54b5d75 100644
--- a/implementation/logging/src/logger.cpp
+++ b/implementation/logging/src/logger.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/logging/src/logger_impl.cpp b/implementation/logging/src/logger_impl.cpp
index 6bf4e08..3934c1e 100644
--- a/implementation/logging/src/logger_impl.cpp
+++ b/implementation/logging/src/logger_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -29,8 +29,11 @@
#include <boost/core/null_deleter.hpp>
#endif
+#include <vsomeip/runtime.hpp>
+
#include "../include/logger_impl.hpp"
#include "../../configuration/include/configuration.hpp"
+#include "../include/defines.hpp"
namespace logging = boost::log;
namespace sources = boost::log::sources;
@@ -71,8 +74,13 @@ void logger_impl::init(const std::shared_ptr<configuration> &_configuration) {
if (_configuration->has_file_log())
get()->enable_file(_configuration->get_logfile());
- if (_configuration->has_dlt_log())
- get()->enable_dlt();
+ if (_configuration->has_dlt_log()) {
+ std::string app_id = runtime::get_property("LogApplication");
+ if (app_id == "") app_id = VSOMEIP_LOG_DEFAULT_APPLICATION_ID;
+ std::string context_id = runtime::get_property("LogContext");
+ if (context_id == "") context_id = VSOMEIP_LOG_DEFAULT_CONTEXT_ID;
+ get()->enable_dlt(app_id, context_id);
+ }
}
void logger_impl::enable_console() {
@@ -123,14 +131,19 @@ void logger_impl::enable_file(const std::string &_path) {
logging::core::get()->add_sink(file_sink_);
}
-void logger_impl::enable_dlt() {
+void logger_impl::enable_dlt(const std::string &_app_id,
+ const std::string &_context_id) {
#ifdef USE_DLT
if (dlt_sink_)
return;
- boost::shared_ptr<dlt_sink_backend> backend = boost::make_shared<dlt_sink_backend>();
+ boost::shared_ptr<dlt_sink_backend> backend = boost::make_shared<dlt_sink_backend>(_app_id,
+ _context_id);
dlt_sink_ = boost::make_shared<dlt_sink_t>(backend);
logging::core::get()->add_sink(dlt_sink_);
+#else
+ (void)_app_id;
+ (void)_context_id;
#endif
}
diff --git a/implementation/message/include/deserializer.hpp b/implementation/message/include/deserializer.hpp
index 941358b..0588aa7 100644
--- a/implementation/message/include/deserializer.hpp
+++ b/implementation/message/include/deserializer.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/message/include/message_base_impl.hpp b/implementation/message/include/message_base_impl.hpp
index 58562f1..40486a2 100644
--- a/implementation/message/include/message_base_impl.hpp
+++ b/implementation/message/include/message_base_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -56,12 +56,16 @@ public:
VSOMEIP_EXPORT bool is_reliable() const;
VSOMEIP_EXPORT void set_reliable(bool _is_reliable);
+ VSOMEIP_EXPORT virtual bool is_initial() const;
+ VSOMEIP_EXPORT virtual void set_initial(bool _is_initial);
+
VSOMEIP_EXPORT message * get_owner() const;
VSOMEIP_EXPORT void set_owner(message *_owner);
protected: // members
message_header_impl header_;
bool is_reliable_;
+ bool is_initial_;
};
} // namespace vsomeip
diff --git a/implementation/message/include/message_header_impl.hpp b/implementation/message/include/message_header_impl.hpp
index b233d75..18f734d 100644
--- a/implementation/message/include/message_header_impl.hpp
+++ b/implementation/message/include/message_header_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/message/include/message_impl.hpp b/implementation/message/include/message_impl.hpp
index 7c8902c..102833a 100644
--- a/implementation/message/include/message_impl.hpp
+++ b/implementation/message/include/message_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -11,6 +11,16 @@
#include <vsomeip/export.hpp>
#include "message_base_impl.hpp"
+# if _MSC_VER >= 1300
+/*
+* Diamond inheritance is used for the vsomeip::message_base base class.
+* The Microsoft compiler put warning (C4250) using a desired c++ feature: "Delegating to a sister class"
+* A powerful technique that arises from using virtual inheritance is to delegate a method from a class in another class
+* by using a common abstract base class. This is also called cross delegation.
+*/
+# pragma warning( disable : 4250 )
+# endif
+
namespace vsomeip {
class payload;
diff --git a/implementation/message/include/payload_impl.hpp b/implementation/message/include/payload_impl.hpp
index 2530ac8..66b3afa 100644
--- a/implementation/message/include/payload_impl.hpp
+++ b/implementation/message/include/payload_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/message/include/serializer.hpp b/implementation/message/include/serializer.hpp
index 427ee20..7928a52 100644
--- a/implementation/message/include/serializer.hpp
+++ b/implementation/message/include/serializer.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/message/src/deserializer.cpp b/implementation/message/src/deserializer.cpp
index 6017d5a..fb6f670 100644
--- a/implementation/message/src/deserializer.cpp
+++ b/implementation/message/src/deserializer.cpp
@@ -8,12 +8,11 @@
#ifdef VSOMEIP_DEBUGGING
#include <iomanip>
#include <sstream>
-
-#include "../../logging/include/logger.hpp"
#endif
#include "../include/message_impl.hpp"
#include "../include/deserializer.hpp"
+#include "../../logging/include/logger.hpp"
#include "../../utility/include/byteorder.hpp"
namespace vsomeip {
@@ -148,8 +147,9 @@ message * deserializer::deserialize_message() {
message_impl* deserialized_message = new message_impl;
if (0 != deserialized_message) {
if (false == deserialized_message->deserialize(this)) {
+ VSOMEIP_ERROR << "SOME/IP message deserialization failed!";
delete deserialized_message;
- deserialized_message = 0;
+ deserialized_message = nullptr;
}
}
diff --git a/implementation/message/src/message_base_impl.cpp b/implementation/message/src/message_base_impl.cpp
index 616ed63..c9597fc 100644
--- a/implementation/message/src/message_base_impl.cpp
+++ b/implementation/message/src/message_base_impl.cpp
@@ -9,7 +9,8 @@
namespace vsomeip {
message_base_impl::message_base_impl()
- : is_reliable_(false) {
+ : is_reliable_(false),
+ is_initial_(false) {
header_.set_owner(this);
}
@@ -110,4 +111,11 @@ void message_base_impl::set_reliable(bool _is_reliable) {
is_reliable_ = _is_reliable;
}
+bool message_base_impl::is_initial() const {
+ return is_initial_;
+}
+void message_base_impl::set_initial(bool _is_initial) {
+ is_initial_ = _is_initial;
+}
+
} // namespace vsomeip
diff --git a/implementation/routing/include/event.hpp b/implementation/routing/include/event.hpp
index 2036636..9033160 100644
--- a/implementation/routing/include/event.hpp
+++ b/implementation/routing/include/event.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -27,7 +27,7 @@ class routing_manager;
class event: public std::enable_shared_from_this<event> {
public:
- event(routing_manager *_routing);
+ event(routing_manager *_routing, bool _is_shadow = false);
service_t get_service() const;
void set_service(service_t _service);
@@ -48,8 +48,10 @@ public:
void set_payload(std::shared_ptr<payload> _payload,
const std::shared_ptr<endpoint_definition> _target);
+ void set_payload_dont_notify(std::shared_ptr<payload> _payload);
+
void set_payload(std::shared_ptr<payload> _payload);
- void unset_payload();
+ void unset_payload(bool _force = false);
bool is_field() const;
void set_field(bool _is_field);
@@ -57,6 +59,8 @@ public:
bool is_provided() const;
void set_provided(bool _is_provided);
+ bool is_set() const;
+
// SIP_RPC_357
void set_update_cycle(std::chrono::milliseconds &_cycle);
@@ -70,10 +74,17 @@ public:
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);
+ void notify_one(client_t _client, bool _is_initial = false);
+
+ void add_ref(client_t _client, bool _is_provided);
+ void remove_ref(client_t _client, bool _is_provided);
+ bool has_ref();
- void add_ref();
- uint32_t remove_ref();
+ bool is_shadow() const;
+ void set_shadow(bool _shadow);
+
+ bool is_cache_placeholder() const;
+ void set_cache_placeholder(bool _is_cache_place_holder);
private:
void update_cbk(boost::system::error_code const &_error);
@@ -99,7 +110,11 @@ private:
bool is_set_;
bool is_provided_;
- uint32_t ref_;
+ std::map<client_t, std::map<bool, uint32_t>> refs_;
+
+ bool is_shadow_;
+
+ bool is_cache_placeholder_;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/eventgroupinfo.hpp b/implementation/routing/include/eventgroupinfo.hpp
index 08536e0..7e832a1 100644
--- a/implementation/routing/include/eventgroupinfo.hpp
+++ b/implementation/routing/include/eventgroupinfo.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -6,6 +6,8 @@
#ifndef VSOMEIP_EVENTGROUPINFO_HPP
#define VSOMEIP_EVENTGROUPINFO_HPP
+#include <chrono>
+#include <list>
#include <memory>
#include <set>
@@ -21,6 +23,15 @@ class event;
class eventgroupinfo {
public:
+ struct target_t {
+ std::shared_ptr<endpoint_definition> endpoint_;
+ std::chrono::high_resolution_clock::time_point expiration_;
+
+ bool operator==(const target_t &_other) const {
+ return (endpoint_ == _other.endpoint_);
+ }
+ };
+
VSOMEIP_EXPORT eventgroupinfo();
VSOMEIP_EXPORT eventgroupinfo(major_version_t _major, ttl_t _ttl);
VSOMEIP_EXPORT ~eventgroupinfo();
@@ -41,22 +52,32 @@ public:
VSOMEIP_EXPORT void add_event(std::shared_ptr<event> _event);
VSOMEIP_EXPORT void remove_event(std::shared_ptr<event> _event);
- VSOMEIP_EXPORT const std::set<
- std::shared_ptr<endpoint_definition> > get_targets() const;
- VSOMEIP_EXPORT bool add_target(std::shared_ptr<endpoint_definition> _target);
- VSOMEIP_EXPORT bool remove_target(std::shared_ptr<endpoint_definition> _target);
+ VSOMEIP_EXPORT const std::list<target_t> get_targets() const;
+ VSOMEIP_EXPORT uint32_t get_unreliable_target_count();
+
+ 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);
+ VSOMEIP_EXPORT bool remove_target(
+ const std::shared_ptr<endpoint_definition> &_target);
VSOMEIP_EXPORT void clear_targets();
+ VSOMEIP_EXPORT void add_multicast_target(const target_t &_multicast_target);
+ VSOMEIP_EXPORT void clear_multicast_targets();
+ VSOMEIP_EXPORT const std::list<target_t> get_multicast_targets() const;
+
private:
major_version_t major_;
ttl_t ttl_;
- bool is_multicast_;
boost::asio::ip::address address_;
uint16_t port_;
std::set<std::shared_ptr<event> > events_;
- std::set<std::shared_ptr<endpoint_definition> > targets_;
+ std::list<target_t> targets_;
+ std::list<target_t> multicast_targets_;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/routing_manager.hpp b/implementation/routing/include/routing_manager.hpp
index 2642677..ee18957 100644
--- a/implementation/routing/include/routing_manager.hpp
+++ b/implementation/routing/include/routing_manager.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -13,6 +13,7 @@
#include <boost/asio/io_service.hpp>
#include <vsomeip/message.hpp>
+#include <vsomeip/handler.hpp>
namespace vsomeip {
@@ -39,7 +40,7 @@ public:
minor_version_t _minor) = 0;
virtual void stop_offer_service(client_t _client, service_t _service,
- instance_t _instance) = 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,
@@ -50,7 +51,8 @@ public:
virtual void subscribe(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
- major_version_t _major, subscription_type_e _subscription_type) = 0;
+ major_version_t _major,
+ subscription_type_e _subscription_type) = 0;
virtual void unsubscribe(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup) = 0;
@@ -59,7 +61,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) = 0;
+ instance_t _instance, bool _flush, bool _reliable, bool _initial) = 0;
virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target,
std::shared_ptr<message>) = 0;
@@ -69,17 +71,26 @@ public:
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) = 0;
+ bool _is_field, 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 std::shared_ptr<event> get_event(service_t _service,
+ instance_t _instance, event_t _event) const = 0;
+
+ virtual std::set<std::shared_ptr<event>> find_events(service_t _service,
+ 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;
virtual void notify_one(service_t _service, instance_t _instance,
event_t _event, std::shared_ptr<payload> _payload, client_t _client) = 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_adapter.hpp b/implementation/routing/include/routing_manager_adapter.hpp
index fc0e55d..0dfe703 100644
--- a/implementation/routing/include/routing_manager_adapter.hpp
+++ b/implementation/routing/include/routing_manager_adapter.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/routing/include/routing_manager_base.hpp b/implementation/routing/include/routing_manager_base.hpp
new file mode 100644
index 0000000..1d69f6f
--- /dev/null
+++ b/implementation/routing/include/routing_manager_base.hpp
@@ -0,0 +1,193 @@
+// 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_ROUTING_MANAGER_BASE
+#define VSOMEIP_ROUTING_MANAGER_BASE
+
+#include <mutex>
+#include <unordered_set>
+
+#include <vsomeip/constants.hpp>
+#include "routing_manager.hpp"
+#include "routing_manager_host.hpp"
+#include "types.hpp"
+#include "serviceinfo.hpp"
+#include "event.hpp"
+#include "eventgroupinfo.hpp"
+#include "../../message/include/serializer.hpp"
+#include "../../message/include/deserializer.hpp"
+#include "../../configuration/include/configuration.hpp"
+#include "../../endpoints/include/endpoint_host.hpp"
+
+#ifdef USE_DLT
+#include "../../tracing/include/trace_connector.hpp"
+#endif
+
+#ifdef USE_DLT
+namespace tc {
+class trace_connector;
+} // namespace tc
+#endif
+
+namespace vsomeip {
+
+class serializer;
+
+class routing_manager_base : public routing_manager,
+ public endpoint_host,
+ public std::enable_shared_from_this<routing_manager_base>{
+
+public:
+ routing_manager_base(routing_manager_host *_host);
+ virtual ~routing_manager_base();
+
+ virtual boost::asio::io_service & get_io();
+ virtual client_t get_client() const;
+
+ virtual void init();
+
+ virtual void offer_service(client_t _client, service_t _service,
+ instance_t _instance, major_version_t _major,
+ minor_version_t _minor);
+
+ virtual void stop_offer_service(client_t _client, service_t _service,
+ instance_t _instance, major_version_t _major, minor_version_t _minor);
+
+ virtual void request_service(client_t _client, service_t _service,
+ instance_t _instance, major_version_t _major,
+ minor_version_t _minor, bool _use_exclusive_proxy);
+
+ virtual void release_service(client_t _client, service_t _service,
+ 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);
+
+ virtual void unregister_event(client_t _client, service_t _service, instance_t _instance,
+ event_t _event, bool _is_provided);
+
+ virtual std::shared_ptr<event> get_event(service_t _service,
+ instance_t _instance, event_t _event) const;
+
+ virtual std::set<std::shared_ptr<event>> find_events(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) const;
+
+ virtual void subscribe(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup,
+ major_version_t _major,
+ subscription_type_e _subscription_type);
+
+ 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_one(service_t _service, instance_t _instance,
+ event_t _event, std::shared_ptr<payload> _payload, client_t _client);
+
+ 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;
+
+ // Endpoint host ~> will be implemented by routing_manager_impl/_proxy/
+ virtual void on_connect(std::shared_ptr<endpoint> _endpoint) = 0;
+ virtual void on_disconnect(std::shared_ptr<endpoint> _endpoint) = 0;
+ virtual void on_message(const byte_t *_data, length_t _length,
+ endpoint *_receiver, const boost::asio::ip::address &_destination
+ = boost::asio::ip::address()) = 0;
+ virtual void on_error(const byte_t *_data, length_t _length,
+ endpoint *_receiver) = 0;
+
+protected:
+ std::shared_ptr<serviceinfo> find_service(service_t _service, instance_t _instance) const;
+ std::shared_ptr<serviceinfo> create_service_info(service_t _service,
+ instance_t _instance, major_version_t _major,
+ minor_version_t _minor, ttl_t _ttl, bool _is_local_service);
+
+ void clear_service_info(service_t _service, instance_t _instance, bool _reliable);
+ services_t get_services() const;
+ bool is_available(service_t _service, instance_t _instance, major_version_t _major);
+ client_t find_local_client(service_t _service, instance_t _instance);
+
+ std::shared_ptr<endpoint> create_local(client_t _client);
+ std::shared_ptr<endpoint> find_or_create_local(client_t _client);
+ void remove_local(client_t _client);
+ std::shared_ptr<endpoint> find_local(client_t _client);
+ std::shared_ptr<endpoint> find_local(service_t _service,
+ instance_t _instance);
+
+ std::unordered_set<client_t> get_connected_clients();
+
+ std::shared_ptr<event> find_event(service_t _service, instance_t _instance,
+ event_t _event) const;
+ std::shared_ptr<eventgroupinfo> find_eventgroup(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) const;
+
+ std::set<client_t> find_local_clients(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup);
+
+ void remove_eventgroup_info(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup);
+
+ void 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 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 insert_subscription(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup, client_t _client);
+
+ routing_manager_host *host_;
+ boost::asio::io_service &io_;
+ client_t client_;
+
+ std::shared_ptr<configuration> configuration_;
+ std::shared_ptr<serializer> serializer_;
+ std::shared_ptr<deserializer> deserializer_;
+
+ std::mutex serialize_mutex_;
+
+ std::mutex local_services_mutex_;
+ std::map<service_t, std::map<instance_t, std::tuple< major_version_t, minor_version_t, client_t> > > local_services_;
+
+ // Eventgroups
+ mutable std::mutex eventgroups_mutex_;
+ std::map<service_t,
+ std::map<instance_t,
+ std::map<eventgroup_t, std::shared_ptr<eventgroupinfo> > > > eventgroups_;
+ mutable std::mutex events_mutex_;
+ std::map<service_t,
+ std::map<instance_t, std::map<event_t, std::shared_ptr<event> > > > events_;
+ std::mutex eventgroup_clients_mutex_;
+ std::map<service_t,
+ std::map<instance_t, std::map<eventgroup_t, std::set<client_t> > > > eventgroup_clients_;
+
+#ifdef USE_DLT
+ std::shared_ptr<tc::trace_connector> tc_;
+#endif
+
+private:
+ services_t services_;
+ mutable std::mutex services_mutex_;
+
+ std::map<client_t, std::shared_ptr<endpoint> > local_endpoints_;
+ mutable std::mutex local_endpoint_mutex_;
+};
+
+} // namespace vsomeip
+
+#endif //VSOMEIP_ROUTING_MANAGER_BASE
diff --git a/implementation/routing/include/routing_manager_host.hpp b/implementation/routing/include/routing_manager_host.hpp
index 7b96be0..3a60d8c 100644
--- a/implementation/routing/include/routing_manager_host.hpp
+++ b/implementation/routing/include/routing_manager_host.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -28,12 +28,14 @@ public:
virtual boost::asio::io_service & get_io() = 0;
virtual void on_availability(service_t _service, instance_t _instance,
- bool _is_available) const = 0;
+ bool _is_available, major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR) = 0;
virtual void on_state(state_type_e _state) = 0;
virtual void on_message(std::shared_ptr<message> _message) = 0;
virtual void on_error(error_code_e _error) = 0;
virtual bool on_subscription(service_t _service, instance_t _instance, eventgroup_t _eventgroup,
client_t _client, bool _subscribed) = 0;
+ virtual void on_subscription_error(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup, uint16_t _error) = 0;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/routing_manager_impl.hpp b/implementation/routing/include/routing_manager_impl.hpp
index 9741f3e..13936a4 100644
--- a/implementation/routing/include/routing_manager_impl.hpp
+++ b/implementation/routing/include/routing_manager_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -10,16 +10,17 @@
#include <memory>
#include <mutex>
#include <vector>
+#include <list>
#include <unordered_set>
#include <boost/asio/ip/address.hpp>
#include <boost/asio/io_service.hpp>
#include <vsomeip/primitive_types.hpp>
+#include <vsomeip/handler.hpp>
-#include "routing_manager.hpp"
+#include "routing_manager_base.hpp"
#include "routing_manager_stub_host.hpp"
-#include "../../endpoints/include/endpoint_host.hpp"
#include "../../service_discovery/include/service_discovery_host.hpp"
namespace vsomeip {
@@ -31,24 +32,20 @@ class eventgroupinfo;
class routing_manager_host;
class routing_manager_stub;
class servicegroup;
-class serviceinfo;
class serializer;
class service_endpoint;
namespace sd {
-
class service_discovery;
+} // namespace sd
-} // namespace sd
// TODO: encapsulate common parts of classes "routing_manager_impl"
// and "routing_manager_proxy" into a base class.
-class routing_manager_impl: public routing_manager,
- public endpoint_host,
+class routing_manager_impl: public routing_manager_base,
public routing_manager_stub_host,
- public sd::service_discovery_host,
- public std::enable_shared_from_this<routing_manager_impl> {
+ public sd::service_discovery_host {
public:
routing_manager_impl(routing_manager_host *_host);
~routing_manager_impl();
@@ -66,7 +63,7 @@ public:
minor_version_t _minor);
void stop_offer_service(client_t _client, service_t _service,
- instance_t _instance);
+ instance_t _instance, major_version_t _major, minor_version_t _minor);
void request_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
@@ -85,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);
+ instance_t _instance, bool _flush, bool _reliable, bool _initial = false);
bool send_to(const std::shared_ptr<endpoint_definition> &_target,
std::shared_ptr<message> _message);
@@ -93,12 +90,15 @@ public:
bool send_to(const std::shared_ptr<endpoint_definition> &_target,
const byte_t *_data, uint32_t _size);
- void register_event(client_t _client, service_t _service,
+ bool send_to(const std::shared_ptr<endpoint_definition> &_target,
+ const byte_t *_data, uint32_t _size, uint16_t _sd_port);
+
+ void register_shadow_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);
- void unregister_event(client_t _client, service_t _service,
+ void unregister_shadow_event(client_t _client, service_t _service,
instance_t _instance, event_t _event,
bool _is_provided);
@@ -108,14 +108,23 @@ public:
void notify_one(service_t _service, instance_t _instance,
event_t _event, std::shared_ptr<payload> _payload, client_t _client);
+ void on_subscribe_nack(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup);
+
+ void on_subscribe_ack(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup);
+
+ 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> create_local(client_t _client);
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);
- std::shared_ptr<endpoint> find_local(service_t _service,
- instance_t _instance);
- void on_stop_offer_service(service_t _service, instance_t _instance);
+ void on_stop_offer_service(service_t _service, instance_t _instance,
+ major_version_t _major, minor_version_t _minor);
// interface "endpoint_host"
std::shared_ptr<endpoint> find_or_create_remote_client(service_t _service,
@@ -124,11 +133,14 @@ public:
void on_connect(std::shared_ptr<endpoint> _endpoint);
void on_disconnect(std::shared_ptr<endpoint> _endpoint);
void on_error(const byte_t *_data, length_t _length, endpoint *_receiver);
- void on_message(const byte_t *_data, length_t _length, endpoint *_receiver);
+ void on_message(const byte_t *_data, length_t _length, endpoint *_receiver,
+ const boost::asio::ip::address &_destination);
void on_message(service_t _service, instance_t _instance,
const byte_t *_data, length_t _size, bool _reliable);
void on_notification(client_t _client, service_t _service,
- instance_t _instance, const byte_t *_data, length_t _size);
+ instance_t _instance, const byte_t *_data, length_t _size,
+ bool _notify_one);
+ void release_port(uint16_t _port, bool _reliable);
// interface "service_discovery_host"
typedef std::map<std::string, std::shared_ptr<servicegroup> > servicegroups_t;
@@ -147,12 +159,17 @@ public:
uint16_t _unreliable_port);
void del_routing_info(service_t _service, instance_t _instance,
bool _has_reliable, bool _has_unreliable);
- ttl_t update_routing_info(ttl_t _elapsed);
+ std::chrono::milliseconds update_routing_info(std::chrono::milliseconds _elapsed);
void on_subscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup,
std::shared_ptr<endpoint_definition> _subscriber,
- std::shared_ptr<endpoint_definition> _target);
+ std::shared_ptr<endpoint_definition> _target,
+ const std::chrono::high_resolution_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);
void on_unsubscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup,
std::shared_ptr<endpoint_definition> _target);
@@ -162,45 +179,34 @@ 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();
+
+ bool has_identified(client_t _client, service_t _service,
+ instance_t _instance, bool _reliable);
+
private:
bool deliver_message(const byte_t *_data, length_t _length,
instance_t _instance, bool _reliable);
bool deliver_notification(service_t _service, instance_t _instance,
const byte_t *_data, length_t _length, bool _reliable);
- 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) const;
-
- client_t find_local_client(service_t _service, instance_t _instance);
- std::set<client_t> find_local_clients(service_t _service,
- instance_t _instance, eventgroup_t _eventgroup);
+
instance_t find_instance(service_t _service, endpoint *_endpoint);
- std::shared_ptr<serviceinfo> find_service(service_t _service,
- instance_t _instance) const;
- std::shared_ptr<serviceinfo> create_service_info(service_t _service,
- instance_t _instance, major_version_t _major,
- minor_version_t _minor, ttl_t _ttl, bool _is_local_service);
+ void init_service_info(service_t _service,
+ instance_t _instance, bool _is_local_service);
std::shared_ptr<endpoint> create_client_endpoint(
- const boost::asio::ip::address &_address, uint16_t _port,
+ const boost::asio::ip::address &_address,
+ uint16_t _local_port, uint16_t _remote_port,
bool _reliable, client_t _client, bool _start);
- void remove_eventgroup_info(service_t _service, instance_t _instance,
- eventgroup_t _eventgroup);
-
std::shared_ptr<endpoint> create_server_endpoint(uint16_t _port,
bool _reliable, bool _start);
std::shared_ptr<endpoint> find_server_endpoint(uint16_t _port,
- bool _reliable);
+ bool _reliable) const;
std::shared_ptr<endpoint> find_or_create_server_endpoint(uint16_t _port,
bool _reliable, bool _start);
- std::set<std::shared_ptr<event> > find_events(service_t _service,
- instance_t _instance, eventgroup_t _eventgroup);
- std::shared_ptr<event> find_event(service_t _service, instance_t _instance,
- event_t _event) const;
bool is_field(service_t _service, instance_t _instance,
event_t _event) const;
@@ -216,19 +222,8 @@ private:
void clear_client_endpoints(service_t _service, instance_t _instance, bool _reliable);
void stop_and_delete_client_endpoint(std::shared_ptr<endpoint> _endpoint);
void clear_multicast_endpoints(service_t _service, instance_t _instance);
- void clear_service_info(service_t _service, instance_t _instance, bool _reliable);
private:
- void send_subscribe(client_t _client, service_t _service,
- instance_t _instance, eventgroup_t _eventgroup,
- major_version_t _major);
-
- void send_unsubscribe(client_t _client, service_t _service,
- instance_t _instance, eventgroup_t _eventgroup);
-
- bool insert_subscription(service_t _service, instance_t _instance,
- eventgroup_t _eventgroup, client_t _client);
-
return_code_e check_error(const byte_t *_data, length_t _size,
instance_t _instance);
@@ -236,23 +231,22 @@ private:
length_t _size, instance_t _instance, bool _reliable,
endpoint *_receiver);
- routing_manager_host *host_;
- boost::asio::io_service &io_;
+ void identify_for_subscribe(client_t _client, service_t _service,
+ instance_t _instance, major_version_t _major);
- std::shared_ptr<deserializer> deserializer_;
- std::shared_ptr<serializer> serializer_;
+ bool supports_selective(service_t _service, instance_t _instance);
- std::shared_ptr<configuration> configuration_;
+ client_t find_client(service_t _service, instance_t _instance,
+ const std::shared_ptr<eventgroupinfo> &_eventgroup,
+ const std::shared_ptr<endpoint_definition> &_target) const;
+
+ void clear_remote_subscriber(service_t _service, instance_t _instance,
+ client_t _client,
+ const std::shared_ptr<endpoint_definition> &_target);
std::shared_ptr<routing_manager_stub> stub_;
std::shared_ptr<sd::service_discovery> discovery_;
- // Routing info
-
- // Local
- std::map<client_t, std::shared_ptr<endpoint> > local_clients_;
- std::map<service_t, std::map<instance_t, client_t> > local_services_;
-
// Server endpoints for local services
std::map<uint16_t, std::map<bool, std::shared_ptr<endpoint> > > server_endpoints_;
std::map<service_t, std::map<endpoint *, instance_t> > service_instances_;
@@ -268,29 +262,27 @@ private:
std::map<instance_t, std::map<client_t, std::map<bool, std::shared_ptr<endpoint> > > > >remote_services_;
std::map<boost::asio::ip::address,
std::map<uint16_t, std::map<bool, std::shared_ptr<endpoint> > > > client_endpoints_by_ip_;
-
- // Services
- services_t services_;
-
- // Eventgroups
- std::map<service_t,
- std::map<instance_t,
- std::map<eventgroup_t, std::shared_ptr<eventgroupinfo> > > > eventgroups_;
- std::map<service_t,
- std::map<instance_t, std::map<event_t, std::shared_ptr<event> > > > events_;
- std::map<service_t,
- std::map<instance_t, std::map<eventgroup_t, std::set<client_t> > > > eventgroup_clients_;
+ std::map<client_t,
+ std::map<service_t,
+ std::map<instance_t,
+ std::set<std::pair<major_version_t, minor_version_t>>>>> requested_services_;
// Mutexes
mutable std::recursive_mutex endpoint_mutex_;
- mutable std::mutex local_mutex_;
- std::mutex serialize_mutex_;
- mutable std::mutex services_mutex_;
- mutable std::mutex eventgroups_mutex_;
+ std::mutex identified_clients_mutex_;
+ std::mutex requested_services_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<client_t, std::shared_ptr<endpoint_definition>> remote_subscriber_map_;
+ std::shared_ptr<serviceinfo> sd_info_;
- std::unordered_set<client_t> specific_endpoint_clients;
+ std::map<bool, std::set<uint16_t>> used_client_ports_;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_proxy.hpp
index 0577597..d2f61d7 100644
--- a/implementation/routing/include/routing_manager_proxy.hpp
+++ b/implementation/routing/include/routing_manager_proxy.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -11,9 +11,9 @@
#include <boost/asio/io_service.hpp>
-#include "routing_manager.hpp"
-#include "../../endpoints/include/endpoint_host.hpp"
+#include "routing_manager_base.hpp"
#include <vsomeip/enumeration_types.hpp>
+#include <vsomeip/handler.hpp>
namespace vsomeip {
@@ -21,19 +21,11 @@ class configuration;
class event;
class routing_manager_host;
-// TODO: encapsulate common parts of classes "routing_manager_impl"
-// and "routing_manager_proxy" into a base class.
-
-class routing_manager_proxy: public routing_manager,
- public endpoint_host,
- public std::enable_shared_from_this<routing_manager_proxy> {
+class routing_manager_proxy: public routing_manager_base {
public:
routing_manager_proxy(routing_manager_host *_host);
virtual ~routing_manager_proxy();
- boost::asio::io_service & get_io();
- client_t get_client() const;
-
void init();
void start();
void stop();
@@ -43,7 +35,7 @@ public:
minor_version_t _minor);
void stop_offer_service(client_t _client, service_t _service,
- instance_t _instance);
+ instance_t _instance, major_version_t _major, minor_version_t _minor);
void request_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
@@ -59,10 +51,9 @@ public:
void unsubscribe(client_t _client, service_t _service, instance_t _instance,
eventgroup_t _eventgroup);
- 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 = true, bool _reliable = false);
+ instance_t _instance, bool _flush = true, bool _reliable = false,
+ bool _initial = false);
bool send_to(const std::shared_ptr<endpoint_definition> &_target,
std::shared_ptr<message> _message);
@@ -73,7 +64,7 @@ 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_field, 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,
@@ -82,29 +73,24 @@ public:
void notify(service_t _service, instance_t _instance, event_t _event,
std::shared_ptr<payload> _payload);
- void notify_one(service_t _service, instance_t _instance,
- event_t _event, std::shared_ptr<payload> _payload,
- client_t _client);
-
void on_connect(std::shared_ptr<endpoint> _endpoint);
void on_disconnect(std::shared_ptr<endpoint> _endpoint);
- void on_message(const byte_t *_data, length_t _length, endpoint *_receiver);
+ void on_message(const byte_t *_data, length_t _length, endpoint *_receiver,
+ const boost::asio::ip::address &_destination);
void on_error(const byte_t *_data, length_t _length, endpoint *_receiver);
+ void release_port(uint16_t _port, bool _reliable);
void on_routing_info(const byte_t *_data, uint32_t _size);
- std::shared_ptr<endpoint> find_local(client_t _client);
- std::shared_ptr<endpoint> find_local(service_t _service,
- instance_t _instance);
- std::shared_ptr<endpoint> find_or_create_local(client_t _client);
- void remove_local(client_t _client);
+ 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();
- std::shared_ptr<endpoint> create_local(client_t _client);
-
void send_pong() const;
void send_offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
@@ -112,6 +98,8 @@ private:
void send_request_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major,
minor_version_t _minor, bool _use_exclusive_proxy);
+ void send_release_service(client_t _client, service_t _service,
+ instance_t _instance);
void send_register_event(client_t _client, service_t _service,
instance_t _instance, event_t _event,
const std::set<eventgroup_t> &_eventgroup,
@@ -120,29 +108,38 @@ private:
instance_t _instance, eventgroup_t _eventgroup,
major_version_t _major, subscription_type_e _subscription_type);
+ void send_subscribe_nack(client_t _subscriber, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup);
+
+ void send_subscribe_ack(client_t _subscriber, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup);
+
bool is_field(service_t _service, instance_t _instance,
event_t _event) const;
+ void on_subscribe_nack(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup);
+
+ void on_subscribe_ack(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup);
+
+ void send_pending_subscriptions(service_t _service, instance_t _instance,
+ major_version_t _major);
+
+ void cache_event_payload(const std::shared_ptr<message> &_message);
+
+ void on_stop_offer_service(service_t _service, instance_t _instance,
+ major_version_t _major, minor_version_t _minor);
+
private:
- boost::asio::io_service &io_;
bool is_connected_;
bool is_started_;
state_type_e state_;
- routing_manager_host *host_;
- client_t client_; // store locally as it is needed in each message
-
- std::shared_ptr<configuration> configuration_;
-
- std::shared_ptr<serializer> serializer_;
- std::shared_ptr<deserializer> deserializer_;
std::shared_ptr<endpoint> sender_; // --> stub
std::shared_ptr<endpoint> receiver_; // --> from everybody
- std::map<client_t, std::shared_ptr<endpoint> > local_endpoints_;
- std::map<service_t, std::map<instance_t, client_t> > local_services_;
- std::map<service_t, std::map<instance_t, major_version_t> > service_versions_;
- std::mutex local_services_mutex_;
+ std::unordered_set<client_t> known_clients_;
struct service_data_t {
service_t service_;
@@ -196,6 +193,7 @@ private:
}
};
std::set<eventgroup_data_t> pending_subscriptions_;
+ std::map<client_t, std::set<eventgroup_data_t>> pending_ingoing_subscripitons_;
std::map<service_t,
std::map<instance_t,
@@ -203,11 +201,8 @@ private:
std::shared_ptr<message> > > > pending_notifications_;
std::mutex send_mutex_;
- std::mutex serialize_mutex_;
std::mutex deserialize_mutex_;
std::mutex pending_mutex_;
-
- std::map<service_t, std::map<instance_t, std::set<event_t> > > fields_;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/routing_manager_stub.hpp b/implementation/routing/include/routing_manager_stub.hpp
index 6a1ec38..27b8ec5 100644
--- a/implementation/routing/include/routing_manager_stub.hpp
+++ b/implementation/routing/include/routing_manager_stub.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -6,11 +6,13 @@
#ifndef VSOMEIP_ROUTING_MANAGER_STUB
#define VSOMEIP_ROUTING_MANAGER_STUB
+#include <condition_variable>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <set>
+#include <thread>
#include <boost/asio/io_service.hpp>
#include <boost/asio/system_timer.hpp>
@@ -36,13 +38,32 @@ public:
void on_connect(std::shared_ptr<endpoint> _endpoint);
void on_disconnect(std::shared_ptr<endpoint> _endpoint);
- void on_message(const byte_t *_data, length_t _length, endpoint *_receiver);
+ void on_message(const byte_t *_data, length_t _length, endpoint *_receiver,
+ const boost::asio::ip::address &_destination);
void on_error(const byte_t *_data, length_t _length, endpoint *_receiver);
+ void release_port(uint16_t _port, bool _reliable);
void on_offer_service(client_t _client, service_t _service,
- instance_t _instance);
+ instance_t _instance, major_version_t _major, minor_version_t _minor);
void on_stop_offer_service(client_t _client, service_t _service,
- instance_t _instance);
+ 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,
+ major_version_t _major, bool _is_remote_subscriber);
+
+ void send_unsubscribe(std::shared_ptr<vsomeip::endpoint> _target,
+ client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup);
+
+ void send_subscribe_nack(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup);
+
+ void send_subscribe_ack(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup);
private:
void broadcast(std::vector<byte_t> &_command) const;
@@ -50,8 +71,8 @@ private:
void on_register_application(client_t _client);
void on_deregister_application(client_t _client);
- void broadcast_routing_info();
- void send_routing_info(client_t _client);
+ void broadcast_routing_info(bool _empty = false);
+ void send_routing_info(client_t _client, bool _empty = false);
void broadcast_ping() const;
void on_pong(client_t _client);
@@ -59,18 +80,30 @@ private:
void check_watchdog();
void send_application_lost(std::list<client_t> &_lost);
+ void client_registration_func(void);
+
private:
routing_manager_stub_host *host_;
boost::asio::io_service &io_;
boost::asio::system_timer watchdog_timer_;
std::string endpoint_path_;
+ std::string local_receiver_path_;
std::shared_ptr<endpoint> endpoint_;
+ std::shared_ptr<endpoint> local_receiver_;
std::map<client_t,
- std::pair<uint8_t, std::map<service_t, std::set<instance_t> > > > routing_info_;
+ std::pair<uint8_t, std::map<service_t, std::map<instance_t, std::pair<major_version_t, minor_version_t>> > > > routing_info_;
mutable std::mutex routing_info_mutex_;
std::shared_ptr<configuration> configuration_;
+
+ size_t routingCommandSize_;
+
+ bool client_registration_running_;
+ 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_;
};
} // namespace vsomeip
diff --git a/implementation/routing/include/routing_manager_stub_host.hpp b/implementation/routing/include/routing_manager_stub_host.hpp
index d56f2d3..e216b5a 100644
--- a/implementation/routing/include/routing_manager_stub_host.hpp
+++ b/implementation/routing/include/routing_manager_stub_host.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -7,6 +7,7 @@
#define VSOMEIP_ROUTING_MANAGER_STUB_HOST
#include <boost/asio/io_service.hpp>
+#include <vsomeip/handler.hpp>
namespace vsomeip {
@@ -20,7 +21,7 @@ public:
minor_version_t _minor) = 0;
virtual void stop_offer_service(client_t _client, service_t _service,
- instance_t _instance) = 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,
@@ -29,17 +30,24 @@ public:
virtual void release_service(client_t _client, service_t _service,
instance_t _instance) = 0;
- virtual void register_event(client_t _client, service_t _service,
+ virtual void register_shadow_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) = 0;
- virtual void unregister_event(client_t _client, service_t _service,
+ virtual void unregister_shadow_event(client_t _client, service_t _service,
instance_t _instance, event_t _event, bool _is_provided) = 0;
virtual void subscribe(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
- major_version_t _major, subscription_type_e _subscription_type) = 0;
+ major_version_t _major,
+ subscription_type_e _subscription_type) = 0;
+
+ virtual void on_subscribe_nack(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) = 0;
+
+ virtual void on_subscribe_ack(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) = 0;
virtual void unsubscribe(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup) = 0;
@@ -49,20 +57,23 @@ public:
virtual void on_notification(client_t _client,
service_t _service, instance_t _instance,
- const byte_t *_data, length_t _size) = 0;
+ const byte_t *_data, length_t _size, bool _notify_one = false) = 0;
virtual void on_stop_offer_service(service_t _service,
- instance_t _instance) = 0;
+ instance_t _instance, major_version_t _major,
+ minor_version_t _minor) = 0;
virtual std::shared_ptr<endpoint> find_local(client_t _client) = 0;
- virtual std::shared_ptr<endpoint> find_local(service_t _service,
- instance_t _instance) = 0;
+
virtual std::shared_ptr<endpoint> find_or_create_local(
client_t _client) = 0;
virtual void remove_local(client_t _client) = 0;
virtual boost::asio::io_service & get_io() = 0;
virtual client_t get_client() const = 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/serviceinfo.hpp b/implementation/routing/include/serviceinfo.hpp
index af3a50c..44050b8 100644
--- a/implementation/routing/include/serviceinfo.hpp
+++ b/implementation/routing/include/serviceinfo.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -9,6 +9,7 @@
#include <memory>
#include <set>
#include <string>
+#include <chrono>
#include <vsomeip/export.hpp>
#include <vsomeip/primitive_types.hpp>
@@ -33,21 +34,16 @@ public:
VSOMEIP_EXPORT ttl_t get_ttl() const;
VSOMEIP_EXPORT void set_ttl(ttl_t _ttl);
+ VSOMEIP_EXPORT std::chrono::milliseconds get_precise_ttl() const;
+ VSOMEIP_EXPORT void set_precise_ttl(std::chrono::milliseconds _ttl);
+
VSOMEIP_EXPORT std::shared_ptr<endpoint> get_endpoint(bool _reliable) const;
VSOMEIP_EXPORT void set_endpoint(std::shared_ptr<endpoint> _endpoint,
bool _reliable);
- VSOMEIP_EXPORT const std::string & get_multicast_address() const;
- VSOMEIP_EXPORT void set_multicast_address(const std::string &_multicast);
-
- VSOMEIP_EXPORT uint16_t get_multicast_port() const;
- VSOMEIP_EXPORT void set_multicast_port(uint16_t _port);
-
- VSOMEIP_EXPORT eventgroup_t get_multicast_group() const;
- VSOMEIP_EXPORT void set_multicast_group(eventgroup_t _multicast_group);
-
VSOMEIP_EXPORT void add_client(client_t _client);
VSOMEIP_EXPORT void remove_client(client_t _client);
+ VSOMEIP_EXPORT uint32_t get_requesters_size();
VSOMEIP_EXPORT bool is_local() const;
@@ -56,15 +52,11 @@ private:
major_version_t major_;
minor_version_t minor_;
- ttl_t ttl_;
+ std::chrono::milliseconds ttl_;
std::shared_ptr<endpoint> reliable_;
std::shared_ptr<endpoint> unreliable_;
- std::string multicast_address_;
- uint16_t multicast_port_;
- eventgroup_t multicast_group_;
-
std::set<client_t> requesters_;
bool is_local_;
diff --git a/implementation/routing/include/types.hpp b/implementation/routing/include/types.hpp
index 60b97bc..c483aee 100644
--- a/implementation/routing/include/types.hpp
+++ b/implementation/routing/include/types.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/routing/src/event.cpp b/implementation/routing/src/event.cpp
index b553415..d536597 100644
--- a/implementation/routing/src/event.cpp
+++ b/implementation/routing/src/event.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -16,13 +16,16 @@
namespace vsomeip {
-event::event(routing_manager *_routing) :
+event::event(routing_manager *_routing, bool _is_shadow) :
routing_(_routing),
message_(runtime::get()->create_notification()),
+ is_field_(false),
cycle_timer_(_routing->get_io()),
is_updating_on_change_(true),
is_set_(false),
- ref_(0) {
+ is_provided_(false),
+ is_shadow_(_is_shadow),
+ is_cache_placeholder_(false) {
}
service_t event::get_service() const {
@@ -73,10 +76,31 @@ void event::set_provided(bool _is_provided) {
is_provided_ = _is_provided;
}
+bool event::is_set() const {
+ return is_set_;
+}
+
const std::shared_ptr<payload> event::get_payload() const {
return (message_->get_payload());
}
+void event::set_payload_dont_notify(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);
+ 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);
+ }
+ }
+}
+
void event::set_payload(std::shared_ptr<payload> _payload) {
if (is_provided_) {
if (set_payload_helper(_payload)) {
@@ -89,6 +113,9 @@ void event::set_payload(std::shared_ptr<payload> _payload) {
notify();
}
}
+ } else {
+ VSOMEIP_DEBUG << "Can't set payload for event " << std::hex
+ << message_->get_method() << " as it isn't provided";
}
}
@@ -103,6 +130,9 @@ void event::set_payload(std::shared_ptr<payload> _payload, client_t _client) {
if (is_updating_on_change_) {
notify_one(_client);
}
+ } else {
+ VSOMEIP_DEBUG << "Can't set payload for event " << std::hex
+ << message_->get_method() << " as it isn't provided";
}
}
@@ -119,13 +149,21 @@ void event::set_payload(std::shared_ptr<payload> _payload,
notify_one(_target);
}
}
+ } else {
+ VSOMEIP_DEBUG << "Can't set payload for event " << std::hex
+ << message_->get_method() << " as it isn't provided";
}
}
-void event::unset_payload() {
- if (is_provided_) {
+void event::unset_payload(bool _force) {
+ if(_force) {
is_set_ = false;
message_->set_payload(std::make_shared<payload_impl>());
+ } else {
+ if (is_provided_) {
+ is_set_ = false;
+ message_->set_payload(std::make_shared<payload_impl>());
+ }
}
}
@@ -177,17 +215,35 @@ void event::update_cbk(boost::system::error_code const &_error) {
void event::notify() {
if (is_set_) {
routing_->send(VSOMEIP_ROUTING_CLIENT, message_, true);
+ } else {
+ VSOMEIP_DEBUG << "Notify event " << std::hex << message_->get_method()
+ << "failed. Event payload not set!";
}
}
void event::notify_one(const std::shared_ptr<endpoint_definition> &_target) {
- if (is_set_)
+ if (is_set_) {
routing_->send_to(_target, message_);
+ } else {
+ VSOMEIP_DEBUG << "Notify one event " << std::hex << message_->get_method()
+ << "failed. Event payload not set!";
+ }
}
-void event::notify_one(client_t _client) {
- if (is_set_)
+void event::notify_one(client_t _client, bool _is_initial) {
+ 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) {
@@ -210,13 +266,54 @@ bool event::set_payload_helper(std::shared_ptr<payload> _payload) {
return is_change;
}
-void event::add_ref() {
- ref_++;
+void event::add_ref(client_t _client, bool _is_provided) {
+ auto its_client = refs_.find(_client);
+ if (its_client == refs_.end()) {
+ refs_[_client][_is_provided] = 1;
+ } else {
+ auto its_provided = its_client->second.find(_is_provided);
+ if (its_provided == its_client->second.end()) {
+ refs_[_client][_is_provided] = 1;
+ } else {
+ its_provided->second++;
+ }
+ }
+}
+
+void event::remove_ref(client_t _client, bool _is_provided) {
+ auto its_client = refs_.find(_client);
+ if (its_client != refs_.end()) {
+ auto its_provided = its_client->second.find(_is_provided);
+ if (its_provided != its_client->second.end()) {
+ its_provided->second--;
+ if (0 == its_provided->second) {
+ its_client->second.erase(_is_provided);
+ if (0 == its_client->second.size()) {
+ refs_.erase(_client);
+ }
+ }
+ }
+ }
+}
+
+bool event::has_ref() {
+ return refs_.size() != 0;
+}
+
+bool event::is_shadow() const {
+ return is_shadow_;
+}
+
+void event::set_shadow(bool _shadow) {
+ is_shadow_ = _shadow;
+}
+
+bool event::is_cache_placeholder() const {
+ return is_cache_placeholder_;
}
-uint32_t event::remove_ref() {
- ref_--;
- return ref_;
+void event::set_cache_placeholder(bool _is_cache_place_holder) {
+ is_cache_placeholder_ = _is_cache_place_holder;
}
} // namespace vsomeip
diff --git a/implementation/routing/src/eventgroupinfo.cpp b/implementation/routing/src/eventgroupinfo.cpp
index 0d098e4..1380969 100644
--- a/implementation/routing/src/eventgroupinfo.cpp
+++ b/implementation/routing/src/eventgroupinfo.cpp
@@ -1,20 +1,24 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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 <algorithm>
+
#include <vsomeip/constants.hpp>
+
#include "../include/eventgroupinfo.hpp"
+#include "../../endpoints/include/endpoint_definition.hpp"
namespace vsomeip {
eventgroupinfo::eventgroupinfo()
- : major_(DEFAULT_MAJOR), ttl_(DEFAULT_TTL), is_multicast_(false) {
+ : major_(DEFAULT_MAJOR), ttl_(DEFAULT_TTL) {
}
eventgroupinfo::eventgroupinfo(major_version_t _major, ttl_t _ttl)
- : major_(_major), ttl_(_ttl), is_multicast_(false) {
+ : major_(_major), ttl_(_ttl) {
}
eventgroupinfo::~eventgroupinfo() {
@@ -37,23 +41,24 @@ void eventgroupinfo::set_ttl(ttl_t _ttl) {
}
bool eventgroupinfo::is_multicast() const {
- return is_multicast_;
+ return address_.is_multicast();
}
bool eventgroupinfo::get_multicast(boost::asio::ip::address &_address,
uint16_t &_port) const {
- if (is_multicast_) {
+
+ if (address_.is_multicast()) {
_address = address_;
_port = port_;
+ return true;
}
- return is_multicast_;
+ return false;
}
void eventgroupinfo::set_multicast(const boost::asio::ip::address &_address,
uint16_t _port) {
address_ = _address;
port_ = _port;
- is_multicast_ = true;
}
const std::set<std::shared_ptr<event> > eventgroupinfo::get_events() const {
@@ -68,20 +73,77 @@ void eventgroupinfo::remove_event(std::shared_ptr<event> _event) {
events_.erase(_event);
}
-const std::set<std::shared_ptr<endpoint_definition> > eventgroupinfo::get_targets() const {
+const std::list<eventgroupinfo::target_t> eventgroupinfo::get_targets() const {
return targets_;
}
-bool eventgroupinfo::add_target(std::shared_ptr<endpoint_definition> _target) {
+uint32_t eventgroupinfo::get_unreliable_target_count(){
+ uint32_t _count(0);
+ for (auto i = targets_.begin(); i != targets_.end(); i++) {
+ if (!i->endpoint_->is_reliable()) {
+ _count++;
+ }
+ }
+ return _count;
+}
+
+void eventgroupinfo::add_multicast_target(const eventgroupinfo::target_t &_multicast_target) {
+ if (std::find(multicast_targets_.begin(), multicast_targets_.end(), _multicast_target)
+ == multicast_targets_.end()) {
+ multicast_targets_.push_back(_multicast_target);
+ }
+}
+
+void eventgroupinfo::clear_multicast_targets() {
+ multicast_targets_.clear();
+}
+
+const std::list<eventgroupinfo::target_t> eventgroupinfo::get_multicast_targets() const {
+ return multicast_targets_;
+}
+
+bool eventgroupinfo::add_target(const eventgroupinfo::target_t &_target) {
std::size_t its_size = targets_.size();
- targets_.insert(_target);
+ if (std::find(targets_.begin(), targets_.end(), _target) == targets_.end()) {
+ targets_.push_back(_target);
+ }
+ return (its_size != targets_.size());
+}
+
+bool eventgroupinfo::add_target(const eventgroupinfo::target_t &_target, const eventgroupinfo::target_t &_subscriber) {
+ 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());
}
+bool eventgroupinfo::update_target(
+ const std::shared_ptr<endpoint_definition> &_target,
+ const std::chrono::high_resolution_clock::time_point &_expiration) {
+ for (auto i = targets_.begin(); i != targets_.end(); i++) {
+ if (i->endpoint_ == _target) {
+ i->expiration_ = _expiration;
+ return true;
+ }
+ }
+ return false;
+}
+
bool eventgroupinfo::remove_target(
- std::shared_ptr<endpoint_definition> _target) {
+ const std::shared_ptr<endpoint_definition> &_target) {
std::size_t its_size = targets_.size();
- targets_.erase(_target);
+
+ for (auto i = targets_.begin(); i != targets_.end(); i++) {
+ if (i->endpoint_ == _target) {
+ targets_.erase(i);
+ break;
+ }
+ }
+
return (its_size != targets_.size());
}
diff --git a/implementation/routing/src/routing_manager_base.cpp b/implementation/routing/src/routing_manager_base.cpp
new file mode 100644
index 0000000..1a04a20
--- /dev/null
+++ b/implementation/routing/src/routing_manager_base.cpp
@@ -0,0 +1,782 @@
+// 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 <iomanip>
+
+#include "../../utility/include/utility.hpp"
+#include "../../utility/include/byteorder.hpp"
+#include "../include/routing_manager_base.hpp"
+#include "../../logging/include/logger.hpp"
+#include "../../endpoints/include/local_client_endpoint_impl.hpp"
+#include "../../endpoints/include/local_server_endpoint_impl.hpp"
+
+namespace vsomeip {
+
+routing_manager_base::routing_manager_base(routing_manager_host *_host) :
+ host_(_host),
+ io_(host_->get_io()),
+ client_(host_->get_client()),
+ configuration_(host_->get_configuration()),
+ serializer_(std::make_shared<serializer>()),
+ deserializer_(std::make_shared<deserializer>())
+#ifdef USE_DLT
+ , tc_(tc::trace_connector::get())
+#endif
+{
+}
+
+routing_manager_base::~routing_manager_base() {
+}
+
+boost::asio::io_service & routing_manager_base::get_io() {
+ return (io_);
+}
+
+client_t routing_manager_base::get_client() const {
+ return client_;
+}
+
+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,
+ instance_t _instance, major_version_t _major,
+ minor_version_t _minor) {
+ (void)_client;
+
+ // Remote route (incoming only)
+ auto its_info = find_service(_service, _instance);
+ if (its_info) {
+ 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);
+ }
+ } else {
+ its_info = create_service_info(_service, _instance, _major, _minor,
+ DEFAULT_TTL, true);
+ }
+}
+
+void routing_manager_base::stop_offer_service(client_t _client, service_t _service,
+ instance_t _instance, major_version_t _major, minor_version_t _minor) {
+ (void)_client;
+ (void)_major;
+ (void)_minor;
+ {
+ std::lock_guard<std::mutex> its_lock(events_mutex_);
+ auto its_events_service = events_.find(_service);
+ if (its_events_service != events_.end()) {
+ auto its_events_instance = its_events_service->second.find(_instance);
+ if (its_events_instance != its_events_service->second.end()) {
+ for (auto &e : its_events_instance->second)
+ e.second->unset_payload();
+ }
+ }
+ }
+ {
+ std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_);
+ auto its_service = eventgroup_clients_.find(_service);
+ if (its_service != eventgroup_clients_.end()) {
+ auto its_instance = its_service->second.find(_instance);
+ if (its_instance != its_service->second.end()) {
+ its_instance->second.clear();
+ }
+ }
+ }
+}
+
+void routing_manager_base::request_service(client_t _client, service_t _service,
+ instance_t _instance, major_version_t _major,
+ minor_version_t _minor, bool _use_exclusive_proxy) {
+ (void)_use_exclusive_proxy;
+
+ auto its_info = find_service(_service, _instance);
+ if (its_info) {
+ if ((_major == its_info->get_major()
+ || DEFAULT_MAJOR == its_info->get_major())
+ && (_minor <= its_info->get_minor()
+ || DEFAULT_MINOR == its_info->get_minor()
+ || _minor == ANY_MINOR)) {
+ its_info->add_client(_client);
+ } else {
+ host_->on_error(error_code_e::SERVICE_PROPERTY_MISMATCH);
+ }
+ }
+}
+
+void routing_manager_base::release_service(client_t _client, service_t _service,
+ instance_t _instance) {
+ auto its_info = find_service(_service, _instance);
+ if (its_info) {
+ its_info->remove_client(_client);
+ }
+}
+
+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) {
+ std::shared_ptr<event> its_event = find_event(_service, _instance, _event);
+ if (its_event) {
+ if(!its_event->is_cache_placeholder()) {
+ if (its_event->is_field() == _is_field) {
+ if (_is_provided) {
+ its_event->set_provided(true);
+ }
+ if (_is_shadow && _is_provided) {
+ its_event->set_shadow(_is_shadow);
+ }
+ for (auto eg : _eventgroups) {
+ its_event->add_eventgroup(eg);
+ }
+ } else {
+ VSOMEIP_ERROR << "Event registration update failed. "
+ "Specified arguments do not match existing registration.";
+ }
+ } else {
+ // the found event was a placeholder for caching.
+ // update it with the real values
+ if(!_is_field) {
+ // don't cache payload for non-fields
+ its_event->unset_payload(true);
+ }
+ if (_is_shadow && _is_provided) {
+ its_event->set_shadow(_is_shadow);
+ }
+ its_event->set_field(_is_field);
+ its_event->set_provided(_is_provided);
+ its_event->set_cache_placeholder(false);
+ std::shared_ptr<serviceinfo> its_service = find_service(_service, _instance);
+ if (its_service) {
+ its_event->set_version(its_service->get_major());
+ }
+ if (_eventgroups.size() == 0) { // No eventgroup specified
+ std::set<eventgroup_t> its_eventgroups;
+ its_eventgroups.insert(_event);
+ its_event->set_eventgroups(its_eventgroups);
+ } else {
+ its_event->set_eventgroups(_eventgroups);
+ }
+
+ }
+ } else {
+ its_event = std::make_shared<event>(this, _is_shadow);
+ its_event->set_service(_service);
+ its_event->set_instance(_instance);
+ its_event->set_event(_event);
+ its_event->set_field(_is_field);
+ its_event->set_provided(_is_provided);
+ its_event->set_cache_placeholder(_is_cache_placeholder);
+ std::shared_ptr<serviceinfo> its_service = find_service(_service, _instance);
+ if (its_service) {
+ its_event->set_version(its_service->get_major());
+ }
+
+ if (_eventgroups.size() == 0) { // No eventgroup specified
+ std::set<eventgroup_t> its_eventgroups;
+ its_eventgroups.insert(_event);
+ its_event->set_eventgroups(its_eventgroups);
+ } else {
+ its_event->set_eventgroups(_eventgroups);
+ }
+ }
+
+ if(!_is_cache_placeholder) {
+ its_event->add_ref(_client, _is_provided);
+ }
+
+ for (auto eg : _eventgroups) {
+ std::shared_ptr<eventgroupinfo> its_eventgroup_info
+ = find_eventgroup(_service, _instance, eg);
+ if (!its_eventgroup_info) {
+ its_eventgroup_info = std::make_shared<eventgroupinfo>();
+ std::lock_guard<std::mutex> its_lock(eventgroups_mutex_);
+ eventgroups_[_service][_instance][eg] = its_eventgroup_info;
+ }
+ its_eventgroup_info->add_event(its_event);
+ }
+
+ std::lock_guard<std::mutex> its_lock(events_mutex_);
+ events_[_service][_instance][_event] = its_event;
+}
+
+void routing_manager_base::unregister_event(client_t _client, service_t _service, instance_t _instance,
+ event_t _event, bool _is_provided) {
+ (void)_client;
+ std::lock_guard<std::mutex> its_lock(events_mutex_);
+ auto found_service = events_.find(_service);
+ if (found_service != events_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto found_event = found_instance->second.find(_event);
+ if (found_event != found_instance->second.end()) {
+ auto its_event = found_event->second;
+ its_event->remove_ref(_client, _is_provided);
+ if (!its_event->has_ref()) {
+ auto its_eventgroups = its_event->get_eventgroups();
+ for (auto eg : its_eventgroups) {
+ std::shared_ptr<eventgroupinfo> its_eventgroup_info
+ = find_eventgroup(_service, _instance, eg);
+ if (its_eventgroup_info) {
+ its_eventgroup_info->remove_event(its_event);
+ if (0 == its_eventgroup_info->get_events().size()) {
+ remove_eventgroup_info(_service, _instance, eg);
+ }
+ }
+ }
+ found_instance->second.erase(_event);
+ } else if (_is_provided) {
+ its_event->set_provided(false);
+ }
+ }
+ }
+ }
+}
+
+std::shared_ptr<event> routing_manager_base::get_event(
+ service_t _service, instance_t _instance, event_t _event) const {
+ std::shared_ptr<event> its_event;
+ std::lock_guard<std::mutex> its_lock(events_mutex_);
+ auto found_service = events_.find(_service);
+ if (found_service != events_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto found_event = found_instance->second.find(_event);
+ if (found_event != found_instance->second.end()) {
+ return found_event->second;
+ }
+ }
+ }
+ return its_event;
+}
+
+
+std::set<std::shared_ptr<event>> routing_manager_base::find_events(
+ service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup) const {
+ std::lock_guard<std::mutex> its_lock(eventgroups_mutex_);
+ std::set<std::shared_ptr<event> > its_events;
+ auto found_service = eventgroups_.find(_service);
+ if (found_service != eventgroups_.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()) {
+ return (found_eventgroup->second->get_events());
+ }
+ }
+ }
+ return (its_events);
+}
+
+void routing_manager_base::subscribe(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup,
+ major_version_t _major,
+ subscription_type_e _subscription_type) {
+
+ (void) _major;
+ (void) _subscription_type;
+
+ bool inserted = insert_subscription(_service, _instance, _eventgroup, _client);
+ if (inserted) {
+ 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);
+ }
+ }
+ }
+}
+
+void routing_manager_base::unsubscribe(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) {
+ std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_);
+ auto its_service = eventgroup_clients_.find(_service);
+ if (its_service != eventgroup_clients_.end()) {
+ auto its_instance = its_service->second.find(_instance);
+ if (its_instance != its_service->second.end()) {
+ auto its_group = its_instance->second.find(_eventgroup);
+ if (its_group != its_instance->second.end()) {
+ its_group->second.erase(_client);
+ }
+ }
+ }
+}
+
+void routing_manager_base::notify(service_t _service, instance_t _instance,
+ event_t _event, std::shared_ptr<payload> _payload) {
+ std::shared_ptr<event> its_event = find_event(_service, _instance, _event);
+ if (its_event) {
+ its_event->set_payload(_payload);
+ } else {
+ VSOMEIP_WARNING << "Attempt to update the undefined event/field ["
+ << std::hex << _service << "." << _instance << "." << _event
+ << "]";
+ }
+}
+
+void routing_manager_base::notify_one(service_t _service, instance_t _instance,
+ event_t _event, std::shared_ptr<payload> _payload, client_t _client) {
+ 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) {
+ its_event->set_payload(_payload, _client);
+ }
+ } else {
+ VSOMEIP_WARNING << "Attempt to update the undefined event/field ["
+ << std::hex << _service << "." << _instance << "." << _event
+ << "]";
+ }
+}
+
+bool routing_manager_base::send(client_t its_client,
+ std::shared_ptr<message> _message,
+ bool _flush) {
+ bool is_sent(false);
+ if (utility::is_request(_message->get_message_type())) {
+ _message->set_client(its_client);
+ }
+ std::lock_guard<std::mutex> its_lock(serialize_mutex_);
+ 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());
+ serializer_->reset();
+ } else {
+ VSOMEIP_ERROR << "Failed to serialize message. Check message size!";
+ }
+ return (is_sent);
+}
+
+// ********************************* PROTECTED **************************************
+std::shared_ptr<serviceinfo> routing_manager_base::create_service_info(
+ service_t _service, instance_t _instance, major_version_t _major,
+ minor_version_t _minor, ttl_t _ttl, bool _is_local_service) {
+ std::lock_guard<std::mutex> its_lock(services_mutex_);
+ std::shared_ptr<serviceinfo> its_info =
+ std::make_shared<serviceinfo>(_major, _minor, _ttl, _is_local_service);
+ services_[_service][_instance] = its_info;
+ return its_info;
+}
+
+std::shared_ptr<serviceinfo> routing_manager_base::find_service(
+ service_t _service, instance_t _instance) const {
+ std::shared_ptr<serviceinfo> its_info;
+ std::lock_guard<std::mutex> its_lock(services_mutex_);
+ auto found_service = services_.find(_service);
+ if (found_service != services_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ its_info = found_instance->second;
+ }
+ }
+ return (its_info);
+}
+
+void routing_manager_base::clear_service_info(service_t _service, instance_t _instance,
+ bool _reliable) {
+ std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance));
+ if (!its_info) {
+ return;
+ }
+ // Clear service_info and service_group
+ std::shared_ptr<endpoint> its_empty_endpoint;
+ if (!its_info->get_endpoint(!_reliable)) {
+ if (1 >= services_[_service].size()) {
+ services_.erase(_service);
+ } else {
+ services_[_service].erase(_instance);
+ }
+ } else {
+ its_info->set_endpoint(its_empty_endpoint, _reliable);
+ }
+}
+
+services_t routing_manager_base::get_services() const {
+ services_t its_offers;
+ std::lock_guard<std::mutex> its_lock(services_mutex_);
+ for (auto s : services_) {
+ for (auto i : s.second) {
+ its_offers[s.first][i.first] = i.second;
+ }
+ }
+ return (its_offers);
+}
+
+bool routing_manager_base::is_available(service_t _service, instance_t _instance,
+ major_version_t _major) {
+ bool available(false);
+ std::lock_guard<std::mutex> its_lock(local_services_mutex_);
+ auto its_service = local_services_.find(_service);
+ if (its_service != local_services_.end()) {
+ auto its_instance = its_service->second.find(_instance);
+ if (its_instance != its_service->second.end()) {
+ if (std::get<0>(its_instance->second) == _major) {
+ available = true;
+ }
+ }
+ }
+ return available;
+}
+
+client_t routing_manager_base::find_local_client(service_t _service, instance_t _instance) {
+ std::lock_guard<std::mutex> its_lock(local_services_mutex_);
+ client_t its_client(VSOMEIP_ROUTING_CLIENT);
+ auto its_service = local_services_.find(_service);
+ if (its_service != local_services_.end()) {
+ auto its_instance = its_service->second.find(_instance);
+ if (its_instance != its_service->second.end()) {
+ its_client = std::get<2>(its_instance->second);
+ }
+ }
+ return its_client;
+}
+
+std::shared_ptr<endpoint> routing_manager_base::create_local(client_t _client) {
+ std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
+
+ std::stringstream its_path;
+ its_path << VSOMEIP_BASE_PATH << std::hex << _client;
+
+#ifdef WIN32
+ boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1");
+ int port = VSOMEIP_INTERNAL_BASE_PORT + _client;
+ VSOMEIP_DEBUG<< "Connecting to ["
+ << std::hex << _client << "] at " << port;
+#else
+ 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<
+ local_client_endpoint_impl>(shared_from_this(),
+#ifdef WIN32
+ boost::asio::ip::tcp::endpoint(address, port)
+#else
+ boost::asio::local::stream_protocol::endpoint(its_path.str())
+#endif
+ , io_, configuration_->get_max_message_size_local());
+
+ if (_client != VSOMEIP_ROUTING_CLIENT) {
+ // VSOMEIP_ROUTING_CLIENT must not be added here.
+ // The routing master should not get an end-point when calling find_local
+ // with VSOMEIP_ROUTING_CLIENT as parameter
+ // as it indicates remote communication!
+
+ local_endpoints_[_client] = its_endpoint;
+ }
+
+ return (its_endpoint);
+}
+
+std::shared_ptr<endpoint> routing_manager_base::find_local(client_t _client) {
+ std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
+ std::shared_ptr<endpoint> its_endpoint;
+ auto found_endpoint = local_endpoints_.find(_client);
+ if (found_endpoint != local_endpoints_.end()) {
+ its_endpoint = found_endpoint->second;
+ }
+ return (its_endpoint);
+}
+
+std::shared_ptr<endpoint> routing_manager_base::find_or_create_local(client_t _client) {
+ std::shared_ptr<endpoint> its_endpoint(find_local(_client));
+ if (!its_endpoint) {
+ its_endpoint = create_local(_client);
+ its_endpoint->start();
+ }
+ return (its_endpoint);
+}
+
+void routing_manager_base::remove_local(client_t _client) {
+ std::shared_ptr<endpoint> its_endpoint(find_local(_client));
+ if (its_endpoint) {
+ its_endpoint->stop();
+ VSOMEIP_DEBUG << "Client [" << std::hex << get_client() << "] is closing connection to ["
+ << std::hex << _client << "]";
+ std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
+ local_endpoints_.erase(_client);
+ }
+ {
+ std::lock_guard<std::mutex> its_lock(local_services_mutex_);
+ // Finally remove all services that are implemented by the client.
+ std::set<std::pair<service_t, instance_t>> its_services;
+ for (auto& s : local_services_) {
+ for (auto& i : s.second) {
+ if (std::get<2>(i.second) == _client)
+ its_services.insert({ s.first, i.first });
+ }
+ }
+
+ for (auto& si : its_services) {
+ local_services_[si.first].erase(si.second);
+ if (local_services_[si.first].size() == 0)
+ local_services_.erase(si.first);
+ }
+ }
+ // delete client's subscriptions if he didn't unsubscribe properly
+ {
+ std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_);
+ for (auto service_it = eventgroup_clients_.begin();
+ service_it != eventgroup_clients_.end();) {
+ for (auto instance_it = service_it->second.begin();
+ instance_it != service_it->second.end();) {
+ for (auto eventgroup_it = instance_it->second.begin();
+ eventgroup_it != instance_it->second.end();) {
+ if (eventgroup_it->second.erase(_client) > 0) {
+ if (eventgroup_it->second.size() == 0) {
+ eventgroup_it = instance_it->second.erase(eventgroup_it);
+ } else {
+ ++eventgroup_it;
+ }
+ } else {
+ ++eventgroup_it;
+ }
+ }
+
+ if (instance_it->second.size() == 0) {
+ instance_it = service_it->second.erase(instance_it);
+ } else {
+ ++instance_it;
+ }
+ }
+
+ if (service_it->second.size() == 0) {
+ service_it = eventgroup_clients_.erase(service_it);
+ } else {
+ ++service_it;
+ }
+ }
+ }
+}
+
+std::shared_ptr<endpoint> routing_manager_base::find_local(service_t _service,
+ instance_t _instance) {
+ return find_local(find_local_client(_service, _instance));
+}
+
+std::unordered_set<client_t> routing_manager_base::get_connected_clients() {
+ std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
+ std::unordered_set<client_t> clients;
+ for (auto its_client : local_endpoints_) {
+ clients.insert(its_client.first);
+ }
+ return clients;
+}
+
+std::shared_ptr<event> routing_manager_base::find_event(service_t _service,
+ instance_t _instance, event_t _event) const {
+ std::shared_ptr<event> its_event;
+ std::lock_guard<std::mutex> its_lock(events_mutex_);
+ auto find_service = events_.find(_service);
+ if (find_service != events_.end()) {
+ auto find_instance = find_service->second.find(_instance);
+ if (find_instance != find_service->second.end()) {
+ auto find_event = find_instance->second.find(_event);
+ if (find_event != find_instance->second.end()) {
+ its_event = find_event->second;
+ }
+ }
+ }
+ return (its_event);
+}
+
+std::shared_ptr<eventgroupinfo> routing_manager_base::find_eventgroup(
+ service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup) const {
+ std::lock_guard<std::mutex> its_lock(eventgroups_mutex_);
+
+ std::shared_ptr<eventgroupinfo> its_info(nullptr);
+ auto found_service = eventgroups_.find(_service);
+ if (found_service != eventgroups_.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()) {
+ its_info = found_eventgroup->second;
+ std::shared_ptr<serviceinfo> its_service_info
+ = find_service(_service, _instance);
+ if (its_service_info) {
+ std::string its_multicast_address;
+ uint16_t its_multicast_port;
+ if (configuration_->get_multicast(_service, _instance,
+ _eventgroup,
+ its_multicast_address, its_multicast_port)) {
+ try {
+ its_info->set_multicast(
+ boost::asio::ip::address::from_string(
+ its_multicast_address),
+ its_multicast_port);
+ }
+ catch (...) {
+ VSOMEIP_ERROR << "Eventgroup ["
+ << std::hex << std::setw(4) << std::setfill('0')
+ << _service << "." << _instance << "." << _eventgroup
+ << "] is configured as multicast, but no valid "
+ "multicast address is configured!";
+ }
+ }
+ its_info->set_major(its_service_info->get_major());
+ its_info->set_ttl(its_service_info->get_ttl());
+ }
+ }
+ }
+ }
+ return (its_info);
+}
+
+void routing_manager_base::remove_eventgroup_info(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) {
+ std::lock_guard<std::mutex> its_lock(eventgroups_mutex_);
+ auto found_service = eventgroups_.find(_service);
+ if (found_service != eventgroups_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ found_instance->second.erase(_eventgroup);
+ }
+ }
+}
+
+std::set<client_t> routing_manager_base::find_local_clients(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) {
+ std::set<client_t> its_clients;
+ std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_);
+ auto found_service = eventgroup_clients_.find(_service);
+ if (found_service != eventgroup_clients_.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()) {
+ its_clients = found_eventgroup->second;
+ }
+ }
+ }
+ return (its_clients);
+}
+
+void 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) {
+ 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(
+ _data[VSOMEIP_SERVICE_POS_MIN], _data[VSOMEIP_SERVICE_POS_MAX]);
+ std::shared_ptr<event> its_event = find_event(its_service, _instance, its_method);
+ if (its_event && !its_event->is_shadow()) {
+ std::vector< byte_t > its_data;
+
+ for (auto its_group : its_event->get_eventgroups()) {
+ // 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);
+ }
+ }
+ }
+ }
+ }
+}
+
+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
+
+ std::vector<byte_t> its_command(
+ VSOMEIP_COMMAND_HEADER_SIZE + _size + sizeof(instance_t)
+ + 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));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &_size,
+ sizeof(_size));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], _data,
+ _size);
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size],
+ &_instance, sizeof(instance_t));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size
+ + 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()));
+ }
+}
+
+bool routing_manager_base::insert_subscription(
+ service_t _service, instance_t _instance, eventgroup_t _eventgroup,
+ client_t _client) {
+ std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_);
+ auto found_service = eventgroup_clients_.find(_service);
+ if (found_service != eventgroup_clients_.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()) {
+ if (found_eventgroup->second.find(_client)
+ != found_eventgroup->second.end())
+ return false;
+ }
+ }
+ }
+
+ eventgroup_clients_[_service][_instance][_eventgroup].insert(_client);
+ return true;
+}
+
+} // namespace vsomeip
diff --git a/implementation/routing/src/routing_manager_impl.cpp b/implementation/routing/src/routing_manager_impl.cpp
index 13ec332..3c98334 100644
--- a/implementation/routing/src/routing_manager_impl.cpp
+++ b/implementation/routing/src/routing_manager_impl.cpp
@@ -1,8 +1,9 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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 <climits>
#include <iomanip>
#include <memory>
#include <sstream>
@@ -40,26 +41,22 @@
namespace vsomeip {
routing_manager_impl::routing_manager_impl(routing_manager_host *_host) :
- host_(_host),
- io_(_host->get_io()),
- deserializer_(std::make_shared<deserializer>()),
- serializer_(std::make_shared<serializer>()),
- configuration_(host_->get_configuration()) {
+ routing_manager_base(_host) {
}
routing_manager_impl::~routing_manager_impl() {
}
boost::asio::io_service & routing_manager_impl::get_io() {
- return (io_);
+ return routing_manager_base::get_io();
}
client_t routing_manager_impl::get_client() const {
- return host_->get_client();
+ return routing_manager_base::get_client();
}
void routing_manager_impl::init() {
- serializer_->create_data(configuration_->get_max_message_size_local());
+ routing_manager_base::init();
// TODO: Only instantiate the stub if needed
stub_ = std::make_shared<routing_manager_stub>(this, configuration_);
@@ -99,134 +96,184 @@ void routing_manager_impl::stop() {
if (discovery_)
discovery_->stop();
stub_->stop();
+
+ for (auto client: get_connected_clients()) {
+ if (client != VSOMEIP_ROUTING_CLIENT) {
+ remove_local(client);
+ }
+ }
}
void 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;
+ std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance);
+
{
- std::lock_guard<std::mutex> its_lock(local_mutex_);
- local_services_[_service][_instance] = _client;
+ std::lock_guard<std::mutex> its_lock(local_services_mutex_);
+ local_services_[_service][_instance] = std::make_tuple(_major, _minor, _client);
+ }
- // Remote route (incoming only)
- its_info = find_service(_service, _instance);
- if (its_info) {
- 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);
+ routing_manager_base::offer_service(_client, _service, _instance, _major, _minor);
+ init_service_info(_service, _instance, true);
+
+ {
+ std::lock_guard<std::mutex> its_lock(events_mutex_);
+ // Set major version for all registered events of this service and instance
+ auto find_service = events_.find(_service);
+ if (find_service != events_.end()) {
+ auto find_instance = find_service->second.find(_instance);
+ if (find_instance != find_service->second.end()) {
+ for (auto j : find_instance->second) {
+ j.second->set_version(_major);
+ }
}
- } else {
- its_info = create_service_info(_service, _instance, _major, _minor,
- DEFAULT_TTL, true);
}
}
- if (discovery_ && its_info) {
+ if (discovery_) {
discovery_->on_offer_change();
}
- stub_->on_offer_service(_client, _service, _instance);
- host_->on_availability(_service, _instance, true);
+ stub_->on_offer_service(_client, _service, _instance, _major, _minor);
+ host_->on_availability(_service, _instance, true, _major, _minor);
}
void routing_manager_impl::stop_offer_service(client_t _client,
- service_t _service, instance_t _instance) {
- on_stop_offer_service(_service, _instance);
- stub_->on_stop_offer_service(_client, _service, _instance);
+ service_t _service, instance_t _instance,
+ major_version_t _major, minor_version_t _minor) {
+ routing_manager_base::stop_offer_service(_client, _service, _instance, _major, _minor);
+ on_stop_offer_service(_service, _instance, _major, _minor);
+ stub_->on_stop_offer_service(_client, _service, _instance, _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) {
- std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance));
- if (its_info) {
+ routing_manager_base::request_service(_client, _service, _instance, _major,
+ _minor, _use_exclusive_proxy);
+
+ auto its_info = find_service(_service, _instance);
+ if (!its_info) {
+ {
+ 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);
+ }
+ } else {
if ((_major == its_info->get_major()
|| DEFAULT_MAJOR == its_info->get_major())
&& (_minor <= its_info->get_minor()
- || DEFAULT_MINOR == its_info->get_minor())) {
- its_info->add_client(_client);
- } else {
- host_->on_error(error_code_e::SERVICE_PROPERTY_MISMATCH);
+ || DEFAULT_MINOR == its_info->get_minor()
+ || _minor == ANY_MINOR)) {
+ if(!its_info->is_local()) {
+ 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);
+ if(its_endpoint) {
+ find_or_create_remote_client(_service, _instance, true, _client);
+ }
+ }
+ }
}
- } else {
- if (discovery_)
- discovery_->request_service(_service, _instance, _major, _minor,
- DEFAULT_TTL);
}
- // TODO: Mutex?!
if (_use_exclusive_proxy) {
- specific_endpoint_clients.insert(_client);
+ std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_);
+ specific_endpoint_clients_[_service][_instance].insert(_client);
}
}
void routing_manager_impl::release_service(client_t _client, service_t _service,
instance_t _instance) {
+ routing_manager_base::release_service(_client, _service, _instance);
std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance));
- if (its_info) {
- its_info->remove_client(_client);
+ if(its_info) {
+ if(!its_info->get_requesters_size()) {
+ if(discovery_) {
+ discovery_->release_service(_service, _instance);
+ }
+ }
} else {
- if (discovery_)
+ if(discovery_) {
discovery_->release_service(_service, _instance);
+ }
}
}
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) {
- if (discovery_) {
+ if (get_client() == find_local_client(_service, _instance)) {
if (!host_->on_subscription(_service, _instance, _eventgroup, _client, true)) {
- VSOMEIP_INFO << "Subscription request for eventgroup " << _eventgroup
- << " rejected from application handler";
+ on_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);
}
-
- if (insert_subscription(_service, _instance, _eventgroup, _client)) {
- if (0 == find_local_client(_service, _instance)) {
- client_t subscriber = VSOMEIP_ROUTING_CLIENT;
- // subscriber != VSOMEIP_ROUTING_CLIENT implies to use its own endpoint
- auto its_selective = specific_endpoint_clients.find(_client);
- if (its_selective != specific_endpoint_clients.end()) {
- subscriber = _client;
- }
- discovery_->subscribe(_service, _instance, _eventgroup,
- _major, DEFAULT_TTL, subscriber, _subscription_type);
- } else {
- send_subscribe(_client, _service, _instance, _eventgroup, _major);
-
- std::shared_ptr<eventgroupinfo> 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);
+ 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 << ".";
+ }
+ }
+ }
+ }
}
+ discovery_->subscribe(_service, _instance, _eventgroup,
+ _major, DEFAULT_TTL, subscriber, _subscription_type);
+ } else {
+ stub_->send_subscribe(routing_manager_base::find_local(_service, _instance),
+ _client, _service, _instance, _eventgroup, _major, false);
}
}
+ } else {
+ VSOMEIP_ERROR<< "SOME/IP eventgroups require SD to be enabled!";
}
- } else {
- VSOMEIP_ERROR<< "SOME/IP eventgroups require SD to be enabled!";
}
}
void routing_manager_impl::unsubscribe(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup) {
if (discovery_) {
- auto found_service = eventgroup_clients_.find(_service);
- if (found_service != eventgroup_clients_.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()) {
- found_eventgroup->second.erase(_client);
- if (0 == found_eventgroup->second.size()) {
- eventgroup_clients_.erase(_eventgroup);
+ {
+ std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_);
+ auto found_service = eventgroup_clients_.find(_service);
+ if (found_service != eventgroup_clients_.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()) {
+ found_eventgroup->second.erase(_client);
+ if (0 == found_eventgroup->second.size()) {
+ eventgroup_clients_.erase(_eventgroup);
+ }
}
}
}
@@ -235,13 +282,23 @@ void routing_manager_impl::unsubscribe(client_t _client, service_t _service,
if (0 == find_local_client(_service, _instance)) {
client_t subscriber = VSOMEIP_ROUTING_CLIENT;
// subscriber != VSOMEIP_ROUTING_CLIENT implies to use its own endpoint
- auto its_selective = specific_endpoint_clients.find(_client);
- if (its_selective != specific_endpoint_clients.end()) {
- subscriber = _client;
+ {
+ std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_);
+ auto found_service = specific_endpoint_clients_.find(_service);
+ if (found_service != specific_endpoint_clients_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto found_client = found_instance->second.find(_client);
+ if(found_client != found_instance->second.end()) {
+ subscriber = _client;
+ }
+ }
+ }
}
discovery_->unsubscribe(_service, _instance, _eventgroup, subscriber);
} else {
- send_unsubscribe(_client, _service, _instance, _eventgroup);
+ stub_->send_unsubscribe(routing_manager_base::find_local(_service, _instance),
+ _client, _service, _instance, _eventgroup);
}
clear_multicast_endpoints(_service, _instance);
} else {
@@ -249,30 +306,14 @@ void routing_manager_impl::unsubscribe(client_t _client, service_t _service,
}
}
-bool routing_manager_impl::send(client_t its_client,
+bool routing_manager_impl::send(client_t _client,
std::shared_ptr<message> _message, bool _flush) {
- bool is_sent(false);
-
- if (utility::is_request(_message->get_message_type())) {
- _message->set_client(its_client);
- }
-
- std::lock_guard<std::mutex> its_lock(serialize_mutex_);
- if (serializer_->serialize(_message.get())) {
- is_sent = send(its_client, serializer_->get_data(),
- serializer_->get_size(), _message->get_instance(),
- _flush, _message->is_reliable());
- serializer_->reset();
- } else {
- VSOMEIP_ERROR << "Failed to serialize message. Check message size!";
- }
-
- return (is_sent);
+ 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 _flush, bool _reliable, bool _initial) {
bool is_sent(false);
std::shared_ptr<endpoint> its_target;
@@ -291,16 +332,20 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data,
if (_size > VSOMEIP_MESSAGE_TYPE_POS) {
if (is_request) {
- its_target = find_local(its_service, _instance);
+ its_target = routing_manager_base::find_local(its_service, _instance);
} else if (!is_notification) {
its_target = find_local(its_client);
} else if (is_notification && _client) {
// Selective notifications!
+ if (_client == get_client()) {
+ deliver_message(_data, _size, _instance, _reliable);
+ return true;
+ }
its_target = find_local(_client);
}
if (its_target) {
- is_sent = send_local(its_target, _client, _data, _size, _instance, _flush, _reliable);
+ is_sent = send_local(its_target, _client, _data, _size, _instance, _flush, _reliable, VSOMEIP_SEND, false, _initial);
} else {
// Check whether hosting application should get the message
// If not, check routes to external
@@ -312,19 +357,39 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data,
} else {
if (is_request) {
client_t client = VSOMEIP_ROUTING_CLIENT;
- if (specific_endpoint_clients.find(its_client) != specific_endpoint_clients.end()) {
- client = its_client;
+ {
+ std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_);
+ auto found_service = specific_endpoint_clients_.find(its_service);
+ if (found_service != specific_endpoint_clients_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto found_client = found_instance->second.find(its_client);
+ if (found_client != found_instance->second.end()) {
+ client = its_client;
+ }
+ }
+ }
}
its_target = find_or_create_remote_client(its_service, _instance, _reliable, client);
if (its_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_target, true))
+ tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
+ _data, its_data_size);
+#endif
is_sent = its_target->send(_data, _size, _flush);
} else {
VSOMEIP_ERROR<< "Routing error. Client from remote service could not be found!";
}
} else {
std::shared_ptr<serviceinfo> its_info(find_service(its_service, _instance));
- if (its_info) {
+ if (its_info || is_service_discovery) {
if (is_notification && !is_service_discovery) {
+ send_local_notification(get_client(), _data, _size, _instance, _flush, _reliable);
method_t its_method = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN],
_data[VSOMEIP_METHOD_POS_MAX]);
std::shared_ptr<event> its_event = find_event(its_service, _instance, its_method);
@@ -332,21 +397,6 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data,
std::vector< byte_t > its_data;
for (auto its_group : its_event->get_eventgroups()) {
- // 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()) {
- its_local_client = VSOMEIP_ROUTING_CLIENT;
- }
-
- 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);
- }
- }
// we need both endpoints as clients can subscribe to events via TCP and UDP
std::shared_ptr<endpoint> its_unreliable_target = its_info->get_endpoint(false);
std::shared_ptr<endpoint> its_reliable_target = its_info->get_endpoint(true);
@@ -354,11 +404,37 @@ 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
for (auto its_remote : its_eventgroup->get_targets()) {
- if(its_remote->is_reliable() && its_reliable_target) {
- its_reliable_target->send_to(its_remote, _data, _size);
- } else if(its_unreliable_target) {
- its_unreliable_target->send_to(its_remote, _data, _size);
+ 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
+ its_unreliable_target->send_to(its_remote.endpoint_, _data, _size);
+ }
+ }
+ //send to multicast targets if subscribers are still interested
+ if(its_eventgroup->is_multicast()
+ && its_eventgroup->get_unreliable_target_count() > 0 ) {
+ for (auto its_multicast_target : its_eventgroup->get_multicast_targets()) {
+ its_unreliable_target->send_to(its_multicast_target.endpoint_, _data, _size);
}
}
}
@@ -366,8 +442,17 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data,
}
}
} else {
- its_target = its_info->get_endpoint(_reliable);
+ its_target = is_service_discovery ? sd_info_->get_endpoint(false) : its_info->get_endpoint(_reliable);
if (its_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_target, true))
+ tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
+ _data, its_data_size);
+#endif
is_sent = its_target->send(_data, _size, _flush);
} else {
VSOMEIP_ERROR << "Routing error. Endpoint for service ["
@@ -390,34 +475,6 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data,
return (is_sent);
}
-bool routing_manager_impl::send_local(
- std::shared_ptr<endpoint>& _target, client_t _client,
- const byte_t *_data, uint32_t _size,
- instance_t _instance,
- bool _flush, bool _reliable) const {
-
- std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
-
- std::vector<byte_t> its_command(
- VSOMEIP_COMMAND_HEADER_SIZE + _size + sizeof(instance_t)
- + sizeof(bool) + sizeof(bool));
- its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SEND;
- std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client,
- sizeof(client_t));
- std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &_size,
- sizeof(_size));
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], _data,
- _size);
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size],
- &_instance, sizeof(instance_t));
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size
- + sizeof(instance_t)], &_flush, sizeof(bool));
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size
- + sizeof(instance_t) + sizeof(bool)], &_reliable, sizeof(bool));
-
- return _target->send(&its_command[0], uint32_t(its_command.size()), _flush);
-}
-
bool routing_manager_impl::send_to(
const std::shared_ptr<endpoint_definition> &_target,
std::shared_ptr<message> _message) {
@@ -439,95 +496,56 @@ bool routing_manager_impl::send_to(
std::shared_ptr<endpoint> its_endpoint = find_server_endpoint(
_target->get_remote_port(), _target->is_reliable());
- return (its_endpoint && its_endpoint->send_to(_target, _data, _size));
-}
-
-void routing_manager_impl::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) {
- (void)_client;
- std::shared_ptr<event> its_event = find_event(_service, _instance, _event);
- if (its_event) {
- if (its_event->is_field() == _is_field) {
- if (_is_provided) {
- its_event->set_provided(true);
- }
- for (auto eg : _eventgroups) {
- its_event->add_eventgroup(eg);
- }
- } else {
- VSOMEIP_ERROR << "Event registration update failed. "
- "Specified arguments do not match existing registration.";
- }
- } else {
- its_event = std::make_shared<event>(this);
- its_event->set_service(_service);
- its_event->set_instance(_instance);
- its_event->set_event(_event);
- its_event->set_field(_is_field);
- its_event->set_provided(_is_provided);
- std::shared_ptr<serviceinfo> its_service = find_service(_service, _instance);
- if (its_service) {
- its_event->set_version(its_service->get_major());
- }
-
- if (_eventgroups.size() == 0) { // No eventgroup specified
- std::set<eventgroup_t> its_eventgroups;
- its_eventgroups.insert(_event);
- its_event->set_eventgroups(its_eventgroups);
- } else {
- its_event->set_eventgroups(_eventgroups);
- }
+ if (its_endpoint) {
+#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_endpoint, true))
+ tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
+ _data, its_data_size);
+#endif
+ return its_endpoint->send_to(_target, _data, _size);
}
+ return false;
+}
- its_event->add_ref();
+bool routing_manager_impl::send_to(const std::shared_ptr<endpoint_definition> &_target,
+ const byte_t *_data, uint32_t _size, uint16_t _sd_port) {
+ std::shared_ptr<endpoint> its_endpoint = find_server_endpoint(
+ _sd_port, _target->is_reliable());
- for (auto eg : _eventgroups) {
- std::shared_ptr<eventgroupinfo> its_eventgroup_info
- = find_eventgroup(_service, _instance, eg);
- if (!its_eventgroup_info) {
- its_eventgroup_info = std::make_shared<eventgroupinfo>();
- eventgroups_[_service][_instance][eg] = its_eventgroup_info;
- }
- its_eventgroup_info->add_event(its_event);
+ if (its_endpoint) {
+#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_endpoint, true))
+ tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
+ _data, its_data_size);
+#endif
+ return its_endpoint->send_to(_target, _data, _size);
}
- events_[_service][_instance][_event] = its_event;
+ return false;
}
-void routing_manager_impl::unregister_event(client_t _client,
+void routing_manager_impl::register_shadow_event(client_t _client,
service_t _service, instance_t _instance,
- event_t _event, bool _is_provided) {
- (void)_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);
+}
- auto found_service = events_.find(_service);
- if (found_service != events_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- auto found_event = found_instance->second.find(_event);
- if (found_event != found_instance->second.end()) {
- auto its_event = found_event->second;
- if (!its_event->remove_ref()) {
- auto its_eventgroups = its_event->get_eventgroups();
- for (auto eg : its_eventgroups) {
- std::shared_ptr<eventgroupinfo> its_eventgroup_info
- = find_eventgroup(_service, _instance, eg);
- if (its_eventgroup_info) {
- its_eventgroup_info->remove_event(its_event);
- if (0 == its_eventgroup_info->get_events().size()) {
- remove_eventgroup_info(_service, _instance, eg);
- }
- }
- }
- found_instance->second.erase(_event);
- } else if (_is_provided) {
- its_event->set_provided(false);
- }
- }
- }
- }
+void routing_manager_impl::unregister_shadow_event(client_t _client,
+ service_t _service, instance_t _instance,
+ event_t _event, bool _is_provided) {
+ routing_manager_base::unregister_event(_client, _service, _instance,
+ _event, _is_provided);
}
void routing_manager_impl::notify(
@@ -545,25 +563,46 @@ 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) {
-
- std::shared_ptr<event> its_event = find_event(_service, _instance, _event);
- if (its_event) {
- for (auto its_group : its_event->get_eventgroups()) {
- auto its_eventgroup = find_eventgroup(_service, _instance, its_group);
- if (its_eventgroup) {
- auto its_subscriber = remote_subscriber_map_.find(_client);
- if (its_subscriber != remote_subscriber_map_.end()) {
- its_event->set_payload(_payload, its_subscriber->second);
- } else {
- its_event->set_payload(_payload, _client);
- }
- }
- }
- } else {
- VSOMEIP_WARNING << "Attempt to update the undefined event/field ["
- << std::hex << _service << "." << _instance << "." << _event
- << "]";
- }
+ 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
+ << "]";
+ }
+ }
}
void routing_manager_impl::on_error(const byte_t *_data, length_t _length, endpoint *_receiver) {
@@ -577,8 +616,12 @@ void routing_manager_impl::on_error(const byte_t *_data, length_t _length, endpo
its_instance, _receiver->is_reliable(), _receiver);
}
+void routing_manager_impl::release_port(uint16_t _port, bool _reliable) {
+ used_client_ports_[_reliable].erase(_port);
+}
+
void routing_manager_impl::on_message(const byte_t *_data, length_t _size,
- endpoint *_receiver) {
+ endpoint *_receiver, const boost::asio::ip::address &_destination) {
#if 0
std::stringstream msg;
msg << "rmi::on_message: ";
@@ -587,36 +630,62 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size,
VSOMEIP_DEBUG << msg.str();
#endif
service_t its_service;
+ method_t its_method;
if (_size >= VSOMEIP_SOMEIP_HEADER_SIZE) {
its_service = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_SERVICE_POS_MIN],
_data[VSOMEIP_SERVICE_POS_MAX]);
if (its_service == VSOMEIP_SD_SERVICE) {
- if (discovery_) {
- boost::asio::ip::address its_address;
- if (_receiver->get_remote_address(its_address)) {
- discovery_->on_message(_data, _size, its_address);
+ its_method = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN],
+ _data[VSOMEIP_METHOD_POS_MAX]);
+ if (discovery_ && its_method == sd::method) {
+ if (configuration_->get_sd_port() == _receiver->get_remote_port()) {
+ boost::asio::ip::address its_address;
+ if (_receiver->get_remote_address(its_address)) {
+ discovery_->on_message(_data, _size, its_address, _destination);
+ } else {
+ VSOMEIP_ERROR << "Ignored SD message from unknown address.";
+ }
} else {
- VSOMEIP_ERROR << "Ignored SD message from unknown address.";
+ VSOMEIP_ERROR << "Ignored SD message from unknown port ("
+ << _receiver->get_remote_port() << ")";
}
}
} else {
instance_t its_instance = find_instance(its_service, _receiver);
return_code_e return_code = check_error(_data, _size, its_instance);
- if (return_code != return_code_e::E_OK) {
- if (return_code != return_code_e::E_NOT_OK) {
+ 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) {
send_error(return_code, _data, _size, its_instance,
_receiver->is_reliable(), _receiver);
+ return;
}
+ } else if(return_code != return_code_e::E_OK && return_code != return_code_e::E_NOT_OK) {
+ //Ignore request no response message if an error occured
return;
}
if (!deliver_specific_endpoint_message(
its_service, its_instance, _data, _size, _receiver)) {
+ // set client ID to zero for all messages
+ if( utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) {
+ byte_t *its_data = const_cast<byte_t *>(_data);
+ its_data[VSOMEIP_CLIENT_POS_MIN] = 0x0;
+ its_data[VSOMEIP_CLIENT_POS_MAX] = 0x0;
+ }
// Common way of message handling
on_message(its_service, its_instance, _data, _size, _receiver->is_reliable());
}
}
}
+#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(_receiver, false))
+ tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
+ _data, its_data_size);
+#endif
}
void routing_manager_impl::on_message(
@@ -632,88 +701,10 @@ void routing_manager_impl::on_message(
msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " ";
VSOMEIP_DEBUG << msg.str();
#endif
- method_t its_method;
client_t its_client;
- session_t its_session;
-
- its_client = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_CLIENT_POS_MIN],
- _data[VSOMEIP_CLIENT_POS_MAX]);
-
- its_method = VSOMEIP_BYTES_TO_WORD(
- _data[VSOMEIP_METHOD_POS_MIN],
- _data[VSOMEIP_METHOD_POS_MAX]);
-
- if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && its_client) {
- // targeted notification
- // reset client_id/subscriber/target field
- const_cast<byte_t *>(_data)[VSOMEIP_CLIENT_POS_MIN] = 0;
- const_cast<byte_t *>(_data)[VSOMEIP_CLIENT_POS_MAX] = 0;
-
- auto it_subscriber = remote_subscriber_map_.find(its_client);
- if (it_subscriber != remote_subscriber_map_.end()) {
- send_to(it_subscriber->second, _data, _size);
- } else {
- if (its_client == host_->get_client()) {
- deliver_message(_data, _size, _instance, _reliable);
- } else {
- send(its_client, _data, _size, _instance, true, _reliable);
- }
- }
- return;
- }
if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) {
- std::shared_ptr<event> its_event
- = find_event(_service, _instance, its_method);
- if (its_event) {
- uint32_t its_length = utility::get_payload_size(_data, _size);
- std::shared_ptr<payload> its_payload =
- runtime::get()->create_payload(
- &_data[VSOMEIP_PAYLOAD_POS],
- its_length);
- its_event->set_payload(its_payload);
-
- if (!utility::is_request_no_return(
- _data[VSOMEIP_MESSAGE_TYPE_POS])) {
- std::shared_ptr<message> its_response =
- runtime::get()->create_message();
- its_session = VSOMEIP_BYTES_TO_WORD(
- _data[VSOMEIP_SESSION_POS_MIN],
- _data[VSOMEIP_SESSION_POS_MAX]);
- major_version_t its_version = _data[VSOMEIP_INTERFACE_VERSION_POS];
-
- its_response->set_service(_service);
- its_response->set_method(its_method);
- its_response->set_client(its_client);
- its_response->set_session(its_session);
- its_response->set_interface_version(its_version);
-
- if (its_event->is_field()) {
- its_response->set_message_type(
- message_type_e::MT_RESPONSE);
- its_response->set_payload(its_event->get_payload());
- } else {
- its_response->set_message_type(message_type_e::MT_ERROR);
- }
-
- std::lock_guard<std::mutex> its_lock(serialize_mutex_);
- if (serializer_->serialize(its_response.get())) {
- // always pass reliable = false, but this won't be used, as
- // the event is sent out via TCP or UDP dependent on which
- // L4Proto the subscriber passed in the endpoint option in
- // its subscription to the eventgroup
- send(its_client,
- serializer_->get_data(), serializer_->get_size(),
- _instance, true, false);
- } else {
- VSOMEIP_ERROR << "routing_manager_impl::on_message: serialization error.";
- }
- serializer_->reset();
- }
- return;
- } else {
- its_client = find_local_client(_service, _instance);
- }
+ its_client = find_local_client(_service, _instance);
} else {
its_client = VSOMEIP_BYTES_TO_WORD(
_data[VSOMEIP_CLIENT_POS_MIN],
@@ -732,7 +723,7 @@ void routing_manager_impl::on_message(
void routing_manager_impl::on_notification(client_t _client,
service_t _service, instance_t _instance,
- const byte_t *_data, length_t _size) {
+ const byte_t *_data, length_t _size, bool _notify_one) {
event_t its_event_id = VSOMEIP_BYTES_TO_WORD(
_data[VSOMEIP_METHOD_POS_MIN],
_data[VSOMEIP_METHOD_POS_MAX]);
@@ -745,10 +736,12 @@ void routing_manager_impl::on_notification(client_t _client,
&_data[VSOMEIP_PAYLOAD_POS],
its_length);
- if (_client == VSOMEIP_ROUTING_CLIENT)
+ if (!_notify_one) {
its_event->set_payload(its_payload);
- else
- its_event->set_payload(its_payload, _client);
+ } else {
+ notify_one(_service, _instance, its_event->get_event(), its_payload, _client);
+ }
+
}
}
@@ -762,15 +755,28 @@ void routing_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) {
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;
+ }
host_->on_availability(its_service.first, its_instance.first,
- true);
+ 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()) {
- host_->on_availability(its_service.first,
- its_instance.first, true);
+ 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);
+ }
}
}
}
@@ -789,15 +795,25 @@ void routing_manager_impl::on_disconnect(std::shared_ptr<endpoint> _endpoint) {
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;
+ }
host_->on_availability(its_service.first, its_instance.first,
- false);
+ false, 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()) {
- host_->on_availability(its_service.first,
- its_instance.first, false);
+
+ 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,
+ false, its_info->get_major(), its_info->get_minor());
}
}
}
@@ -807,12 +823,29 @@ void routing_manager_impl::on_disconnect(std::shared_ptr<endpoint> _endpoint) {
}
void routing_manager_impl::on_stop_offer_service(service_t _service,
- instance_t _instance) {
+ instance_t _instance, major_version_t _major, minor_version_t _minor) {
- for (auto &s : events_)
- for (auto &i : s.second)
- for (auto &e : i.second)
- e.second->unset_payload();
+ {
+ std::lock_guard<std::mutex> its_lock(events_mutex_);
+ auto its_events_service = events_.find(_service);
+ if (its_events_service != events_.end()) {
+ auto its_events_instance = its_events_service->second.find(_instance);
+ if (its_events_instance != its_events_service->second.end()) {
+ for (auto &e : its_events_instance->second)
+ e.second->unset_payload();
+ }
+ }
+ }
+ {
+ std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_);
+ auto its_service = eventgroup_clients_.find(_service);
+ if (its_service != eventgroup_clients_.end()) {
+ auto its_instance = its_service->second.find(_instance);
+ if (its_instance != its_service->second.end()) {
+ its_instance->second.clear();
+ }
+ }
+ }
/**
* Hold reliable & unreliable server-endpoints from service info
@@ -831,11 +864,10 @@ void routing_manager_impl::on_stop_offer_service(service_t _service,
// Trigger "del_routing_info" either over SD or static
if (discovery_) {
- auto found_service = services_.find(_service);
- if (found_service != services_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- found_instance->second->set_ttl(0);
+ auto its_info = find_service(_service, _instance);
+ if (its_info) {
+ if (its_info->get_major() == _major && its_info->get_minor() == _minor) {
+ its_info->set_ttl(0);
discovery_->on_offer_change();
}
}
@@ -909,11 +941,8 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size,
host_->on_message(its_message);
is_delivered = true;
} else {
- VSOMEIP_ERROR << "Deserialization of vSomeIP message failed";
- if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) {
- send_error(return_code_e::E_MALFORMED_MESSAGE, _data,
- _size, _instance, _reliable, nullptr);
- }
+ VSOMEIP_ERROR << "Routing manager: deliver_message: "
+ << "SomeIP-Header deserialization failed!";
}
return is_delivered;
}
@@ -930,18 +959,31 @@ bool routing_manager_impl::deliver_notification(
std::shared_ptr<event> its_event = find_event(_service, _instance, its_method);
if (its_event) {
std::vector< byte_t > its_data;
-
+ std::set<client_t> its_local_client_set;
+ if(its_event->is_field() && !its_event->is_shadow()) {
+ // 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 =
+ runtime::get()->create_payload(
+ &_data[VSOMEIP_PAYLOAD_POS],
+ its_length);
+ its_event->set_payload_dont_notify(its_payload);
+ }
for (auto its_group : its_event->get_eventgroups()) {
- auto its_local_clients = find_local_clients(_service, _instance, its_group);
- for (auto its_local_client : its_local_clients) {
- if (its_local_client == host_->get_client()) {
- deliver_message(_data, _length, _instance, _reliable);
- } else {
- std::shared_ptr<endpoint> its_local_target = find_local(its_local_client);
- if (its_local_target) {
- send_local(its_local_target, VSOMEIP_ROUTING_CLIENT,
- _data, _length, _instance, true, _reliable);
- }
+ auto its_local_clients
+ = find_local_clients(_service, _instance, its_group);
+ its_local_client_set.insert(
+ its_local_clients.begin(), its_local_clients.end());
+ }
+
+ for (auto its_local_client : its_local_client_set) {
+ if (its_local_client == host_->get_client()) {
+ deliver_message(_data, _length, _instance, _reliable);
+ } else {
+ std::shared_ptr<endpoint> its_local_target = find_local(its_local_client);
+ if (its_local_target) {
+ send_local(its_local_target, VSOMEIP_ROUTING_CLIENT,
+ _data, _length, _instance, true, _reliable, VSOMEIP_SEND);
}
}
}
@@ -953,57 +995,7 @@ bool routing_manager_impl::deliver_notification(
std::shared_ptr<eventgroupinfo> routing_manager_impl::find_eventgroup(
service_t _service, instance_t _instance,
eventgroup_t _eventgroup) const {
- std::lock_guard<std::mutex> its_lock(eventgroups_mutex_);
-
- std::shared_ptr<eventgroupinfo> its_info(nullptr);
- auto found_service = eventgroups_.find(_service);
- if (found_service != eventgroups_.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()) {
- its_info = found_eventgroup->second;
- std::shared_ptr<serviceinfo> its_service_info
- = find_service(_service, _instance);
- if (its_service_info) {
- if (_eventgroup
- == its_service_info->get_multicast_group()) {
- try {
- boost::asio::ip::address its_multicast_address =
- boost::asio::ip::address::from_string(
- its_service_info->get_multicast_address());
- uint16_t its_multicast_port =
- its_service_info->get_multicast_port();
- its_info->set_multicast(its_multicast_address,
- its_multicast_port);
- }
- catch (...) {
- VSOMEIP_ERROR << "Eventgroup ["
- << std::hex << std::setw(4) << std::setfill('0')
- << _service << "." << _instance << "." << _eventgroup
- << "] is configured as multicast, but no valid "
- "multicast address is configured!";
- }
- }
- its_info->set_major(its_service_info->get_major());
- its_info->set_ttl(its_service_info->get_ttl());
- }
- }
- }
- }
- return (its_info);
-}
-
-void routing_manager_impl::remove_eventgroup_info(service_t _service,
- instance_t _instance, eventgroup_t _eventgroup) {
- std::lock_guard<std::mutex> its_lock(eventgroups_mutex_);
- auto found_service = eventgroups_.find(_service);
- if (found_service != eventgroups_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- found_instance->second.erase(_eventgroup);
- }
- }
+ return routing_manager_base::find_eventgroup(_service, _instance, _eventgroup);
}
std::shared_ptr<configuration> routing_manager_impl::get_configuration() const {
@@ -1018,16 +1010,11 @@ std::shared_ptr<endpoint> routing_manager_impl::create_service_discovery_endpoin
its_service_endpoint = create_server_endpoint(_port, _reliable, true);
if (its_service_endpoint) {
- std::shared_ptr<serviceinfo> its_info(
- std::make_shared<serviceinfo>(ANY_MAJOR, ANY_MINOR, DEFAULT_TTL,
- false)); // false, because we do _not_ want to announce it...
- its_info->set_endpoint(its_service_endpoint, _reliable);
-
- // routing info
- services_[VSOMEIP_SD_SERVICE][VSOMEIP_SD_INSTANCE] = its_info;
-
- its_service_endpoint->add_multicast(VSOMEIP_SD_SERVICE,
- VSOMEIP_SD_METHOD, _address, _port);
+ sd_info_ = std::make_shared<serviceinfo>(ANY_MAJOR, ANY_MINOR, DEFAULT_TTL,
+ false); // false, because we do _not_ want to announce it...
+ sd_info_->set_endpoint(its_service_endpoint, _reliable);
+ its_service_endpoint->add_default_target(VSOMEIP_SD_SERVICE,
+ _address, _port);
its_service_endpoint->join(_address);
} else {
VSOMEIP_ERROR << "Service Discovery endpoint could not be created. "
@@ -1038,16 +1025,15 @@ std::shared_ptr<endpoint> routing_manager_impl::create_service_discovery_endpoin
}
services_t routing_manager_impl::get_offered_services() const {
- services_t its_offers;
- std::lock_guard<std::mutex> its_lock(services_mutex_);
- for (auto s : services_) {
+ services_t its_services;
+ for (auto s : get_services()) {
for (auto i : s.second) {
if (i.second->is_local()) {
- its_offers[s.first][i.first] = i.second;
+ its_services[s.first][i.first] = i.second;
}
}
}
- return (its_offers);
+ return its_services;
}
std::shared_ptr<endpoint> routing_manager_impl::find_or_create_remote_client(
@@ -1064,26 +1050,12 @@ std::shared_ptr<endpoint> routing_manager_impl::find_or_create_remote_client(
///////////////////////////////////////////////////////////////////////////////
// PRIVATE
///////////////////////////////////////////////////////////////////////////////
-std::shared_ptr<serviceinfo> routing_manager_impl::find_service(
- service_t _service, instance_t _instance) const {
- std::shared_ptr<serviceinfo> its_info;
- std::lock_guard<std::mutex> its_lock(services_mutex_);
- auto found_service = services_.find(_service);
- if (found_service != services_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- its_info = found_instance->second;
- }
- }
- return (its_info);
-}
-
-std::shared_ptr<serviceinfo> routing_manager_impl::create_service_info(
- service_t _service, instance_t _instance, major_version_t _major,
- minor_version_t _minor, ttl_t _ttl, bool _is_local_service) {
- std::shared_ptr<serviceinfo> its_info;
+void routing_manager_impl::init_service_info(
+ service_t _service, instance_t _instance, bool _is_local_service) {
+ std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance);
if (configuration_) {
- its_info = std::make_shared<serviceinfo>(_major, _minor, _ttl, _is_local_service);
+ std::shared_ptr<endpoint> its_reliable_endpoint;
+ std::shared_ptr<endpoint> its_unreliable_endpoint;
uint16_t its_reliable_port = configuration_->get_reliable_port(_service,
_instance);
@@ -1092,16 +1064,6 @@ std::shared_ptr<serviceinfo> routing_manager_impl::create_service_info(
bool is_someip = configuration_->is_someip(_service, _instance);
- its_info->set_multicast_address(
- configuration_->get_multicast_address(_service, _instance));
- its_info->set_multicast_port(
- configuration_->get_multicast_port(_service, _instance));
- its_info->set_multicast_group(
- configuration_->get_multicast_group(_service, _instance));
-
- std::shared_ptr<endpoint> its_reliable_endpoint;
- std::shared_ptr<endpoint> its_unreliable_endpoint;
-
// Create server endpoints for local services only
if (_is_local_service) {
if (ILLEGAL_PORT != its_reliable_port) {
@@ -1133,20 +1095,14 @@ std::shared_ptr<serviceinfo> routing_manager_impl::create_service_info(
<< "]. Service is internal.";
}
}
-
- {
- std::lock_guard<std::mutex> its_lock(services_mutex_);
- services_[_service][_instance] = its_info;
- }
} else {
host_->on_error(error_code_e::CONFIGURATION_MISSING);
}
-
- return (its_info);
}
std::shared_ptr<endpoint> routing_manager_impl::create_client_endpoint(
- const boost::asio::ip::address &_address, uint16_t _port,
+ const boost::asio::ip::address &_address,
+ uint16_t _local_port, uint16_t _remote_port,
bool _reliable, client_t _client, bool _start) {
(void)_client;
@@ -1155,18 +1111,30 @@ std::shared_ptr<endpoint> routing_manager_impl::create_client_endpoint(
if (_reliable) {
its_endpoint = std::make_shared<tcp_client_endpoint_impl>(
shared_from_this(),
- boost::asio::ip::tcp::endpoint(_address, _port), io_,
+ boost::asio::ip::tcp::endpoint(
+ (_address.is_v4() ?
+ boost::asio::ip::tcp::v4() :
+ boost::asio::ip::tcp::v6()),
+ _local_port),
+ boost::asio::ip::tcp::endpoint(_address, _remote_port),
+ io_,
configuration_->get_message_size_reliable(
- _address.to_string(), _port));
+ _address.to_string(), _remote_port));
if (configuration_->has_enabled_magic_cookies(_address.to_string(),
- _port)) {
+ _remote_port)) {
its_endpoint->enable_magic_cookies();
}
} else {
its_endpoint = std::make_shared<udp_client_endpoint_impl>(
shared_from_this(),
- boost::asio::ip::udp::endpoint(_address, _port), io_);
+ boost::asio::ip::udp::endpoint(
+ (_address.is_v4() ?
+ boost::asio::ip::udp::v4() :
+ boost::asio::ip::udp::v6()),
+ _local_port),
+ boost::asio::ip::udp::endpoint(_address, _remote_port),
+ io_);
}
if (_start)
its_endpoint->start();
@@ -1226,7 +1194,7 @@ std::shared_ptr<endpoint> routing_manager_impl::create_server_endpoint(
}
std::shared_ptr<endpoint> routing_manager_impl::find_server_endpoint(
- uint16_t _port, bool _reliable) {
+ uint16_t _port, bool _reliable) const {
std::shared_ptr<endpoint> its_endpoint;
std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
auto found_port = server_endpoints_.find(_port);
@@ -1236,6 +1204,7 @@ std::shared_ptr<endpoint> routing_manager_impl::find_server_endpoint(
its_endpoint = found_endpoint->second;
}
}
+
return (its_endpoint);
}
@@ -1243,118 +1212,23 @@ std::shared_ptr<endpoint> routing_manager_impl::find_or_create_server_endpoint(
uint16_t _port, bool _reliable, bool _start) {
std::shared_ptr<endpoint> its_endpoint = find_server_endpoint(_port,
_reliable);
- if (0 == its_endpoint) {
+ if (!its_endpoint) {
its_endpoint = create_server_endpoint(_port, _reliable, _start);
}
return (its_endpoint);
}
std::shared_ptr<endpoint> routing_manager_impl::find_local(client_t _client) {
- std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
- std::shared_ptr<endpoint> its_endpoint;
- auto found_endpoint = local_clients_.find(_client);
- if (found_endpoint != local_clients_.end()) {
- its_endpoint = found_endpoint->second;
- }
- return (its_endpoint);
-}
-
-std::shared_ptr<endpoint> routing_manager_impl::create_local(client_t _client) {
- std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
-
- std::stringstream its_path;
- its_path << VSOMEIP_BASE_PATH << std::hex << _client;
-
-#ifdef WIN32
- boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1");
- int port = VSOMEIP_INTERNAL_BASE_PORT + _client;
-#endif
-
- std::shared_ptr<endpoint> its_endpoint = std::make_shared<
- local_client_endpoint_impl>(shared_from_this(),
-#ifdef WIN32
- boost::asio::ip::tcp::endpoint(address, port)
-#else
- boost::asio::local::stream_protocol::endpoint(its_path.str())
-#endif
- , io_, configuration_->get_max_message_size_local());
- local_clients_[_client] = its_endpoint;
- its_endpoint->start();
- return (its_endpoint);
+ return routing_manager_base::find_local(_client);
}
std::shared_ptr<endpoint> routing_manager_impl::find_or_create_local(
client_t _client) {
- std::shared_ptr<endpoint> its_endpoint(find_local(_client));
- if (!its_endpoint) {
- its_endpoint = create_local(_client);
- }
- return (its_endpoint);
+ return routing_manager_base::find_or_create_local(_client);
}
void routing_manager_impl::remove_local(client_t _client) {
- {
- std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
- std::shared_ptr<endpoint> its_endpoint = find_local(_client);
- its_endpoint->stop();
- local_clients_.erase(_client);
- }
- {
- std::lock_guard<std::mutex> its_lock(local_mutex_);
- // Finally remove all services that are implemented by the client.
- std::set<std::pair<service_t, instance_t>> its_services;
- for (auto& s : local_services_) {
- for (auto& i : s.second) {
- if (i.second == _client)
- its_services.insert({ s.first, i.first });
- }
- }
-
- for (auto& si : its_services) {
- local_services_[si.first].erase(si.second);
- if (local_services_[si.first].size() == 0)
- local_services_.erase(si.first);
- }
- }
-}
-
-std::shared_ptr<endpoint> routing_manager_impl::find_local(service_t _service,
- instance_t _instance) {
- client_t client = find_local_client(_service, _instance);
- if (client) {
- return find_local(client);
- }
- return nullptr;
-}
-
-client_t routing_manager_impl::find_local_client(service_t _service,
- instance_t _instance) {
- std::lock_guard<std::mutex> its_lock(local_mutex_);
- client_t its_client(0);
- 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()) {
- its_client = found_instance->second;
- }
- }
- return (its_client);
-}
-
-std::set<client_t> routing_manager_impl::find_local_clients(service_t _service,
- instance_t _instance, eventgroup_t _eventgroup) {
- std::set<client_t> its_clients;
- auto found_service = eventgroup_clients_.find(_service);
- if (found_service != eventgroup_clients_.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()) {
- its_clients = found_eventgroup->second;
- }
- }
- }
- return (its_clients);
+ routing_manager_base::remove_local(_client);
}
instance_t routing_manager_impl::find_instance(service_t _service,
@@ -1374,34 +1248,42 @@ std::shared_ptr<endpoint> routing_manager_impl::create_remote_client(
service_t _service, instance_t _instance, bool _reliable, client_t _client) {
std::shared_ptr<endpoint> its_endpoint;
std::shared_ptr<endpoint_definition> its_endpoint_def;
- 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_endpoint_def->get_port(), _reliable, _client,
- configuration_->is_someip(_service, _instance)
- );
- }
- }
- }
- if (its_endpoint) {
- 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);
- }
- }
+
+ 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);
+ }
+ }
+ }
}
return its_endpoint;
}
@@ -1423,7 +1305,7 @@ std::shared_ptr<endpoint> routing_manager_impl::find_remote_client(
}
}
}
- if(its_endpoint || _client != VSOMEIP_ROUTING_CLIENT) {
+ if (its_endpoint || _client != VSOMEIP_ROUTING_CLIENT) {
return its_endpoint;
}
@@ -1461,41 +1343,34 @@ std::shared_ptr<endpoint> routing_manager_impl::find_remote_client(
return its_endpoint;
}
-std::shared_ptr<event> routing_manager_impl::find_event(service_t _service,
- instance_t _instance, event_t _event) const {
- std::shared_ptr<event> its_event;
- auto find_service = events_.find(_service);
- if (find_service != events_.end()) {
- auto find_instance = find_service->second.find(_instance);
- if (find_instance != find_service->second.end()) {
- auto find_event = find_instance->second.find(_event);
- if (find_event != find_instance->second.end()) {
- its_event = find_event->second;
- }
- }
- }
- return (its_event);
-}
-
-std::set<std::shared_ptr<event> > routing_manager_impl::find_events(
- service_t _service, instance_t _instance, eventgroup_t _eventgroup) {
- std::set<std::shared_ptr<event> > its_events;
- auto found_service = eventgroups_.find(_service);
- if (found_service != eventgroups_.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()) {
- return (found_eventgroup->second->get_events());
- }
- }
- }
- return (its_events);
+client_t routing_manager_impl::find_client(
+ service_t _service, instance_t _instance,
+ const std::shared_ptr<eventgroupinfo> &_eventgroup,
+ const std::shared_ptr<endpoint_definition> &_target) const {
+ client_t its_client = VSOMEIP_ROUTING_CLIENT;
+ if (!_eventgroup->is_multicast()) {
+ if (!_target->is_reliable()) {
+ uint16_t unreliable_port = configuration_->get_unreliable_port(_service, _instance);
+ auto endpoint = find_server_endpoint(unreliable_port, false);
+ if (endpoint) {
+ its_client = std::dynamic_pointer_cast<udp_server_endpoint_impl>(endpoint)->
+ get_client(_target);
+ }
+ } else {
+ uint16_t reliable_port = configuration_->get_reliable_port(_service, _instance);
+ auto endpoint = find_server_endpoint(reliable_port, true);
+ if (endpoint) {
+ its_client = std::dynamic_pointer_cast<tcp_server_endpoint_impl>(endpoint)->
+ get_client(_target);
+ }
+ }
+ }
+ return its_client;
}
-
bool routing_manager_impl::is_field(service_t _service, instance_t _instance,
event_t _event) const {
+ std::lock_guard<std::mutex> its_lock(events_mutex_);
auto find_service = events_.find(_service);
if (find_service != events_.end()) {
auto find_instance = find_service->second.find(_instance);
@@ -1530,10 +1405,7 @@ void routing_manager_impl::add_routing_info(
is_local = true;
its_info = create_service_info(_service, _instance, _major, _minor, _ttl, is_local);
- {
- std::lock_guard<std::mutex> its_lock(services_mutex_);
- services_[_service][_instance] = its_info;
- }
+ init_service_info(_service, _instance, is_local);
} else {
its_info->set_ttl(_ttl);
}
@@ -1554,9 +1426,9 @@ void routing_manager_impl::add_routing_info(
if (its_definition->get_address() == _reliable_address
&& its_definition->get_port() == _reliable_port) {
is_reliable_known = true;
+ } else {
+ VSOMEIP_WARNING << "Reliable service endpoint has changed!";
}
- } else {
- VSOMEIP_WARNING << "Reliable service endpoint has changed!";
}
}
if (_unreliable_port != ILLEGAL_PORT) {
@@ -1581,6 +1453,48 @@ void routing_manager_impl::add_routing_info(
= 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
+ {
+ bool connected(false);
+ std::lock_guard<std::mutex> its_lock(requested_services_mutex_);
+ for(const auto &client_id : requested_services_) {
+ auto found_service = client_id.second.find(_service);
+ if (found_service != client_id.second.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ for (const auto &major_minor_pair : found_instance->second) {
+ if ((major_minor_pair.first == _major
+ || _major == DEFAULT_MAJOR)
+ && (major_minor_pair.second <= _minor
+ || _minor == DEFAULT_MINOR
+ || major_minor_pair.second == ANY_MINOR)) {
+ // SWS_SD_00376 establish TCP connection to service
+ // service is marked as available later in on_connect()
+ if(!connected) {
+ find_or_create_remote_client(_service, _instance,
+ true, VSOMEIP_ROUTING_CLIENT);
+ connected = true;
+ }
+ its_info->add_client(client_id.first);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_);
+ auto found_service2 = specific_endpoint_clients_.find(_service);
+ if (found_service2 != specific_endpoint_clients_.end()) {
+ auto found_instance = found_service2->second.find(_instance);
+ if (found_instance != found_service2->second.end()) {
+ for (const client_t& c : found_instance->second) {
+ find_or_create_remote_client(_service, _instance, true, c);
+ }
+ }
+ }
}
if (_unreliable_port != ILLEGAL_PORT && !is_unreliable_known) {
@@ -1588,27 +1502,51 @@ void routing_manager_impl::add_routing_info(
= endpoint_definition::get(_unreliable_address, _unreliable_port, false);
remote_service_info_[_service][_instance][false] = endpoint_def;
is_added = !is_reliable_known;
+ if (is_added) {
+ host_->on_availability(_service, _instance, true, _major, _minor);
+ stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, _major, _minor);
+ }
}
- if (is_added) {
- host_->on_availability(_service, _instance, true);
- stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance);
- }
}
void routing_manager_impl::del_routing_info(service_t _service, instance_t _instance,
bool _has_reliable, bool _has_unreliable) {
- host_->on_availability(_service, _instance, false);
- stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance);
+ std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance));
+ if(!its_info)
+ return;
+
+ 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
- auto found_service = eventgroups_.find(_service);
- if (found_service != eventgroups_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- for (auto &its_eventgroup : found_instance->second) {
- its_eventgroup.second->clear_targets();
+ {
+ std::lock_guard<std::mutex> its_lock(eventgroups_mutex_);
+ auto found_service = eventgroups_.find(_service);
+ if (found_service != eventgroups_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ for (auto &its_eventgroup : found_instance->second) {
+ its_eventgroup.second->clear_targets();
+ }
+ }
+ }
+ }
+ {
+ 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();
+ }
}
}
}
@@ -1626,17 +1564,23 @@ void routing_manager_impl::del_routing_info(service_t _service, instance_t _inst
clear_service_info(_service, _instance, false);
}
-ttl_t routing_manager_impl::update_routing_info(ttl_t _elapsed) {
- ttl_t its_smallest_ttl(DEFAULT_TTL);
+std::chrono::milliseconds routing_manager_impl::update_routing_info(std::chrono::milliseconds _elapsed) {
+ std::chrono::seconds default_ttl(DEFAULT_TTL);
+ std::chrono::milliseconds its_smallest_ttl =
+ std::chrono::duration_cast<std::chrono::milliseconds>(default_ttl);
std::map<service_t,
std::map<instance_t,
std::pair<bool, bool> > > its_expired_offers;
- for (auto &s : services_) {
+ for (auto &s : get_services()) {
for (auto &i : s.second) {
+ if (routing_manager_base::find_local(s.first, i.first)) {
+ continue; //don't expire local services
+ }
ttl_t its_ttl = i.second->get_ttl();
+ std::chrono::milliseconds precise_ttl = i.second->get_precise_ttl();
if (its_ttl < DEFAULT_TTL) { // do not touch "forever"
- if (its_ttl < _elapsed || its_ttl == 0) {
+ if (precise_ttl.count() < _elapsed.count() || precise_ttl.count() == 0) {
i.second->set_ttl(0);
if (discovery_)
discovery_->unsubscribe_all(s.first, i.first);
@@ -1645,8 +1589,8 @@ ttl_t routing_manager_impl::update_routing_info(ttl_t _elapsed) {
i.second->get_endpoint(false) != nullptr
};
} else {
- ttl_t its_new_ttl(its_ttl - _elapsed);
- i.second->set_ttl(its_new_ttl);
+ std::chrono::milliseconds its_new_ttl(precise_ttl - _elapsed);
+ i.second->set_precise_ttl(its_new_ttl);
if (its_smallest_ttl > its_new_ttl)
its_smallest_ttl = its_new_ttl;
}
@@ -1668,8 +1612,11 @@ void routing_manager_impl::expire_services(const boost::asio::ip::address &_addr
std::map<instance_t,
std::pair<bool, bool> > > its_expired_offers;
- for (auto &s : services_) {
+ for (auto &s : get_services()) {
for (auto &i : s.second) {
+ if (routing_manager_base::find_local(s.first, i.first)) {
+ continue; //don't expire local services
+ }
bool is_gone(false);
boost::asio::ip::address its_address;
std::shared_ptr<endpoint> its_endpoint = i.second->get_endpoint(true);
@@ -1705,17 +1652,23 @@ void routing_manager_impl::expire_services(const boost::asio::ip::address &_addr
}
void routing_manager_impl::expire_subscriptions(const boost::asio::ip::address &_address) {
+ std::lock_guard<std::mutex> its_lock(eventgroups_mutex_);
for (auto &its_service : eventgroups_) {
for (auto &its_instance : its_service.second) {
for (auto &its_eventgroup : its_instance.second) {
- std::set<std::shared_ptr<endpoint_definition>> its_invalid_targets;
+ std::set<std::shared_ptr<endpoint_definition>> its_invalid_endpoints;
for (auto &its_target : its_eventgroup.second->get_targets()) {
- if (its_target->get_address() == _address)
- its_invalid_targets.insert(its_target);
+ if (its_target.endpoint_->get_address() == _address)
+ its_invalid_endpoints.insert(its_target.endpoint_);
}
- for (auto &its_target : its_invalid_targets) {
- its_eventgroup.second->remove_target(its_target);
+ for (auto &its_endpoint : its_invalid_endpoints) {
+ its_eventgroup.second->remove_target(its_endpoint);
+ }
+ if(its_eventgroup.second->is_multicast() &&
+ 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();
}
}
}
@@ -1751,16 +1704,15 @@ void routing_manager_impl::init_routing_info() {
}
}
-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) {
+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) {
std::shared_ptr<eventgroupinfo> its_eventgroup
= find_eventgroup(_service, _instance, _eventgroup);
if (its_eventgroup) {
- client_t client = 0;
- if (!its_eventgroup->is_multicast()) {
- if (!_target->is_reliable()) {
+ client_t client = VSOMEIP_ROUTING_CLIENT;
+ if (!_target->is_reliable()) {
+ if (!its_eventgroup->is_multicast()) {
uint16_t unreliable_port = configuration_->get_unreliable_port(_service, _instance);
_target->set_remote_port(unreliable_port);
auto endpoint = find_server_endpoint(unreliable_port, false);
@@ -1769,40 +1721,89 @@ void routing_manager_impl::on_subscribe(
get_client(_target);
}
}
- else {
- uint16_t reliable_port = configuration_->get_reliable_port(_service, _instance);
- auto endpoint = find_server_endpoint(reliable_port, true);
- _target->set_remote_port(reliable_port);
- if (endpoint) {
- client = std::dynamic_pointer_cast<tcp_server_endpoint_impl>(endpoint)->
- get_client(_target);
- }
+ }
+ else {
+ uint16_t reliable_port = configuration_->get_reliable_port(_service, _instance);
+ _target->set_remote_port(reliable_port);
+ auto endpoint = find_server_endpoint(reliable_port, true);
+ if (endpoint) {
+ client = std::dynamic_pointer_cast<tcp_server_endpoint_impl>(endpoint)->
+ get_client(_target);
}
}
- if(!host_->on_subscription(_service, _instance, _eventgroup, client, true)) {
- VSOMEIP_INFO << "Subscription request for eventgroup " << _eventgroup
- << " rejected from application handler";
- return;
+ if (its_eventgroup->update_target(_target, _expiration)) {
+ return true;
}
- VSOMEIP_DEBUG << "on_subscribe: target=" << _target->get_address().to_string()
- << ":" << std::dec <<_target->get_port() << ":Client=" << std::hex
- << client << (_target->is_reliable() ? " reliable" : " unreliable");
+ if (!host_->on_subscription(_service, _instance, _eventgroup, client, true)) {
+ VSOMEIP_INFO << "Subscription request from client: 0x" << std::hex
+ << client << " for eventgroup: 0x" << _eventgroup << std::dec
+ << " rejected from application handler.";
+ return false;
+ }
- send_subscribe(client, _service, _instance, _eventgroup, its_eventgroup->get_major());
+ if (client != VSOMEIP_ROUTING_CLIENT) {
+ VSOMEIP_DEBUG << "Subscription accepted: eventgroup=" << _eventgroup
+ << " : target: " << _target->get_address().to_string()
+ << ":" << std::dec <<_target->get_port()
+ << (_target->is_reliable() ? " reliable" : " unreliable")
+ << " from client: 0x" << std::hex << client << ".";
+ } else {
+ VSOMEIP_DEBUG << "Subscription accepted: eventgroup: " << _eventgroup
+ << " : target: " << _target->get_address().to_string()
+ << ":" << std::dec <<_target->get_port()
+ << (_target->is_reliable() ? " reliable" : " unreliable")
+ << " from unknown client.";
+ }
- remote_subscriber_map_[client] = _target;
+ stub_->send_subscribe(routing_manager_base::find_local(_service, _instance),
+ client, _service, _instance, _eventgroup, its_eventgroup->get_major(), true);
- if (its_eventgroup->add_target(_target)) { // unicast or multicast
+ remote_subscribers_[_service][_instance][client].insert(_target);
+ } else {
+ VSOMEIP_ERROR<< "subscribe: attempt to subscribe to unknown eventgroup!";
+ return false;
+ }
+ return true;
+}
+
+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) {
+
+ 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()) {
+ // Event is in multicast eventgroup and subscribe for UDP
+ target_added = its_eventgroup->add_target({ _target, _expiration }, {_subscriber, _expiration});
+
+ // If the target is multicast, we need to set the remote port
+ // of the unicast(!) here, as its only done in on_subscribe_accepted
+ // for unicast subscribes and it needs to be done before calling
+ // notify_one on the events.
+ uint16_t unreliable_port =
+ configuration_->get_unreliable_port(_service, _instance);
+ _subscriber->set_remote_port(unreliable_port);
+ }
+ else {
+ // subscribe for TCP or UDP
+ target_added = its_eventgroup->add_target({ _target, _expiration });
+ }
+
+ if (target_added) { // unicast or multicast
+ // send initial events
for (auto its_event : its_eventgroup->get_events()) {
if (its_event->is_field()) {
its_event->notify_one(_subscriber); // unicast
}
}
}
- } else {
- VSOMEIP_ERROR<< "subscribe: attempt to subscribe to unknown eventgroup!";
}
}
@@ -1812,35 +1813,26 @@ void routing_manager_impl::on_unsubscribe(service_t _service,
std::shared_ptr<eventgroupinfo> its_eventgroup = find_eventgroup(_service,
_instance, _eventgroup);
if (its_eventgroup) {
- client_t client = 0;
- if (!its_eventgroup->is_multicast()) {
- if (!_target->is_reliable()) {
- uint16_t unreliable_port = configuration_->get_unreliable_port(_service, _instance);
- auto endpoint = find_server_endpoint(unreliable_port, false);
- if (endpoint) {
- client = std::dynamic_pointer_cast<udp_server_endpoint_impl>(endpoint)->
- get_client(_target);
- }
- } else {
- uint16_t reliable_port = configuration_->get_reliable_port(_service, _instance);
- auto endpoint = find_server_endpoint(reliable_port, true);
- if (endpoint) {
- client = std::dynamic_pointer_cast<tcp_server_endpoint_impl>(endpoint)->
- get_client(_target);
- }
- }
- }
+ client_t its_client = find_client(_service, _instance, its_eventgroup, _target);
- VSOMEIP_DEBUG << "on_unsubscribe: target=" << _target->get_address().to_string()
- << ":" << std::dec <<_target->get_port() << ":Client=" << std::hex
- << client << (_target->is_reliable() ? " reliable" : " unreliable");;
+ if (its_client != VSOMEIP_ROUTING_CLIENT) {
+ VSOMEIP_DEBUG << "on_unsubscribe: target: " << _target->get_address().to_string()
+ << ":" << std::dec <<_target->get_port()
+ << (_target->is_reliable() ? " reliable" : " unreliable")
+ << " from client: 0x" << std::hex << its_client;
+ } else {
+ VSOMEIP_DEBUG << "on_unsubscribe: target: " << _target->get_address().to_string()
+ << ":" << std::dec <<_target->get_port()
+ << (_target->is_reliable() ? " reliable" : " unreliable");
+ }
its_eventgroup->remove_target(_target);
+ clear_remote_subscriber(_service, _instance, its_client, _target);
- if (remote_subscriber_map_.find(client) != remote_subscriber_map_.end()) {
- remote_subscriber_map_.erase(client);
- }
- host_->on_subscription(_service, _instance, _eventgroup, client, false);
+ stub_->send_unsubscribe(routing_manager_base::find_local(_service, _instance),
+ its_client, _service, _instance, _eventgroup);
+
+ host_->on_subscription(_service, _instance, _eventgroup, its_client, false);
} else {
VSOMEIP_ERROR<<"unsubscribe: attempt to subscribe to unknown eventgroup!";
@@ -1883,79 +1875,51 @@ void routing_manager_impl::on_subscribe_ack(service_t _service,
}
}
-void routing_manager_impl::send_subscribe(client_t _client, service_t _service,
- instance_t _instance, eventgroup_t _eventgroup,
- major_version_t _major) {
-
- byte_t its_command[VSOMEIP_SUBSCRIBE_COMMAND_SIZE];
- uint32_t its_size = VSOMEIP_SUBSCRIBE_COMMAND_SIZE
- - VSOMEIP_COMMAND_HEADER_SIZE;
-
- its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE;
- 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));
- its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] = _major;
-
- std::shared_ptr<vsomeip::endpoint> target = find_local(_service, _instance);
- if (target) {
- target->send(its_command, sizeof(its_command));
- }
-}
-
-void routing_manager_impl::send_unsubscribe(client_t _client, service_t _service,
- instance_t _instance, eventgroup_t _eventgroup) {
-
- 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::shared_ptr<vsomeip::endpoint> target = find_local(_service, _instance);
- if (target) {
- target->send(its_command, sizeof(its_command));
- }
-}
-
-bool routing_manager_impl::insert_subscription(
- service_t _service, instance_t _instance, eventgroup_t _eventgroup,
- client_t _client) {
-
- auto found_service = eventgroup_clients_.find(_service);
- if (found_service != eventgroup_clients_.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()) {
- if (found_eventgroup->second.find(_client)
- != found_eventgroup->second.end())
- return false;
+void routing_manager_impl::on_subscribe_ack(client_t _client,
+ service_t _service, instance_t _instance, eventgroup_t _eventgroup) {
+ {
+ std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_);
+ auto found_service = specific_endpoint_clients_.find(_service);
+ if(found_service != specific_endpoint_clients_.end()){
+ auto found_instance = found_service->second.find(_instance);
+ if(found_instance != found_service->second.end()) {
+ auto found_client = found_instance->second.find(_client);
+ if(found_client == found_instance->second.end()) {
+ // Ack is only interesting for proxies using its own endpoint!
+ return;
+ }
}
}
}
-
- eventgroup_clients_[_service][_instance][_eventgroup].insert(_client);
- return true;
+ if (_client == get_client()) {
+ host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/);
+ } else {
+ stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup);
+ }
}
+void routing_manager_impl::on_subscribe_nack(client_t _client,
+ service_t _service, instance_t _instance, eventgroup_t _eventgroup) {
+ {
+ std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_);
+ auto found_service = specific_endpoint_clients_.find(_service);
+ if(found_service != specific_endpoint_clients_.end()){
+ auto found_instance = found_service->second.find(_instance);
+ if(found_instance != found_service->second.end()) {
+ auto found_client = found_instance->second.find(_client);
+ if(found_client == found_instance->second.end()) {
+ // Nack is only interesting for proxies using its own endpoint!
+ return;
+ }
+ }
+ }
+ }
+ if (_client == get_client()) {
+ host_->on_subscription_error(_service, _instance, _eventgroup, 0x7 /*Rejected*/);
+ } else {
+ stub_->send_subscribe_nack(_client, _service, _instance, _eventgroup);
+ }
+}
bool routing_manager_impl::deliver_specific_endpoint_message(service_t _service,
instance_t _instance, const byte_t *_data, length_t _size, endpoint *_receiver) {
@@ -1973,9 +1937,12 @@ bool routing_manager_impl::deliver_specific_endpoint_message(service_t _service,
if (found_reliability != client_entry.second.end()) {
auto found_enpoint = found_reliability->second;
if (found_enpoint.get() == _receiver) {
- auto local_endpoint = find_local(client);
if (client != get_client()) {
- send_local(local_endpoint, client, _data, _size, _instance, true, _receiver->is_reliable());
+ auto local_endpoint = find_local(client);
+ if (local_endpoint) {
+ send_local(local_endpoint, client, _data, _size, _instance, true,
+ _receiver->is_reliable(), VSOMEIP_SEND);
+ }
} else {
deliver_message(_data, _size, _instance, _receiver->is_reliable());
}
@@ -2009,18 +1976,27 @@ void routing_manager_impl::clear_client_endpoints(service_t _service, instance_t
}
}
}
- for (client_t client : specific_endpoint_clients) {
- 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);
+ {
+ 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()) {
+ for (const client_t& client : found_instance->second) {
+ 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);
+ }
+ }
+ }
}
}
}
@@ -2137,33 +2113,15 @@ void routing_manager_impl::clear_multicast_endpoints(service_t _service, instanc
}
}
-void routing_manager_impl::clear_service_info(service_t _service, instance_t _instance,
- bool _reliable) {
- std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance));
- if (!its_info) {
- return;
- }
- // Clear service_info and service_group
- std::shared_ptr<endpoint> its_empty_endpoint;
- if (!its_info->get_endpoint(!_reliable)) {
- if (1 >= services_[_service].size()) {
- services_.erase(_service);
- } else {
- services_[_service].erase(_instance);
- }
- } else {
- its_info->set_endpoint(its_empty_endpoint, _reliable);
- }
-}
-
return_code_e routing_manager_impl::check_error(const byte_t *_data, length_t _size,
instance_t _instance) {
service_t its_service = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_SERVICE_POS_MIN],
_data[VSOMEIP_SERVICE_POS_MAX]);
- if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) {
- if (_size >= VSOMEIP_PAYLOAD_POS) {
+ if (_size >= VSOMEIP_PAYLOAD_POS) {
+ if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])
+ || utility::is_request_no_return(_data[VSOMEIP_MESSAGE_TYPE_POS]) ) {
if (_data[VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) {
VSOMEIP_WARNING << "Received a message with unsupported protocol version for service 0x"
<< std::hex << its_service;
@@ -2175,25 +2133,26 @@ return_code_e routing_manager_impl::check_error(const byte_t *_data, length_t _s
return return_code_e::E_UNKNOWN_SERVICE;
}
// Check interface version of service/instance
- auto found_service = services_.find(its_service);
- if (found_service != services_.end()) {
- auto found_instance = found_service->second.find(_instance);
- if (found_instance != found_service->second.end()) {
- auto its_info = found_instance->second;
- major_version_t its_version = _data[VSOMEIP_INTERFACE_VERSION_POS];
- if (its_version != its_info->get_major()) {
- return return_code_e::E_WRONG_INTERFACE_VERSION;
- }
+ auto its_info = find_service(its_service, _instance);
+ if (its_info) {
+ major_version_t its_version = _data[VSOMEIP_INTERFACE_VERSION_POS];
+ if (its_version != its_info->get_major()) {
+ VSOMEIP_WARNING << "Received a message with unsupported interface version for service 0x"
+ << std::hex << its_service;
+ return return_code_e::E_WRONG_INTERFACE_VERSION;
}
}
if (_data[VSOMEIP_RETURN_CODE_POS] != static_cast<byte_t> (return_code_e::E_OK)) {
// Request calls must to have return code E_OK set!
+ VSOMEIP_WARNING << "Received a message with unsupported return code set for service 0x"
+ << std::hex << its_service;
return return_code_e::E_NOT_OK;
}
- } else {
- // Message shorter than vSomeIP message header
- return return_code_e::E_MALFORMED_MESSAGE;
}
+ } else {
+ // Message shorter than vSomeIP message header
+ VSOMEIP_WARNING << "Received a message message which is shorter than vSomeIP message header!";
+ return return_code_e::E_MALFORMED_MESSAGE;
}
return return_code_e::E_OK;
}
@@ -2207,6 +2166,7 @@ void routing_manager_impl::send_error(return_code_e _return_code,
service_t its_service = 0;
method_t its_method = 0;
session_t its_session = 0;
+ major_version_t its_version = 0;
if (_size >= VSOMEIP_CLIENT_POS_MAX) {
its_client = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_CLIENT_POS_MIN],
@@ -2224,11 +2184,14 @@ void routing_manager_impl::send_error(return_code_e _return_code,
its_session = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_SESSION_POS_MIN],
_data[VSOMEIP_SESSION_POS_MAX]);
}
+ if( _size >= VSOMEIP_INTERFACE_VERSION_POS) {
+ its_version = _data[VSOMEIP_INTERFACE_VERSION_POS];
+ }
auto error_message = runtime::get()->create_message(_reliable);
error_message->set_client(its_client);
error_message->set_instance(_instance);
- error_message->set_interface_version(0);
+ error_message->set_interface_version(its_version);
error_message->set_message_type(message_type_e::MT_ERROR);
error_message->set_method(its_method);
error_message->set_return_code(_return_code);
@@ -2241,11 +2204,19 @@ void routing_manager_impl::send_error(return_code_e _return_code,
boost::asio::ip::address adr;
uint16_t port;
if (_receiver->is_reliable()) {
- auto remote = static_cast<tcp_server_endpoint_impl*>(_receiver)->get_remote();
+ auto endpoint = dynamic_cast<tcp_server_endpoint_impl*>(_receiver);
+ if(!endpoint) {
+ return;
+ }
+ auto remote = endpoint->get_remote();
adr = remote.address();
port = remote.port();
} else {
- auto remote = static_cast<udp_server_endpoint_impl*>(_receiver)->get_remote();
+ auto endpoint = dynamic_cast<udp_server_endpoint_impl*>(_receiver);
+ if (!endpoint) {
+ return;
+ }
+ auto remote = endpoint->get_remote();
adr = remote.address();
port = remote.port();
}
@@ -2253,9 +2224,6 @@ void routing_manager_impl::send_error(return_code_e _return_code,
std::make_shared<endpoint_definition>(adr, port, _receiver->is_reliable());
its_endpoint_def->set_remote_port(_receiver->get_local_port());
send_to(its_endpoint_def, serializer_->get_data(), serializer_->get_size());
- } else {
- send(get_client(), serializer_->get_data(), serializer_->get_size(),
- _instance, true, _reliable);
}
serializer_->reset();
} else {
@@ -2263,5 +2231,163 @@ 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);
+ 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)) {
+ auto unreliable_endpoint = find_or_create_remote_client(_service, _instance, false, _client);
+ if (unreliable_endpoint) {
+ auto message = runtime::get()->create_message(false);
+ message->set_service(_service);
+ message->set_instance(_instance);
+ message->set_client(_client);
+ message->set_method(ANY_METHOD - 1);
+ message->set_interface_version(_major);
+ message->set_message_type(message_type_e::MT_REQUEST);
+ std::lock_guard<std::mutex> its_lock(serialize_mutex_);
+ if (serializer_->serialize(message.get())) {
+ unreliable_endpoint->send(serializer_->get_data(),
+ serializer_->get_size());
+ serializer_->reset();
+ }
+ }
+ }
+ if (!has_identified(_client, _service, _instance, true)) {
+ auto reliable_endpoint = find_or_create_remote_client(_service, _instance, true, _client);
+ if (reliable_endpoint) {
+ auto message = runtime::get()->create_message(true);
+ message->set_service(_service);
+ message->set_instance(_instance);
+ message->set_client(_client);
+ message->set_method(ANY_METHOD - 1);
+ message->set_interface_version(_major);
+ message->set_message_type(message_type_e::MT_REQUEST);
+ std::lock_guard<std::mutex> its_lock(serialize_mutex_);
+ if (serializer_->serialize(message.get())) {
+ reliable_endpoint->send(serializer_->get_data(),
+ serializer_->get_size());
+ serializer_->reset();
+ }
+ }
+ }
+}
+
+bool routing_manager_impl::supports_selective(service_t _service, instance_t _instance) {
+ bool supports_selective(false);
+ auto its_service = remote_service_info_.find(_service);
+ if (its_service != remote_service_info_.end()) {
+ auto its_instance = its_service->second.find(_instance);
+ if (its_instance != its_service->second.end()) {
+ for (auto its_reliable : its_instance->second) {
+ supports_selective |= configuration_->
+ supports_selective_broadcasts(
+ its_reliable.second->get_address());
+ }
+ }
+ }
+ return supports_selective;
}
- // namespace vsomeip
+
+bool routing_manager_impl::has_identified(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 true;
+ }
+ bool has_identified(false);
+ std::lock_guard<std::mutex> its_lock(identified_clients_mutex_);
+ auto its_service = identified_clients_.find(_service);
+ if (its_service != identified_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()) {
+ has_identified = true;
+ }
+ }
+ }
+ }
+ return has_identified;
+}
+
+void routing_manager_impl::clear_remote_subscriber(
+ service_t _service, instance_t _instance, client_t _client,
+ const std::shared_ptr<endpoint_definition> &_target) {
+ 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_client = its_instance->second.find(_client);
+ if (its_client != its_instance->second.end()) {
+ if (its_client->second.size() <= 1) {
+ its_instance->second.erase(_client);
+ } else {
+ its_client->second.erase(_target);
+ }
+ }
+ }
+ }
+}
+
+std::chrono::high_resolution_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);
+
+ for (auto &its_service : eventgroups_) {
+ for (auto &its_instance : its_service.second) {
+ for (auto &its_eventgroup : its_instance.second) {
+ std::set<std::shared_ptr<endpoint_definition>> its_expired_endpoints;
+ for (auto &its_target : its_eventgroup.second->get_targets()) {
+ if (its_target.expiration_ < now) {
+ its_expired_endpoints.insert(its_target.endpoint_);
+ } else if (its_target.expiration_ < next_expiration) {
+ next_expiration = its_target.expiration_;
+ }
+ }
+
+ for (auto its_endpoint : its_expired_endpoints) {
+ its_eventgroup.second->remove_target(its_endpoint);
+
+ client_t its_client
+ = find_client(its_service.first, its_instance.first,
+ its_eventgroup.second, its_endpoint);
+ clear_remote_subscriber(its_service.first, its_instance.first,
+ its_client, its_endpoint);
+
+ VSOMEIP_DEBUG << "Expired subscription ("
+ << std::hex << its_service.first << "."
+ << its_instance .first << "."
+ << its_eventgroup.first << " from "
+ << its_endpoint->get_address() << ":"
+ << std::dec << its_endpoint->get_port()
+ << "(" << std::hex << its_client << ")";
+ }
+ if(its_eventgroup.second->is_multicast() &&
+ 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();
+ }
+ }
+ }
+ }
+
+ return next_expiration;
+}
+
+bool routing_manager_impl::queue_message(const byte_t *_data, uint32_t _size) const {
+ return stub_->queue_message(_data, _size);
+}
+
+} // namespace vsomeip
diff --git a/implementation/routing/src/routing_manager_proxy.cpp b/implementation/routing/src/routing_manager_proxy.cpp
index 45346bf..0a3f7b5 100644
--- a/implementation/routing/src/routing_manager_proxy.cpp
+++ b/implementation/routing/src/routing_manager_proxy.cpp
@@ -1,10 +1,19 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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 <climits>
#include <iomanip>
#include <mutex>
+#include <unordered_set>
+#include <future>
+
+#ifndef WIN32
+// for umask
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
#include <vsomeip/constants.hpp>
#include <vsomeip/runtime.hpp>
@@ -26,32 +35,20 @@
namespace vsomeip {
routing_manager_proxy::routing_manager_proxy(routing_manager_host *_host) :
- io_(_host->get_io()),
+ routing_manager_base(_host),
is_connected_(false),
is_started_(false),
state_(state_type_e::ST_DEREGISTERED),
- host_(_host),
- client_(_host->get_client()),
- configuration_(host_->get_configuration()),
- serializer_(std::make_shared<serializer>()),
- deserializer_(std::make_shared<deserializer>()),
sender_(0),
- receiver_(0) {
+ receiver_(0)
+{
}
routing_manager_proxy::~routing_manager_proxy() {
}
-boost::asio::io_service & routing_manager_proxy::get_io() {
- return (io_);
-}
-
-client_t routing_manager_proxy::get_client() const {
- return client_;
-}
-
void routing_manager_proxy::init() {
- serializer_->create_data(configuration_->get_max_message_size_local());
+ routing_manager_base::init();
std::stringstream its_sender_path;
sender_ = create_local(VSOMEIP_ROUTING_CLIENT);
@@ -63,6 +60,7 @@ void routing_manager_proxy::init() {
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
@@ -75,30 +73,45 @@ void routing_manager_proxy::init() {
#ifdef WIN32
VSOMEIP_DEBUG << "Listening at " << port;
#else
+ ::umask(previous_mask);
VSOMEIP_DEBUG<< "Listening at " << its_client.str();
#endif
}
void routing_manager_proxy::start() {
- if (sender_)
+ is_started_ = true;
+
+ if (!sender_) {
+ // application has been stopped and started again
+ sender_ = create_local(VSOMEIP_ROUTING_CLIENT);
+ }
+ if (sender_) {
sender_->start();
+ }
if (receiver_)
receiver_->start();
-
- if (is_connected_) {
- register_application();
- }
-
- is_started_ = true;
}
void routing_manager_proxy::stop() {
deregister_application();
- if (receiver_)
+ if (receiver_) {
receiver_->stop();
+ }
+ if (sender_) {
+ sender_->stop();
+ }
+
+ for (auto client: get_connected_clients()) {
+ if (client != VSOMEIP_ROUTING_CLIENT) {
+ remove_local(client);
+ }
+ }
+
+ // delete the sender
+ sender_ = nullptr;
std::stringstream its_client;
its_client << VSOMEIP_BASE_PATH << std::hex << client_;
#ifdef WIN32
@@ -113,14 +126,14 @@ void routing_manager_proxy::stop() {
void routing_manager_proxy::offer_service(client_t _client, service_t _service,
instance_t _instance, major_version_t _major, minor_version_t _minor) {
- service_versions_[_service][_instance] = _major;
+ routing_manager_base::offer_service(_client, _service, _instance, _major, _minor);
+
if (is_connected_) {
send_offer_service(_client, _service, _instance, _major, _minor);
- } else {
- service_data_t offer = { _service, _instance, _major, _minor, false };
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- 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);
}
void routing_manager_proxy::send_offer_service(client_t _client,
@@ -149,16 +162,15 @@ void routing_manager_proxy::send_offer_service(client_t _client,
}
void routing_manager_proxy::stop_offer_service(client_t _client,
- service_t _service, instance_t _instance) {
+ service_t _service, instance_t _instance,
+ major_version_t _major, minor_version_t _minor) {
(void)_client;
- auto its_service = service_versions_.find(_service);
- if (its_service != service_versions_.end()) {
- auto its_instance = its_service->second.find(_instance);
- if (its_instance != its_service->second.end()) {
- its_service->second.clear();
- }
- }
+ routing_manager_base::stop_offer_service(_client, _service, _instance, _major, _minor);
+
+ // Reliable/Unreliable unimportant as routing_proxy does not
+ // 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];
@@ -174,45 +186,49 @@ void routing_manager_proxy::stop_offer_service(client_t _client,
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));
- } else {
- 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;
- }
- it++;
+ }
+ 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;
}
-
- if (it != pending_offers_.end()) pending_offers_.erase(it);
+ it++;
}
+ if (it != pending_offers_.end()) pending_offers_.erase(it);
}
void routing_manager_proxy::request_service(client_t _client,
service_t _service, instance_t _instance, major_version_t _major,
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);
}
void routing_manager_proxy::release_service(client_t _client,
service_t _service, instance_t _instance) {
- (void)_client;
- (void)_service;
- (void)_instance;
+ routing_manager_base::release_service(_client, _service, _instance);
+ send_release_service(_client, _service, _instance);
}
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) {
- (void)_client;
+ bool _is_field, bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) {
+
+ (void)_is_shadow;
+ (void)_is_cache_placeholder;
- if (_is_field)
- fields_[_service][_instance].insert(_event);
+ 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);
@@ -221,18 +237,9 @@ void routing_manager_proxy::register_event(client_t _client,
void routing_manager_proxy::unregister_event(client_t _client,
service_t _service, instance_t _instance, event_t _event,
bool _is_provided) {
- (void)_client;
- auto find_service = fields_.find(_service);
- if (find_service != fields_.end()) {
- auto find_instance = find_service->second.find(_instance);
- if (find_instance != find_service->second.end()) {
- find_instance->second.erase(_event);
- if (find_instance->second.size() == 0)
- find_service->second.erase(find_instance);
- }
- if (find_service->second.size() == 0)
- fields_.erase(find_service);
- }
+
+ routing_manager_base::unregister_event(_client, _service, _instance,
+ _event, _is_provided);
if (is_connected_) {
byte_t its_command[VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE];
@@ -250,33 +257,30 @@ void routing_manager_proxy::unregister_event(client_t _client,
sizeof(_instance));
std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_event,
sizeof(_event));
- its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5]
+ its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6]
= static_cast<byte_t>(_is_provided);
sender_->send(its_command, sizeof(its_command));
- } else {
- 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;
- }
- it++;
+ }
+ 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 (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,
event_t _event) const {
- auto find_service = fields_.find(_service);
- if (find_service != fields_.end()) {
- auto find_instance = find_service->second.find(_instance);
- if (find_instance != find_service->second.end())
- return (find_instance->second.find(_event) != find_instance->second.end());
+ auto event = find_event(_service, _instance, _event);
+ if (event && event->is_field()) {
+ return true;
}
return false;
}
@@ -284,15 +288,15 @@ 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_) {
+
+ if (is_connected_ && is_available(_service, _instance, _major)) {
send_subscribe(_client, _service, _instance, _eventgroup, _major,
_subscription_type);
- } else {
- eventgroup_data_t subscription = { _service, _instance, _eventgroup, _major,
- _subscription_type};
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- 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,
@@ -305,8 +309,8 @@ void routing_manager_proxy::send_subscribe(client_t _client, service_t _service,
- VSOMEIP_COMMAND_HEADER_SIZE;
its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE;
- std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_,
- sizeof(client_));
+ 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,
@@ -316,10 +320,71 @@ void routing_manager_proxy::send_subscribe(client_t _client, service_t _service,
std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup,
sizeof(_eventgroup));
its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] = _major;
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7], &_subscription_type,
+ its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7] = 0; // local subscriber
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_subscription_type,
sizeof(_subscription_type));
- sender_->send(its_command, sizeof(its_command));
+ client_t target_client = find_local_client(_service, _instance);
+ if (target_client != VSOMEIP_ROUTING_CLIENT) {
+ 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));
+ }
+}
+
+void routing_manager_proxy::send_subscribe_nack(client_t _subscriber,
+ service_t _service, instance_t _instance, eventgroup_t _eventgroup) {
+ byte_t its_command[VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE];
+ uint32_t its_size = VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE
+ - VSOMEIP_COMMAND_HEADER_SIZE;
+
+ client_t its_client = get_client();
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_NACK;
+ std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &its_client,
+ sizeof(its_client));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size,
+ sizeof(its_size));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service,
+ sizeof(_service));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance,
+ sizeof(_instance));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup,
+ sizeof(_eventgroup));
+
+ auto its_target = find_local(_subscriber);
+ if (its_target) {
+ its_target->send(its_command, sizeof(its_command));
+ } else {
+ sender_->send(its_command, sizeof(its_command));
+ }
+}
+
+void routing_manager_proxy::send_subscribe_ack(client_t _subscriber,
+ service_t _service, instance_t _instance, eventgroup_t _eventgroup) {
+ byte_t its_command[VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE];
+ uint32_t its_size = VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE
+ - VSOMEIP_COMMAND_HEADER_SIZE;
+
+ client_t its_client = get_client();
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_ACK;
+ std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &its_client,
+ sizeof(its_client));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size,
+ sizeof(its_size));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service,
+ sizeof(_service));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance,
+ sizeof(_instance));
+ std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup,
+ sizeof(_eventgroup));
+
+ auto its_target = find_local(_subscriber);
+ if (its_target) {
+ its_target->send(its_command, sizeof(its_command));
+ } else {
+ sender_->send(its_command, sizeof(its_command));
+ }
}
void routing_manager_proxy::unsubscribe(client_t _client, service_t _service,
@@ -332,8 +397,8 @@ void routing_manager_proxy::unsubscribe(client_t _client, service_t _service,
- 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_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,
@@ -343,84 +408,92 @@ void routing_manager_proxy::unsubscribe(client_t _client, service_t _service,
std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup,
sizeof(_eventgroup));
- sender_->send(its_command, sizeof(its_command));
- } else {
- 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;
- }
- it++;
+ 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));
}
-
- if (it != pending_subscriptions_.end()) pending_subscriptions_.erase(it);
}
-}
-
-bool routing_manager_proxy::send(client_t its_client,
- std::shared_ptr<message> _message,
- bool _flush) {
- bool is_sent(false);
-
- std::lock_guard<std::mutex> its_lock(serialize_mutex_);
- if (serializer_->serialize(_message.get())) {
- is_sent = send(its_client, serializer_->get_data(),
- serializer_->get_size(), _message->get_instance(),
- _flush, _message->is_reliable());
- serializer_->reset();
- } else {
- VSOMEIP_ERROR << "Failed to serialize message. Check message size!";
+ 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;
+ }
+ it++;
}
- return (is_sent);
+ 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 is_sent(false);
-
- std::shared_ptr<endpoint> its_target;
+ bool _reliable,
+ bool _initial) {
+ bool is_sent(false);
if (_size > VSOMEIP_MESSAGE_TYPE_POS) {
+ std::shared_ptr<endpoint> its_target;
if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) {
+ // Request
service_t its_service = VSOMEIP_BYTES_TO_WORD(
_data[VSOMEIP_SERVICE_POS_MIN],
_data[VSOMEIP_SERVICE_POS_MAX]);
std::lock_guard<std::mutex> its_lock(send_mutex_);
- its_target = find_local(its_service, _instance);
- } else {
+ client_t its_client = find_local_client(its_service, _instance);
+ if (its_client != VSOMEIP_ROUTING_CLIENT) {
+ if (known_clients_.find(its_client) != known_clients_.end()) {
+ its_target = find_or_create_local(its_client);
+ }
+ }
+ } else if (!utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) {
+ // Response
client_t its_client = VSOMEIP_BYTES_TO_WORD(
_data[VSOMEIP_CLIENT_POS_MIN],
_data[VSOMEIP_CLIENT_POS_MAX]);
std::lock_guard<std::mutex> its_lock(send_mutex_);
- its_target = find_local(its_client);
+ if (its_client != VSOMEIP_ROUTING_CLIENT) {
+ if (known_clients_.find(its_client) != known_clients_.end()) {
+ its_target = find_or_create_local(its_client);
+ }
+ }
+ } 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);
+ } 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);
+ }
}
-
- // If no direct endpoint could be found, route to stub
- if (!its_target)
+ // 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_;
-
- std::vector<byte_t> its_command(
- VSOMEIP_COMMAND_HEADER_SIZE + _size + sizeof(instance_t)
- + sizeof(bool) + sizeof(bool));
- its_command[VSOMEIP_COMMAND_TYPE_POS]
- = utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) ?
- VSOMEIP_NOTIFY : VSOMEIP_SEND;
-
- std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client,
- sizeof(client_t));
- std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &_size,
- sizeof(_size));
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], _data, _size);
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size],
- &_instance, sizeof(instance_t));
- its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size + sizeof(instance_t)] =
- _flush;
- its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size + sizeof(instance_t)
- + sizeof(bool)] = _reliable;
- is_sent = its_target->send(&its_command[0], uint32_t(its_command.size()));
+ }
+#ifdef USE_DLT
+ else {
+ uint16_t its_data_size
+ = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size);
+
+ tc::trace_header its_header;
+ if (its_header.prepare(its_target, true))
+ tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
+ _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;
+ }
+ is_sent = send_local(its_target, _client, _data, _size, _instance, _flush, _reliable, command, false, _initial);
}
return (is_sent);
}
@@ -451,44 +524,26 @@ void routing_manager_proxy::notify(
its_notification->set_instance(_instance);
its_notification->set_method(_event);
its_notification->set_payload(_payload);
- auto its_service = service_versions_.find(_service);
- if (its_service != service_versions_.end()) {
- auto its_instance = its_service->second.find(_instance);
- if (its_instance != its_service->second.end()) {
- its_notification->set_interface_version(its_instance->second);
- }
+ auto service_info = find_service(_service, _instance);
+ if (service_info) {
+ its_notification->set_interface_version(service_info->get_major());
}
if (is_connected_) {
- send(VSOMEIP_ROUTING_CLIENT, its_notification, true);
- } else if (is_field(_service, _instance, _event)) {
+ 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;
}
}
-void routing_manager_proxy::notify_one(service_t _service, instance_t _instance,
- event_t _event, std::shared_ptr<payload> _payload, client_t _client) {
-
- 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);
- its_notification->set_client(_client);
- auto its_service = service_versions_.find(_service);
- if (its_service != service_versions_.end()) {
- auto its_instance = its_service->second.find(_instance);
- if (its_instance != its_service->second.end()) {
- its_notification->set_interface_version(its_instance->second);
- }
- }
- send(VSOMEIP_ROUTING_CLIENT, its_notification, true);
-}
-
void routing_manager_proxy::on_connect(std::shared_ptr<endpoint> _endpoint) {
- is_connected_ = is_connected_ || (_endpoint == sender_);
+ if (_endpoint != sender_) {
+ return;
+ }
+ is_connected_ = true;
if (is_connected_ && is_started_) {
+ VSOMEIP_DEBUG << std::hex << "Client " << client_
+ << " successfully connected to routing ~> registering..";
register_application();
}
}
@@ -510,10 +565,16 @@ void routing_manager_proxy::on_error(const byte_t *_data, length_t _length,
(void)(_receiver);
}
+void routing_manager_proxy::release_port(uint16_t _port, bool _reliable) {
+ (void)_port;
+ (void)_reliable;
+ // intentionally empty
+}
void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
- endpoint *_receiver) {
+ endpoint *_receiver, const boost::asio::ip::address &_destination) {
(void)_receiver;
+ (void)_destination;
#if 0
std::stringstream msg;
msg << "rmp::on_message: ";
@@ -528,7 +589,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;
- ttl_t its_ttl;
+ bool subscription_accepted;
if (_size > VSOMEIP_COMMAND_SIZE_POS_MAX) {
its_command = _data[VSOMEIP_COMMAND_TYPE_POS];
@@ -542,9 +603,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(instance_t));
+ - sizeof(bool) - sizeof(bool)], sizeof(instance_t));
bool its_reliable;
- std::memcpy(&its_reliable, &_data[_size - sizeof(bool)],
+ std::memcpy(&its_reliable, &_data[_size - sizeof(bool) - sizeof(bool)],
sizeof(its_reliable));
deserializer_->set_data(&_data[VSOMEIP_COMMAND_PAYLOAD_POS],
its_length);
@@ -553,9 +614,16 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
if (its_message) {
its_message->set_instance(its_instance);
its_message->set_reliable(its_reliable);
+ 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);
} else {
- VSOMEIP_ERROR << "Deserialization of vSomeIP message failed";
+ VSOMEIP_ERROR << "Routing proxy: on_message: "
+ << "SomeIP-Header deserialization failed!";
}
deserializer_->reset();
}
@@ -567,6 +635,8 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
case VSOMEIP_PING:
send_pong();
+ VSOMEIP_TRACE << "PING("
+ << std::hex << std::setw(4) << std::setfill('0') << client_ << ")";
break;
case VSOMEIP_SUBSCRIBE:
@@ -578,10 +648,36 @@ 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));
- std::memcpy(&its_ttl, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7],
- sizeof(its_ttl));
+ bool is_remote_subscriber;
+ std::memcpy(&is_remote_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7],
+ sizeof(is_remote_subscriber));
- host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, true);
+ 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);
+ }
+ }
+ } 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);
+ }
+ }
+ 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:
@@ -592,6 +688,44 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4],
sizeof(its_eventgroup));
host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, false);
+ routing_manager_base::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_NACK:
+ std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
+ sizeof(its_service));
+ std::memcpy(&its_instance, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2],
+ sizeof(its_instance));
+ std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4],
+ sizeof(its_eventgroup));
+
+ on_subscribe_nack(its_client, its_service, its_instance, its_eventgroup);
+ VSOMEIP_DEBUG << "SUBSCRIBE NACK("
+ << 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:
+ std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
+ sizeof(its_service));
+ std::memcpy(&its_instance, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2],
+ sizeof(its_instance));
+ std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4],
+ sizeof(its_eventgroup));
+
+ on_subscribe_ack(its_client, its_service, its_instance, its_eventgroup);
+ VSOMEIP_DEBUG << "SUBSCRIBE ACK("
+ << std::hex << std::setw(4) << std::setfill('0') << its_client << "): ["
+ << std::hex << std::setw(4) << std::setfill('0') << its_service << "."
+ << std::hex << std::setw(4) << std::setfill('0') << its_instance << "."
+ << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "]";
break;
default:
@@ -605,16 +739,19 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data,
#if 0
std::stringstream msg;
msg << "rmp::on_routing_info(" << std::hex << client_ << "): ";
- for (int i = 0; i < _size; ++i)
+ for (uint32_t i = 0; i < _size; ++i)
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);
- std::map<service_t, std::map<instance_t, client_t> > old_local_services;
+ bool restart_sender(_size == 0);
+ 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;
{
std::lock_guard<std::mutex> its_lock(local_services_mutex_);
old_local_services = local_services_;
local_services_.clear();
+ std::unordered_set<client_t> known_clients;
uint32_t i = 0;
while (i + sizeof(uint32_t) <= _size) {
@@ -627,11 +764,10 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data,
std::memcpy(&its_client, &_data[i], sizeof(client_t));
i += uint32_t(sizeof(client_t));
- if (its_client != client_) {
- (void) find_or_create_local(its_client);
- } else {
+ if (its_client == client_) {
its_state = state_type_e::ST_REGISTERED;
}
+ known_clients.insert(its_client);
uint32_t j = 0;
while (j + sizeof(uint32_t) <= its_client_size) {
@@ -639,22 +775,29 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data,
std::memcpy(&its_services_size, &_data[i + j], sizeof(uint32_t));
j += uint32_t(sizeof(uint32_t));
- if (its_services_size >= sizeof(service_t) + sizeof(instance_t)) {
+ if (its_services_size >= sizeof(service_t) + sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t)) {
its_services_size -= uint32_t(sizeof(service_t));
service_t its_service;
std::memcpy(&its_service, &_data[i + j], sizeof(service_t));
j += uint32_t(sizeof(service_t));
- while (its_services_size >= sizeof(instance_t)) {
+ while (its_services_size >= sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t)) {
instance_t its_instance;
std::memcpy(&its_instance, &_data[i + j], sizeof(instance_t));
j += uint32_t(sizeof(instance_t));
- if (its_client != client_)
- local_services_[its_service][its_instance] = its_client;
+ major_version_t its_major;
+ std::memcpy(&its_major, &_data[i + j], sizeof(major_version_t));
+ j += uint32_t(sizeof(major_version_t));
- its_services_size -= uint32_t(sizeof(instance_t));
+ minor_version_t its_minor;
+ std::memcpy(&its_minor, &_data[i + j], sizeof(minor_version_t));
+ j += uint32_t(sizeof(minor_version_t));
+
+ local_services_[its_service][its_instance] = std::make_tuple(its_major, its_minor, its_client);
+
+ its_services_size -= uint32_t(sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t) );
}
}
}
@@ -662,10 +805,24 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data,
i += j;
}
}
+ // Which clients are no longer needed?!
+ for (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.";
+ }
host_->on_state(its_state);
state_ = its_state;
}
@@ -677,12 +834,15 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data,
for (auto j : i.second) {
auto found_instance = found_service->second.find(j.first);
if (found_instance == found_service->second.end()) {
- host_->on_availability(i.first, j.first, false);
+ 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));
}
}
} else {
for (auto j : i.second) {
- host_->on_availability(i.first, j.first, false);
+ 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));
}
}
}
@@ -694,15 +854,50 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data,
for (auto j : i.second) {
auto found_instance = found_service->second.find(j.first);
if (found_instance == found_service->second.end()) {
- host_->on_availability(i.first, j.first, true);
+ 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) {
- host_->on_availability(i.first, j.first, true);
+ 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));
}
}
}
+
+ 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_);
+ }
+ }
+ }
+ pending_ingoing_subscripitons_.erase(client);
+ }
+
+ if (clients_to_delete.size() || restart_sender) {
+ std::async(std::launch::async, [this, clients_to_delete, restart_sender] () {
+ for (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();
+ }
+ });
+ }
}
void routing_manager_proxy::register_application() {
@@ -721,6 +916,7 @@ void routing_manager_proxy::register_application() {
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_,
@@ -729,7 +925,8 @@ void routing_manager_proxy::register_application() {
for (auto &s : pending_notifications_) {
for (auto &i : s.second) {
for (auto &pn : i.second) {
- send(VSOMEIP_ROUTING_CLIENT, pn.second, true);
+ routing_manager_base::notify(s.first, i.first,
+ pn.first, pn.second->get_payload());
}
}
}
@@ -738,16 +935,6 @@ void routing_manager_proxy::register_application() {
send_request_service(client_, po.service_, po.instance_,
po.major_, po.minor_, po.use_exclusive_proxy_);
}
-
- std::lock_guard<std::mutex> its_lock(pending_mutex_);
- for (auto &ps : pending_subscriptions_)
- send_subscribe(client_, ps.service_, ps.instance_,
- ps.eventgroup_, ps.major_, ps.subscription_type_);
-
- pending_offers_.clear();
- pending_requests_.clear();
- pending_notifications_.clear();
- pending_subscriptions_.clear();
}
}
@@ -764,75 +951,6 @@ void routing_manager_proxy::deregister_application() {
(void)sender_->send(&its_command[0], uint32_t(its_command.size()));
}
-std::shared_ptr<endpoint> routing_manager_proxy::find_local(client_t _client) {
- std::shared_ptr<endpoint> its_endpoint;
- auto found_endpoint = local_endpoints_.find(_client);
- if (found_endpoint != local_endpoints_.end()) {
- its_endpoint = found_endpoint->second;
- }
- return (its_endpoint);
-}
-
-std::shared_ptr<endpoint> routing_manager_proxy::create_local(
- client_t _client) {
- std::stringstream its_path;
- its_path << VSOMEIP_BASE_PATH << std::hex << _client;
-
-#ifdef WIN32
- boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1");
- int port = VSOMEIP_INTERNAL_BASE_PORT + _client;
- VSOMEIP_DEBUG<< "Connecting to ["
- << std::hex << _client << "] at " << port;
-#else
- VSOMEIP_DEBUG<< "Connecting to ["
- << std::hex << _client << "] at " << its_path.str();
-#endif
-
- std::shared_ptr<endpoint> its_endpoint = std::make_shared<
- local_client_endpoint_impl>(shared_from_this(),
-#ifdef WIN32
- boost::asio::ip::tcp::endpoint(address, port),
-#else
- boost::asio::local::stream_protocol::endpoint(its_path.str()),
-#endif
- io_, configuration_->get_max_message_size_local());
-
- local_endpoints_[_client] = its_endpoint;
-
- return (its_endpoint);
-}
-
-std::shared_ptr<endpoint> routing_manager_proxy::find_or_create_local(
- client_t _client) {
- std::shared_ptr<endpoint> its_endpoint(find_local(_client));
- if (0 == its_endpoint) {
- its_endpoint = create_local(_client);
- its_endpoint->start();
- }
- return (its_endpoint);
-}
-
-void routing_manager_proxy::remove_local(client_t _client) {
- std::shared_ptr<endpoint> its_endpoint(find_local(_client));
- if (its_endpoint)
- its_endpoint->stop();
- local_endpoints_.erase(_client);
-}
-
-std::shared_ptr<endpoint> routing_manager_proxy::find_local(service_t _service,
- instance_t _instance) {
- client_t its_client(0);
- 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()) {
- its_client = found_instance->second;
- }
- }
- return (find_local(its_client));
-}
-
void routing_manager_proxy::send_pong() const {
byte_t its_pong[] = {
VSOMEIP_PONG, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
@@ -877,6 +995,28 @@ void routing_manager_proxy::send_request_service(client_t _client, service_t _se
}
}
+void routing_manager_proxy::send_release_service(client_t _client, service_t _service,
+ instance_t _instance) {
+ (void)_client;
+ byte_t its_command[VSOMEIP_RELEASE_SERVICE_COMMAND_SIZE];
+ 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));
+ }
+}
+
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,
@@ -930,4 +1070,97 @@ void routing_manager_proxy::send_register_event(client_t _client,
}
}
+void routing_manager_proxy::on_subscribe_ack(client_t _client,
+ service_t _service, instance_t _instance, eventgroup_t _eventgroup) {
+ (void)_client;
+ host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/);
+}
+
+void routing_manager_proxy::on_subscribe_nack(client_t _client,
+ service_t _service, instance_t _instance, eventgroup_t _eventgroup) {
+ (void)_client;
+ host_->on_subscription_error(_service, _instance, _eventgroup, 0x7 /*Rejected*/);
+}
+
+void routing_manager_proxy::on_identify_response(client_t _client, service_t _service,
+ instance_t _instance, bool _reliable) {
+ static const uint32_t size = uint32_t(VSOMEIP_COMMAND_HEADER_SIZE + sizeof(service_t) + sizeof(instance_t)
+ + sizeof(bool));
+ byte_t its_command[size];
+ uint32_t its_size = size - VSOMEIP_COMMAND_HEADER_SIZE;
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_ID_RESPONSE;
+ 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], &_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);
+}
+
+void routing_manager_proxy::cache_event_payload(
+ const std::shared_ptr<message> &_message) {
+ const service_t its_service(_message->get_service());
+ const instance_t its_instance(_message->get_instance());
+ const method_t its_method(_message->get_method());
+ std::shared_ptr<event> its_event = find_event(its_service, its_instance, its_method);
+ if (its_event) {
+ if (its_event->is_field()) {
+ its_event->set_payload_dont_notify(_message->get_payload());
+ }
+ } else {
+ // we received a event which was not yet requested
+ std::set<eventgroup_t> its_eventgroups;
+ // 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);
+ 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());
+ }
+ }
+
+}
+
+void routing_manager_proxy::send_pending_subscriptions(service_t _service,
+ instance_t _instance, major_version_t _major) {
+ for (auto &ps : pending_subscriptions_) {
+ if (ps.service_ == _service &&
+ ps.instance_ == _instance && ps.major_ == _major) {
+ send_subscribe(client_, ps.service_, ps.instance_,
+ ps.eventgroup_, ps.major_, ps.subscription_type_);
+ }
+ }
+}
+
+void routing_manager_proxy::on_stop_offer_service(service_t _service,
+ instance_t _instance,
+ major_version_t _major,
+ minor_version_t _minor) {
+ (void) _major;
+ (void) _minor;
+ {
+ std::lock_guard<std::mutex> its_lock(events_mutex_);
+ auto its_events_service = events_.find(_service);
+ if (its_events_service != events_.end()) {
+ auto its_events_instance = its_events_service->second.find(_instance);
+ if (its_events_instance != its_events_service->second.end()) {
+ for (auto &e : its_events_instance->second)
+ e.second->unset_payload();
+ }
+ }
+ }
+}
+
} // namespace vsomeip
diff --git a/implementation/routing/src/routing_manager_stub.cpp b/implementation/routing/src/routing_manager_stub.cpp
index 7f8aad8..01ca85a 100644
--- a/implementation/routing/src/routing_manager_stub.cpp
+++ b/implementation/routing/src/routing_manager_stub.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -6,7 +6,12 @@
#include <chrono>
#include <functional>
#include <iomanip>
-#include <iostream>
+
+#ifndef WIN32
+// for umask
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
#include <boost/system/error_code.hpp>
@@ -21,6 +26,7 @@
#include "../../endpoints/include/local_server_endpoint_impl.hpp"
#include "../../logging/include/logger.hpp"
#include "../../utility/include/byteorder.hpp"
+#include "../../utility/include/utility.hpp"
namespace vsomeip {
@@ -30,7 +36,8 @@ routing_manager_stub::routing_manager_stub(
host_(_host),
io_(_host->get_io()),
watchdog_timer_(_host->get_io()),
- configuration_(_configuration) {
+ configuration_(_configuration),
+ routingCommandSize_(VSOMEIP_ROUTING_INFO_SIZE_INIT) {
}
routing_manager_stub::~routing_manager_stub() {
@@ -40,13 +47,21 @@ 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_ =
@@ -58,23 +73,62 @@ void routing_manager_stub::init() {
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
}
void routing_manager_stub::start() {
endpoint_->start();
-
- // Start watchdog (TODO: only if configured)
- start_watchdog();
+ local_receiver_->start();
+
+ client_registration_running_ = true;
+ client_registration_thread_ = std::make_shared<std::thread>(
+ std::bind(&routing_manager_stub::client_registration_func, this));
+
+ if (configuration_->is_watchdog_enabled()) {
+ VSOMEIP_INFO << "Watchdog is enabled : Timeout in ms = "
+ << configuration_->get_watchdog_timeout()
+ << " : Allowed missing pongs = "
+ << configuration_->get_allowed_missing_pongs()
+ << ".";
+ start_watchdog();
+ } else {
+ VSOMEIP_INFO << "Watchdog is disabled!";
+ }
}
void routing_manager_stub::stop() {
+ client_registration_running_ = false;
+ client_registration_condition_.notify_one();
+ if (client_registration_thread_->joinable()) {
+ client_registration_thread_->join();
+ }
+
watchdog_timer_.cancel();
endpoint_->stop();
+ local_receiver_->stop();
+
#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());
#endif
+
+ broadcast_routing_info(true);
}
void routing_manager_stub::on_connect(std::shared_ptr<endpoint> _endpoint) {
@@ -95,15 +149,22 @@ void routing_manager_stub::on_error(const byte_t *_data, length_t _length,
(void)(_receiver);
}
+void routing_manager_stub::release_port(uint16_t _port, bool _reliable) {
+ (void)_port;
+ (void)_reliable;
+ // intentionally empty
+}
+
void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
- endpoint *_receiver) {
+ endpoint *_receiver, const boost::asio::ip::address &_destination) {
(void)_receiver;
+ (void)_destination;
#if 0
std::stringstream msg;
msg << "rms::on_message: ";
for (length_t i = 0; i < _size; ++i)
msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " ";
- VSOMEIP_DEBUG << msg.str();
+ VSOMEIP_INFO << msg.str();
#endif
if (VSOMEIP_COMMAND_SIZE_POS_MAX < _size) {
@@ -125,6 +186,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
bool its_reliable(false);
bool use_exclusive_proxy(false);
subscription_type_e its_subscription_type;
+ bool is_remote_subscriber(false);
its_command = _data[VSOMEIP_COMMAND_TYPE_POS];
std::memcpy(&its_client, &_data[VSOMEIP_COMMAND_CLIENT_POS],
@@ -136,21 +198,31 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
if (its_size <= _size - VSOMEIP_COMMAND_HEADER_SIZE) {
switch (its_command) {
case VSOMEIP_REGISTER_APPLICATION:
- on_register_application(its_client);
- VSOMEIP_DEBUG << "Application/Client "
+ {
+ std::lock_guard<std::mutex> its_lock(client_registration_mutex_);
+ VSOMEIP_INFO << "Application/Client "
<< std::hex << std::setw(4) << std::setfill('0')
- << its_client << " got registered!";
+ << its_client << " is registering.";
+ pending_client_registrations_[its_client].push_back(true);
+ client_registration_condition_.notify_one();
+ }
break;
case VSOMEIP_DEREGISTER_APPLICATION:
- on_deregister_application(its_client);
- VSOMEIP_DEBUG << "Application/Client "
- << std::hex << std::setw(4) << std::setfill('0')
- << its_client << " got deregistered!";
+ {
+ std::lock_guard<std::mutex> its_lock(client_registration_mutex_);
+ VSOMEIP_INFO << "Application/Client "
+ << std::hex << std::setw(4) << std::setfill('0')
+ << its_client << " is deregistering.";
+ pending_client_registrations_[its_client].push_back(false);
+ client_registration_condition_.notify_one();
+ }
break;
case VSOMEIP_PONG:
on_pong(its_client);
+ VSOMEIP_TRACE << "PONG("
+ << std::hex << std::setw(4) << std::setfill('0') << its_client << ")";
break;
case VSOMEIP_OFFER_SERVICE:
@@ -165,7 +237,11 @@ 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);
- on_offer_service(its_client, its_service, its_instance);
+ 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:
@@ -174,8 +250,18 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
std::memcpy(&its_instance,
&_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2],
sizeof(its_instance));
- host_->stop_offer_service(its_client, its_service, its_instance);
- on_stop_offer_service(its_client, its_service, its_instance);
+
+ std::memcpy(&its_major, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4],
+ sizeof(its_major));
+ std::memcpy(&its_minor, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 5],
+ 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:
@@ -187,10 +273,18 @@ void routing_manager_stub::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));
- std::memcpy(&its_subscription_type, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7],
+ std::memcpy(&is_remote_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7],
+ sizeof(is_remote_subscriber));
+ std::memcpy(&its_subscription_type, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8],
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:
@@ -202,6 +296,41 @@ 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:
+ std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
+ sizeof(its_service));
+ std::memcpy(&its_instance, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2],
+ sizeof(its_instance));
+ std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4],
+ sizeof(its_eventgroup));
+ host_->on_subscribe_ack(its_client, its_service, its_instance, its_eventgroup);
+ VSOMEIP_DEBUG << "SUBSCRIBE ACK("
+ << std::hex << std::setw(4) << std::setfill('0') << its_client << "): ["
+ << std::hex << std::setw(4) << std::setfill('0') << its_service << "."
+ << std::hex << std::setw(4) << std::setfill('0') << its_instance << "."
+ << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "]";
+ break;
+
+ case VSOMEIP_SUBSCRIBE_NACK:
+ std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
+ sizeof(its_service));
+ std::memcpy(&its_instance, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2],
+ sizeof(its_instance));
+ std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4],
+ sizeof(its_eventgroup));
+ host_->on_subscribe_nack(its_client, its_service, its_instance, its_eventgroup);
+ VSOMEIP_DEBUG << "SUBSCRIBE NACK("
+ << std::hex << std::setw(4) << std::setfill('0') << its_client << "): ["
+ << std::hex << std::setw(4) << std::setfill('0') << its_service << "."
+ << std::hex << std::setw(4) << std::setfill('0') << its_instance << "."
+ << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "]";
break;
case VSOMEIP_SEND:
@@ -209,8 +338,11 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
its_service = VSOMEIP_BYTES_TO_WORD(
its_data[VSOMEIP_SERVICE_POS_MIN],
its_data[VSOMEIP_SERVICE_POS_MAX]);
- std::memcpy(&its_instance, &_data[_size - 4], sizeof(its_instance));
- std::memcpy(&its_reliable, &_data[_size - 1], sizeof(its_reliable));
+ 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));
host_->on_message(its_service, its_instance, its_data, its_size, its_reliable);
break;
@@ -219,9 +351,24 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
its_service = VSOMEIP_BYTES_TO_WORD(
its_data[VSOMEIP_SERVICE_POS_MIN],
its_data[VSOMEIP_SERVICE_POS_MAX]);
- std::memcpy(&its_instance, &_data[_size - 4], sizeof(its_instance));
+ its_client = VSOMEIP_BYTES_TO_WORD(
+ 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));
host_->on_notification(its_client, its_service, its_instance, its_data, its_size);
break;
+ case VSOMEIP_NOTIFY_ONE:
+ its_data = &_data[VSOMEIP_COMMAND_PAYLOAD_POS];
+ its_service = VSOMEIP_BYTES_TO_WORD(
+ 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));
+ host_->on_notification(its_client, its_service, its_instance, its_data, its_size, true);
+ break;
case VSOMEIP_REQUEST_SERVICE:
std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
@@ -237,10 +384,24 @@ 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:
+ std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
+ sizeof(its_service));
+ std::memcpy(&its_instance,
+ &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2],
+ sizeof(its_instance));
+ 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:
@@ -265,9 +426,15 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
sizeof(its_eventgroup));
its_eventgroups.insert(its_eventgroup);
}
- host_->register_event(its_client, its_service,
+ host_->register_shadow_event(its_client, its_service,
its_instance, its_event, its_eventgroups,
is_field, is_provided);
+ VSOMEIP_DEBUG << "REGISTER EVENT("
+ << 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_event
+ << ":is_provider=" << is_provided << "]";
break;
case VSOMEIP_UNREGISTER_EVENT:
@@ -281,8 +448,31 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
std::memcpy(&is_provided,
&_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6],
sizeof(is_provided));
- host_->unregister_event(its_client, its_service, its_instance,
+ host_->unregister_shadow_event(its_client, its_service, its_instance,
its_event, is_provided);
+ VSOMEIP_DEBUG << "UNREGISTER EVENT("
+ << 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_event
+ << ":is_provider=" << is_provided << "]";
+ break;
+
+ case VSOMEIP_ID_RESPONSE:
+ std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
+ sizeof(its_service));
+ std::memcpy(&its_instance,
+ &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2],
+ sizeof(its_instance));
+ std::memcpy(&its_reliable,
+ &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4],
+ sizeof(its_reliable));
+ host_->on_identify_response(its_client, its_service, its_instance, its_reliable);
+ VSOMEIP_TRACE << "ID RESPONSE("
+ << 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
+ << ":is_reliable=" << its_reliable << "]";
break;
}
}
@@ -290,10 +480,15 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
}
void routing_manager_stub::on_register_application(client_t _client) {
- std::lock_guard<std::mutex> its_guard(routing_info_mutex_);
- (void)host_->find_or_create_local(_client);
- routing_info_[_client].first = 0;
- broadcast_routing_info();
+ auto endpoint = host_->find_local(_client);
+ if (endpoint) {
+ VSOMEIP_ERROR << "Registering application: " << std::hex << _client
+ << " failed. It is already registered!";
+ } else {
+ (void)host_->find_or_create_local(_client);
+ std::lock_guard<std::mutex> its_lock(routing_info_mutex_);
+ routing_info_[_client].first = 0;
+ }
}
void routing_manager_stub::on_deregister_application(client_t _client) {
@@ -302,29 +497,59 @@ void routing_manager_stub::on_deregister_application(client_t _client) {
if (its_info != routing_info_.end()) {
for (auto &its_service : its_info->second.second) {
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);
+ host_->on_stop_offer_service(its_service.first, its_instance.first, its_version.first, its_version.second);
routing_info_mutex_.lock();
}
}
}
+ routing_info_.erase(_client);
routing_info_mutex_.unlock();
-
- std::lock_guard<std::mutex> its_lock(routing_info_mutex_);
host_->remove_local(_client);
- routing_info_.erase(_client);
- broadcast_routing_info();
}
+void routing_manager_stub::client_registration_func(void) {
+ std::unique_lock<std::mutex> its_lock(client_registration_mutex_);
+ while (client_registration_running_) {
+ while (!pending_client_registrations_.size() && client_registration_running_) {
+ client_registration_condition_.wait(its_lock);
+ }
+
+ std::map<client_t, std::vector<bool>> its_registrations(
+ pending_client_registrations_);
+ pending_client_registrations_.clear();
+ its_lock.unlock();
+
+ for (auto r : its_registrations) {
+ for (auto b : r.second) {
+ if (b) {
+ on_register_application(r.first);
+ } else {
+ on_deregister_application(r.first);
+ }
+ }
+ }
+
+ {
+ std::lock_guard<std::mutex> its_guard(routing_info_mutex_);
+ broadcast_routing_info();
+ }
+
+ its_lock.lock();
+ }
+}
+
+
void routing_manager_stub::on_offer_service(client_t _client,
- service_t _service, instance_t _instance) {
+ service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) {
std::lock_guard<std::mutex> its_guard(routing_info_mutex_);
- routing_info_[_client].second[_service].insert(_instance);
+ routing_info_[_client].second[_service][_instance] = std::make_pair(_major, _minor);
broadcast_routing_info();
}
void routing_manager_stub::on_stop_offer_service(client_t _client,
- service_t _service, instance_t _instance) {
+ service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) {
std::lock_guard<std::mutex> its_guard(routing_info_mutex_);
auto found_client = routing_info_.find(_client);
if (found_client != routing_info_.end()) {
@@ -332,83 +557,138 @@ void routing_manager_stub::on_stop_offer_service(client_t _client,
if (found_service != found_client->second.second.end()) {
auto found_instance = found_service->second.find(_instance);
if (found_instance != found_service->second.end()) {
- found_service->second.erase(_instance);
- if (0 == found_service->second.size()) {
- found_client->second.second.erase(_service);
+ auto found_version = found_instance->second;
+ if( _major == found_version.first && _minor == found_version.second) {
+ found_service->second.erase(_instance);
+ if (0 == found_service->second.size()) {
+ found_client->second.second.erase(_service);
+ }
+ broadcast_routing_info();
+ } else if( _major == DEFAULT_MAJOR && _minor == DEFAULT_MINOR) {
+ found_service->second.erase(_instance);
+ if (0 == found_service->second.size()) {
+ found_client->second.second.erase(_service);
+ }
+ broadcast_routing_info();
}
- broadcast_routing_info();
}
}
}
}
-void routing_manager_stub::send_routing_info(client_t _client) {
+void routing_manager_stub::send_routing_info(client_t _client, bool _empty) {
std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client);
if (its_endpoint) {
- uint32_t its_capacity = 4096; // TODO: dynamic resizing
- std::vector<byte_t> its_command(its_capacity);
- its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_ROUTING_INFO;
- std::memset(&its_command[VSOMEIP_COMMAND_CLIENT_POS], 0,
- sizeof(client_t));
- uint32_t its_size = VSOMEIP_COMMAND_PAYLOAD_POS;
-
- for (auto &info : routing_info_) {
- uint32_t its_size_pos = its_size;
- uint32_t its_entry_size = its_size;
+ // Create the command vector & reserve some bytes initially..
+ // ..to avoid reallocation for smaller messages!
+ std::vector<byte_t> its_command;
+ its_command.reserve(routingCommandSize_);
+
+ // Routing command
+ its_command.push_back(VSOMEIP_ROUTING_INFO);
+
+ // Sender client
+ client_t client = 0x0;
+ for (uint32_t i = 0; i < sizeof(client_t); ++i) {
+ its_command.push_back(
+ reinterpret_cast<const byte_t*>(&client)[i]);
+ }
- its_size += uint32_t(sizeof(uint32_t)); // placeholder
+ // Overall size placeholder
+ byte_t size_placeholder = 0x0;
+ for (uint32_t i = 0; i < sizeof(uint32_t); ++i) {
+ its_command.push_back(size_placeholder);
+ }
- if (info.first != host_->get_client()) {
- std::memcpy(&its_command[its_size], &info.first, sizeof(client_t));
- } else {
- std::memset(&its_command[its_size], 0x0, sizeof(client_t));
+ // Routing info loop
+ for (auto &info : routing_info_) {
+ if (_empty) {
+ break;
}
-
- its_size += uint32_t(sizeof(client_t));
-
+ std::size_t its_size_pos = its_command.size();
+ std::size_t its_entry_size = its_command.size();
+ // Client size placeholder
+ byte_t placeholder = 0x0;
+ for (uint32_t i = 0; i < sizeof(uint32_t); ++i) {
+ its_command.push_back(placeholder);
+ }
+ // Client
+ for (uint32_t i = 0; i < sizeof(client_t); ++i) {
+ its_command.push_back(
+ reinterpret_cast<const byte_t*>(&info.first)[i]);
+ }
+ // Iterate over all services
for (auto &service : info.second.second) {
+ // Service entry size
uint32_t its_service_entry_size = uint32_t(sizeof(service_t)
- + service.second.size() * sizeof(instance_t));
-
- std::memcpy(&its_command[its_size], &its_service_entry_size,
- sizeof(uint32_t));
- its_size += uint32_t(sizeof(uint32_t));
-
- std::memcpy(&its_command[its_size], &service.first,
- sizeof(service_t));
- its_size += uint32_t(sizeof(service_t));
-
+ + service.second.size() * (sizeof(instance_t)
+ + sizeof(major_version_t) + sizeof(minor_version_t)));
+ for (uint32_t i = 0; i < sizeof(its_service_entry_size); ++i) {
+ its_command.push_back(
+ reinterpret_cast<const byte_t*>(&its_service_entry_size)[i]);
+ }
+ // Service
+ for (uint32_t i = 0; i < sizeof(service_t); ++i) {
+ its_command.push_back(
+ reinterpret_cast<const byte_t*>(&service.first)[i]);
+ }
+ // Iterate over all instances
for (auto &instance : service.second) {
- std::memcpy(&its_command[its_size], &instance,
- sizeof(instance_t));
- its_size += uint32_t(sizeof(instance_t));
+ // Instance
+ for (uint32_t i = 0; i < sizeof(instance_t); ++i) {
+ its_command.push_back(
+ reinterpret_cast<const byte_t*>(&instance)[i]);
+ }
+ // Major version
+ for (uint32_t i = 0; i < sizeof(major_version_t); ++i) {
+ its_command.push_back(
+ reinterpret_cast<const byte_t*>(&instance.second.first)[i]);
+ }
+ // Minor version
+ for (uint32_t i = 0; i < sizeof(minor_version_t); ++i) {
+ its_command.push_back(
+ reinterpret_cast<const byte_t*>(&instance.second.second)[i]);
+ }
}
}
-
- its_entry_size = its_size - its_entry_size - uint32_t(sizeof(uint32_t));
- std::memcpy(&its_command[its_size_pos], &its_entry_size,
- sizeof(uint32_t));
+ // File client size
+ its_entry_size = its_command.size() - its_entry_size - uint32_t(sizeof(uint32_t));
+ std::memcpy(&its_command[its_size_pos], &its_entry_size, sizeof(uint32_t));
}
- its_size -= VSOMEIP_COMMAND_PAYLOAD_POS;
- std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size,
- sizeof(its_size));
+ // File overall size
+ std::size_t its_size = its_command.size() - VSOMEIP_COMMAND_PAYLOAD_POS;
+ std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, sizeof(uint32_t));
its_size += VSOMEIP_COMMAND_PAYLOAD_POS;
+
+ // Double init size until it fits into the actual size for next run
+ size_t newInitSize;
+ for (newInitSize = VSOMEIP_ROUTING_INFO_SIZE_INIT;
+ newInitSize < its_size; newInitSize *= 2);
+ routingCommandSize_ = newInitSize;
+
#if 0
std::stringstream msg;
msg << "rms::send_routing_info ";
- for (int i = 0; i < its_size; ++i)
+ for (uint32_t i = 0; i < its_size; ++i)
msg << std::hex << std::setw(2) << std::setfill('0') << (int)its_command[i] << " ";
VSOMEIP_DEBUG << msg.str();
#endif
- its_endpoint->send(&its_command[0], its_size, true);
+
+ // Send routing info or error!
+ if(its_command.size() <= VSOMEIP_MAX_LOCAL_MESSAGE_SIZE) {
+ its_endpoint->send(&its_command[0], uint32_t(its_size), true);
+ } else {
+ VSOMEIP_ERROR << "Routing info exceeds maximum message size: Can't send!";
+ }
}
}
-void routing_manager_stub::broadcast_routing_info() {
+void routing_manager_stub::broadcast_routing_info(bool _empty) {
for (auto& info : routing_info_) {
- if (info.first != VSOMEIP_ROUTING_CLIENT)
- send_routing_info(info.first);
+ if (info.first != VSOMEIP_ROUTING_CLIENT) {
+ send_routing_info(info.first, _empty);
+ }
}
}
@@ -425,6 +705,104 @@ void routing_manager_stub::broadcast(std::vector<byte_t> &_command) const {
}
}
+void routing_manager_stub::send_subscribe(std::shared_ptr<vsomeip::endpoint> _target,
+ client_t _client, service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup, major_version_t _major, bool _is_remote_subscriber) {
+ if (_target) {
+ byte_t its_command[VSOMEIP_SUBSCRIBE_COMMAND_SIZE];
+ uint32_t its_size = VSOMEIP_SUBSCRIBE_COMMAND_SIZE
+ - VSOMEIP_COMMAND_HEADER_SIZE;
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE;
+ 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));
+ its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] = _major;
+ its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7] = _is_remote_subscriber;
+
+ _target->send(its_command, sizeof(its_command));
+ }
+}
+
+void routing_manager_stub::send_unsubscribe(std::shared_ptr<vsomeip::endpoint> _target,
+ client_t _client, service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup) {
+ if (_target) {
+ 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));
+
+ _target->send(its_command, sizeof(its_command));
+ }
+}
+
+void routing_manager_stub::send_subscribe_ack(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) {
+
+ 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
+ - VSOMEIP_COMMAND_HEADER_SIZE;
+
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_ACK;
+ 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));
+
+ its_endpoint->send(&its_command[0], sizeof(its_command), true);
+ }
+}
+
+void routing_manager_stub::send_subscribe_nack(client_t _client, service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) {
+
+ 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
+ - VSOMEIP_COMMAND_HEADER_SIZE;
+
+ its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_NACK;
+ 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));
+
+ its_endpoint->send(&its_command[0], sizeof(its_command), true);
+ }
+}
+
// Watchdog
void routing_manager_stub::broadcast_ping() const {
const byte_t its_ping[] = {
@@ -445,8 +823,9 @@ void routing_manager_stub::on_pong(client_t _client) {
}
void routing_manager_stub::start_watchdog() {
+ // Divide / 2 as start and check sleep each
watchdog_timer_.expires_from_now(
- std::chrono::milliseconds(VSOMEIP_DEFAULT_WATCHDOG_CYCLE)); // TODO: use config variable
+ std::chrono::milliseconds(configuration_->get_watchdog_timeout() / 2));
std::function<void(boost::system::error_code const &)> its_callback =
[this](boost::system::error_code const &_error) {
@@ -467,7 +846,7 @@ void routing_manager_stub::check_watchdog() {
broadcast_ping();
watchdog_timer_.expires_from_now(
- std::chrono::milliseconds(VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT)); // TODO: use config variable
+ std::chrono::milliseconds(configuration_->get_watchdog_timeout() / 2));
std::function<void(boost::system::error_code const &)> its_callback =
[this](boost::system::error_code const &_error) {
@@ -477,42 +856,27 @@ void routing_manager_stub::check_watchdog() {
std::lock_guard<std::mutex> its_lock(routing_info_mutex_);
for (auto i : routing_info_) {
if (i.first > 0 && i.first != host_->get_client()) {
- if (i.second.first > VSOMEIP_DEFAULT_MAX_MISSING_PONGS) { // TODO: use config variable
+ if (i.second.first > configuration_->get_allowed_missing_pongs()) {
VSOMEIP_WARNING << "Lost contact to application " << std::hex << (int)i.first;
lost.push_back(i.first);
}
}
}
-
- for (auto i : lost) {
- routing_info_.erase(i);
- }
}
- if (0 < lost.size())
- send_application_lost(lost);
-
+ for (auto i : lost) {
+ utility::release_client_id(i);
+ on_deregister_application(i);
+ }
start_watchdog();
};
watchdog_timer_.async_wait(its_callback);
}
-void routing_manager_stub::send_application_lost(std::list<client_t> &_lost) {
- uint32_t its_size = uint32_t(_lost.size() * sizeof(client_t));
- std::vector<byte_t> its_command(VSOMEIP_COMMAND_HEADER_SIZE + its_size);
- its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_APPLICATION_LOST;
- std::memset(&its_command[VSOMEIP_COMMAND_CLIENT_POS], 0, sizeof(client_t));
- std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size,
- sizeof(uint32_t));
-
- uint32_t its_offset = 0;
- for (auto i : _lost) {
- std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + its_offset], &i,
- sizeof(client_t));
- its_offset += uint32_t(sizeof(client_t));
- }
-
- broadcast(its_command);
+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);
}
} // namespace vsomeip
diff --git a/implementation/routing/src/serviceinfo.cpp b/implementation/routing/src/serviceinfo.cpp
index 75d11dd..fcf535e 100644
--- a/implementation/routing/src/serviceinfo.cpp
+++ b/implementation/routing/src/serviceinfo.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -12,11 +12,13 @@ serviceinfo::serviceinfo(major_version_t _major, minor_version_t _minor,
: group_(0),
major_(_major),
minor_(_minor),
- ttl_(_ttl),
+ ttl_(0),
reliable_(nullptr),
unreliable_(nullptr),
- multicast_group_(0xFFFF),
is_local_(_is_local) {
+
+ std::chrono::seconds ttl = static_cast<std::chrono::seconds> (_ttl);
+ ttl_ = std::chrono::duration_cast<std::chrono::milliseconds>(ttl);
}
serviceinfo::~serviceinfo() {
@@ -39,11 +41,21 @@ minor_version_t serviceinfo::get_minor() const {
}
ttl_t serviceinfo::get_ttl() const {
- return ttl_;
+ ttl_t ttl = static_cast<ttl_t>(std::chrono::duration_cast<std::chrono::seconds>(ttl_).count());
+ return ttl;
}
void serviceinfo::set_ttl(ttl_t _ttl) {
- ttl_ = _ttl;
+ std::chrono::seconds ttl = static_cast<std::chrono::seconds>(_ttl);
+ ttl_ = std::chrono::duration_cast<std::chrono::milliseconds> (ttl);
+}
+
+std::chrono::milliseconds serviceinfo::get_precise_ttl() const {
+ return ttl_;
+}
+
+void serviceinfo::set_precise_ttl(std::chrono::milliseconds _precise_ttl) {
+ ttl_ = _precise_ttl;
}
std::shared_ptr<endpoint> serviceinfo::get_endpoint(bool _reliable) const {
@@ -59,30 +71,6 @@ void serviceinfo::set_endpoint(std::shared_ptr<endpoint> _endpoint,
}
}
-const std::string & serviceinfo::get_multicast_address() const {
- return multicast_address_;
-}
-
-void serviceinfo::set_multicast_address(const std::string &_multicast_address) {
- multicast_address_ = _multicast_address;
-}
-
-uint16_t serviceinfo::get_multicast_port() const {
- return multicast_port_;
-}
-
-void serviceinfo::set_multicast_port(uint16_t _multicast_port) {
- multicast_port_ = _multicast_port;
-}
-
-eventgroup_t serviceinfo::get_multicast_group() const {
- return multicast_group_;
-}
-
-void serviceinfo::set_multicast_group(eventgroup_t _multicast_group) {
- multicast_group_ = _multicast_group;
-}
-
void serviceinfo::add_client(client_t _client) {
requesters_.insert(_client);
}
@@ -91,6 +79,10 @@ void serviceinfo::remove_client(client_t _client) {
requesters_.erase(_client);
}
+uint32_t serviceinfo::get_requesters_size() {
+ return static_cast<std::uint32_t>(requesters_.size());
+}
+
bool serviceinfo::is_local() const {
return is_local_;
}
diff --git a/implementation/runtime/include/application_impl.hpp b/implementation/runtime/include/application_impl.hpp
index fea635e..06f60eb 100644
--- a/implementation/runtime/include/application_impl.hpp
+++ b/implementation/runtime/include/application_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -17,6 +17,7 @@
#include <vector>
#include <boost/asio/signal_set.hpp>
+#include <boost/asio/system_timer.hpp>
#include <vsomeip/export.hpp>
#include <vsomeip/application.hpp>
@@ -47,8 +48,8 @@ public:
VSOMEIP_EXPORT void offer_service(service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor);
- VSOMEIP_EXPORT void stop_offer_service(service_t _service,
- instance_t _instance);
+ VSOMEIP_EXPORT void stop_offer_service(service_t _service, instance_t _instance,
+ major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR);
VSOMEIP_EXPORT void offer_event(service_t _service,
instance_t _instance, event_t _event,
@@ -73,12 +74,13 @@ public:
VSOMEIP_EXPORT void subscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, major_version_t _major,
- subscription_type_e _subscription_type);
+ subscription_type_e _subscription_type, event_t _event);
VSOMEIP_EXPORT void unsubscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup);
- VSOMEIP_EXPORT bool is_available(service_t _service, instance_t _instance) const;
+ VSOMEIP_EXPORT bool is_available(service_t _service, instance_t _instance,
+ major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR) const;
VSOMEIP_EXPORT void send(std::shared_ptr<message> _message, bool _flush);
@@ -97,15 +99,25 @@ public:
instance_t _instance, method_t _method);
VSOMEIP_EXPORT void register_availability_handler(service_t _service,
- instance_t _instance, availability_handler_t _handler);
+ instance_t _instance, availability_handler_t _handler,
+ major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR);
VSOMEIP_EXPORT void unregister_availability_handler(service_t _service,
- instance_t _instance);
+ instance_t _instance,
+ major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR);
VSOMEIP_EXPORT void register_subscription_handler(service_t _service,
instance_t _instance, eventgroup_t _eventgroup, subscription_handler_t _handler);
VSOMEIP_EXPORT void unregister_subscription_handler(service_t _service,
instance_t _instance, eventgroup_t _eventgroup);
+ VSOMEIP_EXPORT void register_subscription_error_handler(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup,
+ error_handler_t _handler);
+ VSOMEIP_EXPORT void unregister_subscription_error_handler(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup);
+
+ VSOMEIP_EXPORT bool is_routing() const;
+
// routing_manager_host
VSOMEIP_EXPORT const std::string & get_name() const;
VSOMEIP_EXPORT client_t get_client() const;
@@ -114,16 +126,34 @@ public:
VSOMEIP_EXPORT void on_state(state_type_e _state);
VSOMEIP_EXPORT void on_availability(service_t _service, instance_t _instance,
- bool _is_available) const;
+ bool _is_available, major_version_t _major, minor_version_t _minor);
VSOMEIP_EXPORT void on_message(std::shared_ptr<message> _message);
VSOMEIP_EXPORT void on_error(error_code_e _error);
VSOMEIP_EXPORT bool on_subscription(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, client_t _client, bool _subscribed);
+ VSOMEIP_EXPORT void on_subscription_error(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup, uint16_t _error);
// service_discovery_host
VSOMEIP_EXPORT routing_manager * get_routing_manager() const;
private:
+ //
+ // Types
+ //
+ struct sync_handler {
+
+ sync_handler(std::function<void()> _handler) :
+ handler_(_handler),
+ is_dispatching_(false) { }
+
+ std::function<void()> handler_;
+ bool is_dispatching_;
+ };
+
+ //
+ // Methods
+ //
void service();
inline void update_session() {
session_++;
@@ -132,10 +162,36 @@ 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;
+ void do_register_availability_handler(service_t _service,
+ instance_t _instance, availability_handler_t _handler,
+ major_version_t _major, minor_version_t _minor);
+
+
+ void main_dispatch();
void dispatch();
+ void invoke_handler(std::shared_ptr<sync_handler> &_handler);
+ bool is_active_dispatcher(std::thread::id &_id);
+ void remove_elapsed_dispatchers();
+
+ void clear_all_handler();
void wait_for_stop();
-private:
+ 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);
+
+ //
+ // Attributes
+ //
client_t client_; // unique application identifier
session_t session_;
std::mutex session_mutex_;
@@ -153,6 +209,9 @@ private:
// Proxy to or the Routing Manager itself
std::shared_ptr<routing_manager> routing_;
+ // vsomeip state (registered / deregistered)
+ state_type_e state_;
+
// vsomeip state handler
state_handler_t handler_;
@@ -162,31 +221,43 @@ private:
mutable std::mutex members_mutex_;
// Availability handlers
- std::map<service_t, std::map<instance_t, availability_handler_t> > availability_;
+ std::map<service_t, std::map<instance_t, std::tuple<major_version_t, minor_version_t, availability_handler_t, bool>>> availability_;
mutable std::mutex availability_mutex_;
// Availability
- mutable std::map<service_t, std::set<instance_t>> available_;
+ mutable available_t available_;
- // Subscriptopn handlers
+ // Subscription handlers
std::map<service_t, std::map<instance_t, std::map<eventgroup_t, subscription_handler_t>>>
subscription_;
mutable std::mutex subscription_mutex_;
+ std::map<service_t,
+ std::map<instance_t, std::map<eventgroup_t,
+ std::map<client_t, error_handler_t > > > > eventgroup_error_handlers_;
+ mutable std::mutex subscription_error_mutex_;
// Signals
boost::asio::signal_set signals_;
- // Thread pool for dispatch handlers
- std::size_t num_dispatchers_;
- std::vector<std::thread> dispatchers_;
- std::atomic_bool is_dispatching_;
-
// Handlers
- mutable std::deque<std::function<void()>> handlers_;
-
- // Condition to wake up
- mutable std::mutex dispatch_mutex_;
- mutable std::condition_variable dispatch_condition_;
+ mutable std::deque<std::shared_ptr<sync_handler>> handlers_;
+ mutable std::mutex handlers_mutex_;
+
+ // Dispatching
+ bool is_dispatching_;
+ // Dispatcher threads
+ std::map<std::thread::id, std::shared_ptr<std::thread>> dispatchers_;
+ // Dispatcher threads that elapsed and can be removed
+ std::set<std::thread::id> elapsed_dispatchers_;
+ // Dispatcher threads that blocked
+ std::set<std::thread::id> blocked_dispatchers_;
+ // Mutex to protect access to dispatchers_ & elapsed_dispatchers_
+ std::mutex dispatcher_mutex_;
+ // Condition to wakeup the dispatcher thread
+ mutable std::condition_variable dispatcher_condition_;
+ boost::asio::system_timer dispatcher_timer_;
+ std::size_t max_dispatchers_;
+ std::size_t max_dispatch_time_;
// Workaround for destruction problem
std::shared_ptr<logger> logger_;
@@ -195,6 +266,16 @@ private:
std::mutex start_stop_mutex_;
bool stopped_;
std::thread stop_thread_;
+
+ bool catched_signal_;
+
+ static uint32_t app_counter__;
+
+ 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_;
};
} // namespace vsomeip
diff --git a/implementation/runtime/include/runtime_impl.hpp b/implementation/runtime/include/runtime_impl.hpp
index 123272b..a81b00e 100644
--- a/implementation/runtime/include/runtime_impl.hpp
+++ b/implementation/runtime/include/runtime_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -13,6 +13,10 @@ namespace vsomeip {
class runtime_impl: public runtime {
public:
+
+ static std::string get_property(const std::string &_name);
+ static void set_property(const std::string &_name, const std::string &_value);
+
static std::shared_ptr<runtime> get();
virtual ~runtime_impl();
@@ -37,6 +41,7 @@ public:
private:
static std::shared_ptr<runtime> the_runtime_;
+ static std::map<std::string, std::string> properties_;
std::map<std::string, std::shared_ptr<application>> applications_;
};
diff --git a/implementation/runtime/src/application_impl.cpp b/implementation/runtime/src/application_impl.cpp
index c9efed4..dc7bda5 100644
--- a/implementation/runtime/src/application_impl.cpp
+++ b/implementation/runtime/src/application_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -10,8 +10,8 @@
#ifndef WIN32
#include <dlfcn.h>
#endif
-#include <iostream>
#include <vsomeip/defines.hpp>
+#include <vsomeip/runtime.hpp>
#include "../include/application_impl.hpp"
#include "../../configuration/include/configuration.hpp"
@@ -22,24 +22,28 @@
#include "../../routing/include/routing_manager_proxy.hpp"
#include "../../utility/include/utility.hpp"
#include "../../configuration/include/configuration_impl.hpp"
+#include "../../tracing/include/trace_connector.hpp"
+#include "../../tracing/include/enumeration_types.hpp"
namespace vsomeip {
+uint32_t application_impl::app_counter__ = 0;
+
application_impl::application_impl(const std::string &_name)
: is_initialized_(false), name_(_name),
file_(VSOMEIP_DEFAULT_CONFIGURATION_FILE),
folder_(VSOMEIP_DEFAULT_CONFIGURATION_FOLDER),
routing_(0),
+ state_(state_type_e::ST_DEREGISTERED),
signals_(io_, SIGINT, SIGTERM),
- num_dispatchers_(0), logger_(logger::get()),
- stopped_(false) {
+ dispatcher_timer_(io_),
+ logger_(logger::get()),
+ stopped_(false),
+ catched_signal_(false) {
}
application_impl::~application_impl() {
-#ifdef WIN32
- exit(0); // TODO: clean solution...
-#endif
- stop_thread_.join();
+
}
void application_impl::set_configuration(
@@ -49,6 +53,10 @@ void application_impl::set_configuration(
}
bool application_impl::init() {
+ if(is_initialized_) {
+ VSOMEIP_WARNING << "Trying to initialize an already initialized application.";
+ return true;
+ }
// Application name
if (name_ == "") {
const char *its_name = getenv(VSOMEIP_ENV_APPLICATION_NAME);
@@ -69,7 +77,7 @@ bool application_impl::init() {
#ifdef WIN32
HMODULE config = LoadLibrary(config_module.c_str());
if (config != 0) {
- VSOMEIP_INFO << "\"" << config_module << "\" was loaded";
+ VSOMEIP_INFO << "\"" << config_module << "\" is loaded.";
if (!configuration_) {
VSOMEIP_ERROR << "Configuration not set.";
return false;
@@ -82,13 +90,13 @@ bool application_impl::init() {
#else
void *config = dlopen(config_module.c_str(), RTLD_LAZY | RTLD_GLOBAL);
if(config != 0) {
- VSOMEIP_INFO << "\"" << config_module << "\" was loaded";
+ VSOMEIP_INFO << "\"" << config_module << "\" is loaded.";
if(!configuration_) {
VSOMEIP_ERROR << "Configuration not set.";
return false;
}
} else {
- VSOMEIP_ERROR << "\"" << config_module << "\" could not be loaded (" << dlerror() << ")";
+ VSOMEIP_ERROR << "\"" << config_module << "\" could not be loaded (" << dlerror() << ").";
return false;
}
dlclose(config);
@@ -120,58 +128,51 @@ bool application_impl::init() {
std::shared_ptr<configuration> its_configuration = get_configuration();
if (its_configuration) {
- VSOMEIP_INFO << "Initializing vsomeip application \"" << name_ << "\"";
+ VSOMEIP_INFO << "Initializing vsomeip application \"" << name_ << "\".";
if (utility::is_file(file_))
- VSOMEIP_INFO << "Using configuration file: \"" << file_ << "\"";
+ VSOMEIP_INFO << "Using configuration file: \"" << file_ << "\".";
if (utility::is_folder(folder_))
- VSOMEIP_INFO << "Using configuration folder: \"" << folder_ << "\"";
+ VSOMEIP_INFO << "Using configuration folder: \"" << folder_ << "\".";
- bool is_routing_manager_host(false);
client_ = its_configuration->get_id(name_);
- std::string its_routing_host = its_configuration->get_routing_host();
- if (client_ == 0 || its_routing_host == "") {
-#ifndef WIN32
- if (!utility::auto_configuration_init()) {
- VSOMEIP_ERROR << "Configuration incomplete and "
- "Auto-configuration failed!";
- return false;
- }
-#else
- return false;
-#endif
- }
- // Client ID
- if (client_ == 0) {
-#ifndef WIN32
- client_ = utility::get_client_id();
- VSOMEIP_INFO << "No SOME/IP client identifier configured. "
- << "Using auto-configured "
- << std::hex << std::setfill('0') << std::setw(4)
- << client_;
-#else
- return false;
-#endif
- }
+ // Max dispatchers is the configured maximum number of dispatchers and
+ // the main dispatcher
+ max_dispatchers_ = its_configuration->get_max_dispatchers(name_) + 1;
+ max_dispatch_time_ = its_configuration->get_max_dispatch_time(name_);
- // Routing
- if (its_routing_host == "") {
-#ifndef WIN32
- is_routing_manager_host = utility::is_routing_manager_host();
- VSOMEIP_INFO << "No routing manager configured. "
- << "Using auto-configuration ("
- << (is_routing_manager_host ?
- "Host" : "Proxy") << ")";
-#else
- return false;
-#endif
+ std::string its_routing_host = its_configuration->get_routing_host();
+ if (!utility::auto_configuration_init(name_)) {
+ VSOMEIP_WARNING << "Could _not_ initialize auto-configuration:"
+ " Cannot guarantee unique application identifiers!";
} else {
- is_routing_manager_host = (its_routing_host == name_);
+ // Client Identifier
+ client_t its_old_client = client_;
+ client_ = utility::request_client_id(client_);
+ VSOMEIP_INFO << "SOME/IP client identifier configured. "
+ << "Using "
+ << std::hex << std::setfill('0') << std::setw(4)
+ << client_
+ << " (was: "
+ << std::hex << std::setfill('0') << std::setw(4)
+ << its_old_client
+ << ")";
+
+ // Routing
+ if (its_routing_host == "") {
+ is_routing_manager_host_ = utility::is_routing_manager_host();
+ 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 (is_routing_manager_host) {
+ if (is_routing_manager_host_) {
routing_ = std::make_shared<routing_manager_impl>(this);
} else {
routing_ = std::make_shared<routing_manager_proxy>(this);
@@ -179,14 +180,41 @@ bool application_impl::init() {
routing_->init();
- num_dispatchers_ = its_configuration->get_num_dispatchers(name_);
-
// Smallest allowed session identifier
session_ = 0x0001;
- VSOMEIP_DEBUG<< "Application(" << (name_ != "" ? name_ : "unnamed")
- << ", " << std::hex << client_ << ") is initialized (uses "
- << std::dec << num_dispatchers_ << " dispatcher threads).";
+#ifdef USE_DLT
+ // Tracing
+ std::shared_ptr<tc::trace_connector> its_trace_connector = tc::trace_connector::get();
+ 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) {
+ 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) {
+ std::shared_ptr<cfg::trace_filter_rule> its_filter_rule_cfg = *it;
+ tc::trace_connector::filter_rule_t its_filter_rule;
+
+ its_filter_rule[tc::filter_criteria_e::SERVICES] = its_filter_rule_cfg->services_;
+ its_filter_rule[tc::filter_criteria_e::METHODS] = its_filter_rule_cfg->methods_;
+ its_filter_rule[tc::filter_criteria_e::CLIENTS] = its_filter_rule_cfg->clients_;
+
+ its_trace_connector->add_filter_rule(it->get()->channel_, its_filter_rule);
+ }
+
+ bool enable_tracing = its_trace_cfg->is_enabled_;
+ if(enable_tracing)
+ its_trace_connector->init();
+ its_trace_connector->set_enabled(enable_tracing);
+#endif
+
+ VSOMEIP_DEBUG << "Application(" << (name_ != "" ? name_ : "unnamed")
+ << ", " << std::hex << client_ << ") is initialized ("
+ << std::dec << max_dispatchers_ << ", "
+ << std::dec << max_dispatch_time_ << ").";
is_initialized_ = true;
}
@@ -202,11 +230,11 @@ bool application_impl::init() {
switch (_signal) {
case SIGTERM:
case SIGINT:
- stop();
- exit(0);
- break;
+ catched_signal_ = true;
+ stop();
+ break;
default:
- break;
+ break;
}
}
};
@@ -219,7 +247,7 @@ bool application_impl::init() {
void application_impl::start() {
{
std::lock_guard<std::mutex> its_lock(start_stop_mutex_);
- if(io_.stopped()) {
+ if (io_.stopped()) {
io_.reset();
} else if(stop_thread_.joinable()) {
VSOMEIP_ERROR << "Trying to start an already started application.";
@@ -228,11 +256,11 @@ void application_impl::start() {
is_dispatching_ = true;
- for (size_t i = 0; i < num_dispatchers_; i++)
- dispatchers_.push_back(
- std::thread(std::bind(&application_impl::dispatch, this)));
+ 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;
- if(stop_thread_.joinable()) {
+ if (stop_thread_.joinable()) {
stop_thread_.join();
}
stop_thread_= std::thread(&application_impl::wait_for_stop, this);
@@ -240,31 +268,42 @@ void application_impl::start() {
if (routing_)
routing_->start();
}
- VSOMEIP_INFO << "Starting vsomeip application \"" << name_ << "\"";
+
+ start_stop_mutex_.lock();
+ app_counter__++;
+ start_stop_mutex_.unlock();
+
+ VSOMEIP_INFO << "Starting vsomeip application \"" << name_ << "\".";
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();
+ app_counter__--;
+
+ if (catched_signal_ && !app_counter__) {
+ start_stop_mutex_.unlock();
+ VSOMEIP_INFO << "Exiting vsomeip application...";
+ exit(0);
+ }
+ start_stop_mutex_.unlock();
}
void application_impl::stop() {
#ifndef WIN32 // Gives serious problems under Windows.
- VSOMEIP_INFO << "Stopping vsomeip application \"" << name_ << "\"";
+ VSOMEIP_INFO << "Stopping vsomeip application \"" << name_ << "\".";
#endif
- std::lock_guard<std::mutex> its_lock(start_stop_mutex_);
- is_dispatching_ = false;
- dispatch_condition_.notify_all();
- for (auto &t : dispatchers_) {
- if(t.get_id() == std::this_thread::get_id()) {
- continue;
- }
- if(t.joinable()) {
- t.join();
- }
- }
-
- if (routing_)
- routing_->stop();
-#ifndef WIN32
+ utility::release_client_id(client_);
utility::auto_configuration_exit();
-#endif
+
+ std::lock_guard<std::mutex> its_lock_start_stop(start_stop_mutex_);
stopped_ = true;
stop_cv_.notify_one();
}
@@ -275,14 +314,22 @@ void application_impl::offer_service(service_t _service, instance_t _instance,
routing_->offer_service(client_, _service, _instance, _major, _minor);
}
-void application_impl::stop_offer_service(service_t _service,
- instance_t _instance) {
+void application_impl::stop_offer_service(service_t _service, instance_t _instance,
+ major_version_t _major, minor_version_t _minor) {
if (routing_)
- routing_->stop_offer_service(client_, _service, _instance);
+ routing_->stop_offer_service(client_, _service, _instance, _major, _minor);
}
void application_impl::request_service(service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor, bool _use_exclusive_proxy) {
+ if (_use_exclusive_proxy) {
+ message_handler_t handler([&](const std::shared_ptr<message>& response) {
+ routing_->on_identify_response(get_client(), response->get_service(),
+ response->get_instance(), response->is_reliable());
+ });
+ register_message_handler(_service, _instance, ANY_METHOD - 1, handler);
+ }
+
if (routing_)
routing_->request_service(client_, _service, _instance, _major, _minor,
_use_exclusive_proxy);
@@ -290,16 +337,57 @@ void application_impl::request_service(service_t _service, instance_t _instance,
void application_impl::release_service(service_t _service,
instance_t _instance) {
- if (routing_)
+ if (routing_) {
routing_->release_service(client_, _service, _instance);
+ }
}
void application_impl::subscribe(service_t _service, instance_t _instance,
- eventgroup_t _eventgroup, major_version_t _major,
- subscription_type_e _subscription_type) {
- if (routing_)
+ eventgroup_t _eventgroup,
+ major_version_t _major,
+ subscription_type_e _subscription_type,
+ event_t _event) {
+ if (routing_) {
+ bool send_back_cached(false);
+ bool send_back_cached_group(false);
+ {
+ std::lock_guard<std::mutex> its_lock(event_subscriptions_mutex_);
+ auto found_service = event_subscriptions_.find(_service);
+ if(found_service != event_subscriptions_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto its_event = found_instance->second.find(_event);
+ if (its_event == found_instance->second.end()) {
+ // first subscription to this event
+ event_subscriptions_[_service][_instance][_event] = false;
+ } else {
+ if(its_event->second) {
+ // initial values for this event have already been sent,
+ // send back cached value
+ if(_event == ANY_EVENT) {
+ send_back_cached_group = true;
+ } else {
+ send_back_cached = true;
+ }
+ }
+ }
+ } else {
+ // first subscription to this service instance
+ event_subscriptions_[_service][_instance][_event] = false;
+ }
+ } else {
+ // first subscription to this service
+ event_subscriptions_[_service][_instance][_event] = false;
+ }
+ }
+ if(send_back_cached) {
+ send_back_cached_event(_service, _instance, _event);
+ } else if(send_back_cached_group) {
+ send_back_cached_eventgroup(_service, _instance, _event);
+ }
routing_->subscribe(client_, _service, _instance, _eventgroup, _major,
_subscription_type);
+ }
}
void application_impl::unsubscribe(service_t _service, instance_t _instance,
@@ -309,13 +397,160 @@ void application_impl::unsubscribe(service_t _service, instance_t _instance,
}
bool application_impl::is_available(
- service_t _service, instance_t _instance) const {
- auto found_available = available_.find(_service);
- if (found_available == available_.end())
- return false;
+ service_t _service, instance_t _instance,
+ major_version_t _major, minor_version_t _minor) const {
+ std::lock_guard<std::mutex> its_lock(availability_mutex_);
+ return is_available_unlocked(_service, _instance, _major, _minor);
+}
+
+bool application_impl::is_available_unlocked(
+ service_t _service, instance_t _instance,
+ major_version_t _major, minor_version_t _minor) const {
- return (found_available->second.find(_instance)
- != found_available->second.end());
+ bool is_available(false);
+
+ auto found_available_service = available_.find(_service);
+ if (found_available_service != available_.end()) {
+ auto found_instance = found_available_service->second.find(_instance);
+ if( found_instance != found_available_service->second.end()) {
+ auto found_major = found_instance->second.find(_major);
+ if( found_major != found_instance->second.end() ){
+ if( _minor <= found_major->second) {
+ is_available = true;
+ }
+ } else if(_major == DEFAULT_MAJOR &&
+ _minor == DEFAULT_MINOR){
+ is_available = true;
+ }
+ }
+ }
+ return is_available;
+}
+
+bool application_impl::are_available(
+ available_t &_available,
+ service_t _service, instance_t _instance,
+ major_version_t _major, minor_version_t _minor) const {
+ std::lock_guard<std::mutex> its_lock(availability_mutex_);
+ return are_available_unlocked(_available, _service, _instance, _major, _minor);
+}
+
+bool application_impl::are_available_unlocked(available_t &_available,
+ service_t _service, instance_t _instance,
+ major_version_t _major, minor_version_t _minor) const {
+
+ //find available services
+ if(_service == ANY_SERVICE) {
+ //add all available services
+ for(auto its_available_services_it = available_.begin();
+ its_available_services_it != available_.end();
+ ++its_available_services_it)
+ _available[its_available_services_it->first];
+ } else {
+ // check if specific service is available
+ if(available_.find(_service) != available_.end())
+ _available[_service];
+ }
+
+ //find available instances
+ //iterate through found available services
+ for(auto its_available_services_it = _available.begin();
+ its_available_services_it != _available.end();
+ ++its_available_services_it) {
+ //get available service
+ auto found_available_service = available_.find(its_available_services_it->first);
+ if (found_available_service != available_.end()) {
+ if(_instance == ANY_INSTANCE) {
+ //add all available instances
+ for(auto its_available_instances_it = found_available_service->second.begin();
+ its_available_instances_it != found_available_service->second.end();
+ ++its_available_instances_it)
+ _available[its_available_services_it->first][its_available_instances_it->first];
+ } else {
+ if(found_available_service->second.find(_instance) != found_available_service->second.end())
+ _available[its_available_services_it->first][_instance];
+ }
+ }
+ }
+
+ //find major versions
+ //iterate through found available services
+ for(auto its_available_services_it = _available.begin();
+ its_available_services_it != _available.end();
+ ++its_available_services_it) {
+ //get available service
+ auto found_available_service = available_.find(its_available_services_it->first);
+ if (found_available_service != available_.end()) {
+ //iterate through found available instances
+ for(auto its_available_instances_it = found_available_service->second.begin();
+ its_available_instances_it != found_available_service->second.end();
+ ++its_available_instances_it) {
+ //get available instance
+ auto found_available_instance = found_available_service->second.find(its_available_instances_it->first);
+ if(found_available_instance != found_available_service->second.end()) {
+ if(_major == ANY_MAJOR || _major == DEFAULT_MAJOR) {
+ //add all major versions
+ for(auto its_available_major_it = found_available_instance->second.begin();
+ its_available_major_it != found_available_instance->second.end();
+ ++its_available_major_it)
+ _available[its_available_services_it->first][its_available_instances_it->first][its_available_major_it->first];
+ } else {
+ if(found_available_instance->second.find(_major) != found_available_instance->second.end())
+ _available[its_available_services_it->first][its_available_instances_it->first][_major];
+ }
+ }
+ }
+ }
+ }
+
+ //find minor
+ //iterate through found available services
+ auto its_available_services_it = _available.begin();
+ while(its_available_services_it != _available.end()) {
+ bool found_minor(false);
+ //get available service
+ auto found_available_service = available_.find(its_available_services_it->first);
+ if (found_available_service != available_.end()) {
+ //iterate through found available instances
+ for(auto its_available_instances_it = found_available_service->second.begin();
+ its_available_instances_it != found_available_service->second.end();
+ ++its_available_instances_it) {
+ //get available instance
+ auto found_available_instance = found_available_service->second.find(its_available_instances_it->first);
+ if(found_available_instance != found_available_service->second.end()) {
+ //iterate through found available major version
+ for(auto its_available_major_it = found_available_instance->second.begin();
+ its_available_major_it != found_available_instance->second.end();
+ ++its_available_major_it) {
+ //get available major version
+ auto found_available_major = found_available_instance->second.find(its_available_major_it->first);
+ if(found_available_major != found_available_instance->second.end()) {
+ if(_minor == ANY_MINOR || _minor == DEFAULT_MINOR) {
+ //add minor version
+ _available[its_available_services_it->first][its_available_instances_it->first][its_available_major_it->first] = _minor;
+ found_minor = true;
+ } else {
+ if(_minor == found_available_major->second) {
+ _available[its_available_services_it->first][its_available_instances_it->first][_major] = _minor;
+ found_minor = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if(found_minor)
+ ++its_available_services_it;
+ else
+ its_available_services_it = _available.erase(its_available_services_it);
+ }
+
+ if(_available.empty()) {
+ _available[_service][_instance][_major] = _minor ;
+ return false;
+ }
+ return true;
}
void application_impl::send(std::shared_ptr<message> _message, bool _flush) {
@@ -360,24 +595,56 @@ void application_impl::unregister_state_handler() {
}
void application_impl::register_availability_handler(service_t _service,
- instance_t _instance, availability_handler_t _handler) {
+ instance_t _instance, availability_handler_t _handler,
+ major_version_t _major, minor_version_t _minor) {
+ if (state_ == state_type_e::ST_REGISTERED) {
+ do_register_availability_handler(_service, _instance,
+ _handler, _major, _minor);
+ } else {
+ availability_[_service][_instance]
+ = std::make_tuple(_major, _minor, _handler, false);
+ }
+}
+
+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> its_lock(availability_mutex_);
- availability_[_service][_instance] = _handler;
+ 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);
+
+ 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::async(std::launch::async, [this, _service, _instance, _handler]() {
- _handler(_service, _instance, is_available(_service, _instance));
- });
+
+ dispatcher_condition_.notify_one();
}
void application_impl::unregister_availability_handler(service_t _service,
- instance_t _instance) {
- std::unique_lock<std::mutex> its_lock(availability_mutex_);
+ instance_t _instance, major_version_t _major, minor_version_t _minor) {
+ std::lock_guard<std::mutex> its_lock(availability_mutex_);
auto found_service = availability_.find(_service);
if (found_service != availability_.end()) {
auto found_instance = found_service->second.find(_instance);
if (found_instance != found_service->second.end()) {
- found_service->second.erase(_instance);
+ auto found_version = found_instance->second;
+ auto found_major = std::get<0>(found_version);
+ auto found_minor = std::get<1>(found_version);
+ if(found_major == _major) {
+ if(found_minor == _minor) {
+ found_service->second.erase(_instance);
+ }
+ }
}
}
}
@@ -385,7 +652,7 @@ void application_impl::unregister_availability_handler(service_t _service,
bool application_impl::on_subscription(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, client_t _client, bool _subscribed) {
- std::unique_lock<std::mutex> its_lock(subscription_mutex_);
+ std::lock_guard<std::mutex> its_lock(subscription_mutex_);
auto found_service = subscription_.find(_service);
if (found_service != subscription_.end()) {
auto found_instance = found_service->second.find(_instance);
@@ -403,14 +670,18 @@ void application_impl::register_subscription_handler(service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
subscription_handler_t _handler) {
- std::unique_lock<std::mutex> its_lock(subscription_mutex_);
+ std::lock_guard<std::mutex> its_lock(subscription_mutex_);
subscription_[_service][_instance][_eventgroup] = _handler;
+
+ message_handler_t handler([&](const std::shared_ptr<message>& request) {
+ send(runtime::get()->create_response(request), true);
+ });
+ register_message_handler(_service, _instance, ANY_METHOD - 1, handler);
}
void application_impl::unregister_subscription_handler(service_t _service,
instance_t _instance, eventgroup_t _eventgroup) {
-
- std::unique_lock<std::mutex> its_lock(subscription_mutex_);
+ std::lock_guard<std::mutex> its_lock(subscription_mutex_);
auto found_service = subscription_.find(_service);
if (found_service != subscription_.end()) {
auto found_instance = found_service->second.find(_instance);
@@ -421,17 +692,71 @@ void application_impl::unregister_subscription_handler(service_t _service,
}
}
}
+ unregister_message_handler(_service, _instance, ANY_METHOD - 1);
+}
+
+void application_impl::on_subscription_error(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup, uint16_t _error) {
+ error_handler_t handler = nullptr;
+ std::lock_guard<std::mutex> its_lock(subscription_error_mutex_);
+ auto found_service = eventgroup_error_handlers_.find(_service);
+ if (found_service != eventgroup_error_handlers_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto found_eventgroup = found_instance->second.find(_eventgroup);
+ if (found_eventgroup != found_instance->second.end()) {
+ auto found_client = found_eventgroup->second.find(get_client());
+ if (found_client != found_eventgroup->second.end()) {
+ handler = found_client->second;
+
+ }
+ }
+ }
+ }
+ if (handler) {
+ {
+ std::unique_lock<std::mutex> handlers_lock(handlers_mutex_);
+ std::shared_ptr<sync_handler> its_sync_handler
+ = std::make_shared<sync_handler>([handler, _error]() {
+ handler(_error);
+ });
+ handlers_.push_back(its_sync_handler);
+ }
+ dispatcher_condition_.notify_all();
+ }
+}
+
+void application_impl::register_subscription_error_handler(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup,
+ error_handler_t _handler) {
+ std::lock_guard<std::mutex> its_lock(subscription_error_mutex_);
+ eventgroup_error_handlers_[_service][_instance][_eventgroup][get_client()] = _handler;
+}
+
+void application_impl::unregister_subscription_error_handler(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) {
+ std::lock_guard<std::mutex> its_lock(subscription_error_mutex_);
+ auto found_service = eventgroup_error_handlers_.find(_service);
+ if (found_service != eventgroup_error_handlers_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ auto found_eventgroup = found_instance->second.find(_eventgroup);
+ if (found_eventgroup != found_instance->second.end()) {
+ found_eventgroup->second.erase(get_client());
+ }
+ }
+ }
}
void application_impl::register_message_handler(service_t _service,
instance_t _instance, method_t _method, message_handler_t _handler) {
- std::unique_lock<std::mutex> its_lock(members_mutex_);
+ std::lock_guard<std::mutex> its_lock(members_mutex_);
members_[_service][_instance][_method] = _handler;
}
void application_impl::unregister_message_handler(service_t _service,
instance_t _instance, method_t _method) {
- std::unique_lock<std::mutex> its_lock(members_mutex_);
+ std::lock_guard<std::mutex> its_lock(members_mutex_);
auto found_service = members_.find(_service);
if (found_service != members_.end()) {
auto found_instance = found_service->second.find(_instance);
@@ -462,7 +787,7 @@ void application_impl::request_event(service_t _service, instance_t _instance,
if (routing_)
routing_->register_event(client_, _service, _instance, _event,
_eventgroups, _is_field, false);
- }
+}
void application_impl::release_event(service_t _service, instance_t _instance,
event_t _event) {
@@ -501,81 +826,149 @@ boost::asio::io_service & application_impl::get_io() {
}
void application_impl::on_state(state_type_e _state) {
+ if (state_ != _state) {
+ state_ = _state;
+ if (state_ == state_type_e::ST_REGISTERED) {
+ for (auto &its_service : availability_) {
+ for (auto &its_instance : its_service.second) {
+ if (!std::get<3>(its_instance.second)) {
+ do_register_availability_handler(
+ its_service.first, its_instance.first,
+ std::get<2>(its_instance.second),
+ std::get<0>(its_instance.second),
+ std::get<1>(its_instance.second));
+ }
+ }
+ }
+ }
+ }
+
if (handler_) {
- if (num_dispatchers_ > 0) {
- std::unique_lock<std::mutex> its_lock(dispatch_mutex_);
- handlers_.push_back([this, _state]() {
- handler_(_state);
- });
- dispatch_condition_.notify_one();
- } else {
- handler_(_state);
+ {
+ std::lock_guard<std::mutex> its_lock(handlers_mutex_);
+
+ std::shared_ptr<sync_handler> its_sync_handler
+ = std::make_shared<sync_handler>([this, _state]() {
+ handler_(_state);
+ });
+
+ handlers_.push_back(its_sync_handler);
}
+ dispatcher_condition_.notify_one();
}
}
void application_impl::on_availability(service_t _service, instance_t _instance,
- bool _is_available) const {
+ bool _is_available, major_version_t _major, minor_version_t _minor) {
- std::map<instance_t, availability_handler_t>::const_iterator found_instance;
+ std::map<minor_version_t, availability_handler_t>::const_iterator found_minor;
availability_handler_t its_handler;
- std::map<instance_t, availability_handler_t>::const_iterator found_wildcard_instance;
+ std::map<minor_version_t, availability_handler_t>::const_iterator found_wildcard_minor;
availability_handler_t its_wildcard_handler;
bool has_handler(false);
bool has_wildcard_handler(false);
{
- std::unique_lock<std::mutex> its_lock(availability_mutex_);
-
- if (_is_available == is_available(_service, _instance))
+ std::lock_guard<std::mutex> availability_lock(availability_mutex_);
+ if (_is_available == is_available_unlocked(_service, _instance, _major, _minor)) {
return;
+ }
if (_is_available) {
- available_[_service].insert(_instance);
+ available_[_service][_instance][_major] = _minor;
} else {
auto found_available_service = available_.find(_service);
- if (found_available_service != available_.end())
- found_available_service->second.erase(_instance);
+ if (found_available_service != available_.end()) {
+ auto found_instance = found_available_service->second.find(_instance);
+ if( found_instance != found_available_service->second.end()) {
+ auto found_major = found_instance->second.find(_major);
+ if( found_major != found_instance->second.end() ){
+ if( _minor == found_major->second)
+ found_available_service->second.erase(_instance);
+ }
+ }
+ }
}
auto found_service = availability_.find(_service);
if (found_service != availability_.end()) {
- found_instance = found_service->second.find(_instance);
- has_handler = (found_instance != found_service->second.end());
- if (has_handler)
- its_handler = found_instance->second;
- found_wildcard_instance = found_service->second.find(ANY_INSTANCE);
- has_wildcard_handler = (found_wildcard_instance != found_service->second.end());
- if (has_wildcard_handler)
- its_wildcard_handler = found_wildcard_instance->second;
+ //find specific instance
+ auto found_instance = found_service->second.find(_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);
+ }
+ }
+
+ //find wildcard instance major minor
+ found_instance = found_service->second.find(ANY_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);
+ }
+ }
}
- }
- if (num_dispatchers_ > 0) {
+ std::lock_guard<std::mutex> handlers_lock(handlers_mutex_);
if (has_handler) {
- std::unique_lock<std::mutex> its_lock(dispatch_mutex_);
- handlers_.push_back(
- [its_handler, _service, _instance, _is_available]() {
- its_handler(_service, _instance, _is_available);
- });
- dispatch_condition_.notify_one();
+
+ std::shared_ptr<sync_handler> its_sync_handler
+ = std::make_shared<sync_handler>(
+ [its_handler, _service, _instance, _is_available]() {
+ its_handler(_service, _instance, _is_available);
+ }
+ );
+
+ handlers_.push_back(its_sync_handler);
}
if (has_wildcard_handler) {
- std::unique_lock < std::mutex > its_lock(dispatch_mutex_);
- handlers_.push_back(
- [its_wildcard_handler, _service, _instance, _is_available]() {
- its_wildcard_handler(_service, _instance, _is_available);
- });
- dispatch_condition_.notify_one();
- }
- } else {
- if(has_handler) {
- its_handler(_service, _instance, _is_available);
+
+ std::shared_ptr<sync_handler> its_sync_handler
+ = std::make_shared<sync_handler>(
+ [its_wildcard_handler, _service, _instance, _is_available]() {
+ its_wildcard_handler(_service, _instance, _is_available);
+ }
+ );
+
+ handlers_.push_back(its_sync_handler);
}
- if(has_wildcard_handler) {
- its_wildcard_handler(_service, _instance, _is_available);
+ }
+ if (!_is_available) {
+ std::lock_guard<std::mutex> its_lock(event_subscriptions_mutex_);
+ auto found_service = event_subscriptions_.find(_service);
+ if (found_service != event_subscriptions_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ for (auto &e : found_instance->second) {
+ e.second = false;
+ }
+ }
}
}
+
+ if (has_handler || has_wildcard_handler) {
+ dispatcher_condition_.notify_one();
+ }
}
void application_impl::on_message(std::shared_ptr<message> _message) {
@@ -587,8 +980,36 @@ void application_impl::on_message(std::shared_ptr<message> _message) {
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);
+ if(found_service != event_subscriptions_.end()) {
+ auto found_instance = found_service->second.find(its_instance);
+ if (found_instance != found_service->second.end()) {
+ auto its_event = found_instance->second.find(its_method);
+ if (its_event != found_instance->second.end()) {
+ its_event->second = true;
+ } else {
+ // received a event which nobody yet subscribed to
+ event_subscriptions_[its_service][its_instance][its_method] = true;
+ // check if someone subscribed to ANY_EVENT
+ auto its_any_event = found_instance->second.find(ANY_EVENT);
+ if(its_any_event == found_instance->second.end()) {
+ return;
+ }
+ }
+ } else {
+ // received a event from a service instance which nobody yet subscribed to
+ event_subscriptions_[its_service][its_instance][its_method] = true;
+ }
+ } else {
+ // received a event from a service which nobody yet subscribed to
+ event_subscriptions_[its_service][its_instance][its_method] = true;
+ }
+ }
+
{
- std::unique_lock<std::mutex> its_lock(members_mutex_);
+ std::lock_guard<std::mutex> its_lock(members_mutex_);
auto found_service = members_.find(its_service);
if (found_service == members_.end()) {
@@ -611,18 +1032,19 @@ void application_impl::on_message(std::shared_ptr<message> _message) {
}
}
}
- }
- if (has_handler) {
- if (num_dispatchers_ > 0) {
- std::unique_lock<std::mutex> its_lock(dispatch_mutex_);
- handlers_.push_back([its_handler, _message]() {
- its_handler(_message);
- });
- dispatch_condition_.notify_one();
- } else {
- its_handler(_message);
+ if (has_handler) {
+ 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);
}
+ dispatcher_condition_.notify_one();
}
}
@@ -641,36 +1063,203 @@ void application_impl::service() {
io_.run();
}
-void application_impl::dispatch() {
- std::function<void()> handler;
+void application_impl::main_dispatch() {
while (is_dispatching_) {
- {
- std::unique_lock<std::mutex> its_lock(dispatch_mutex_);
- if (handlers_.empty()) {
- dispatch_condition_.wait(its_lock);
- continue;
- } else {
- handler = handlers_.front();
+ std::unique_lock<std::mutex> its_lock(handlers_mutex_);
+
+ if (handlers_.empty()) {
+ // Cancel other waiting dispatcher
+ dispatcher_condition_.notify_all();
+ // Wait for new handlers to execute
+ dispatcher_condition_.wait(its_lock);
+ } else {
+ while (!handlers_.empty()) {
+ std::shared_ptr<sync_handler> its_handler = handlers_.front();
handlers_.pop_front();
+ its_lock.unlock();
+ invoke_handler(its_handler);
+ its_lock.lock();
+
+ remove_elapsed_dispatchers();
}
}
- handler();
}
}
-void application_impl::wait_for_stop() {
- std::unique_lock<std::mutex> its_lock(start_stop_mutex_);
- while(!stopped_) {
- stop_cv_.wait(its_lock);
+void application_impl::dispatch() {
+ std::thread::id its_id = std::this_thread::get_id();
+ while (is_active_dispatcher(its_id)) {
+ std::unique_lock<std::mutex> its_lock(handlers_mutex_);
+ if (handlers_.empty()) {
+ dispatcher_condition_.wait(its_lock);
+ if (handlers_.empty()) { // Maybe woken up from main dispatcher
+ std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
+ elapsed_dispatchers_.insert(its_id);
+ return;
+ }
+ } else {
+ while (!handlers_.empty() && is_active_dispatcher(its_id)) {
+ std::shared_ptr<sync_handler> its_handler = handlers_.front();
+ handlers_.pop_front();
+ its_lock.unlock();
+ invoke_handler(its_handler);
+ its_lock.lock();
+
+ remove_elapsed_dispatchers();
+ }
+ }
+ }
+
+ std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
+ elapsed_dispatchers_.insert(std::this_thread::get_id());
+}
+
+void application_impl::invoke_handler(std::shared_ptr<sync_handler> &_handler) {
+ std::thread::id its_id = std::this_thread::get_id();
+
+ dispatcher_timer_.expires_from_now(std::chrono::milliseconds(max_dispatch_time_));
+ dispatcher_timer_.async_wait([this, its_id](const boost::system::error_code &_error) {
+ if (!_error) {
+ VSOMEIP_DEBUG << "Blocking call detected. Client=" << std::hex << get_client();
+ std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
+ blocked_dispatchers_.insert(its_id);
+
+ // If possible, create a new dispatcher thread to unblock.
+ // If this is _not_ possible, dispatching is blocked until at least
+ // one of the active handler calls returns.
+ if (dispatchers_.size() < max_dispatchers_) {
+ auto its_dispatcher = std::make_shared<std::thread>(
+ std::bind(&application_impl::dispatch, this));
+ dispatchers_[its_dispatcher->get_id()] = its_dispatcher;
+ } else {
+ VSOMEIP_DEBUG << "Maximum number of dispatchers exceeded.";
+ }
+ }
+ });
+
+ _handler->handler_();
+ dispatcher_timer_.cancel();
+ {
+ std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
+ blocked_dispatchers_.erase(its_id);
+ }
+}
+
+bool application_impl::is_active_dispatcher(std::thread::id &_id) {
+ std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
+ for (auto d : dispatchers_) {
+ if (d.first != _id &&
+ blocked_dispatchers_.find(d.first) == blocked_dispatchers_.end()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void application_impl::remove_elapsed_dispatchers() {
+ std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
+ for (auto id : elapsed_dispatchers_) {
+ auto its_dispatcher = dispatchers_.find(id);
+ if (its_dispatcher->second->joinable())
+ its_dispatcher->second->join();
+ dispatchers_.erase(id);
+ }
+ elapsed_dispatchers_.clear();
+}
+
+void application_impl::clear_all_handler() {
+ unregister_state_handler();
+
+ {
+ std::lock_guard<std::mutex> availability_lock(availability_mutex_);
+ availability_.clear();
}
- stopped_ = false;
- for (auto &t : dispatchers_) {
- if(t.joinable()) {
- t.join();
+ {
+ std::lock_guard<std::mutex> its_lock(subscription_mutex_);
+ subscription_.clear();
+ }
+
+ {
+ std::lock_guard<std::mutex> its_lock(subscription_error_mutex_);
+ eventgroup_error_handlers_.clear();
+ }
+
+ {
+ std::lock_guard<std::mutex> its_lock(members_mutex_);
+ members_.clear();
+ }
+}
+
+void application_impl::wait_for_stop() {
+
+ {
+ std::unique_lock<std::mutex> its_lock(start_stop_mutex_);
+ while(!stopped_) {
+ stop_cv_.wait(its_lock);
}
+ stopped_ = false;
+
+ // join dispatch threads
+ is_dispatching_ = false;
+ dispatcher_condition_.notify_all();
+ }
+
+ for (auto its_dispatcher : dispatchers_) {
+ if (its_dispatcher.second->joinable())
+ its_dispatcher.second->join();
}
+
+ if (routing_)
+ routing_->stop();
+
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 {
+ return is_routing_manager_host_;
+}
+
+void application_impl::send_back_cached_event(service_t _service,
+ instance_t _instance,
+ event_t _event) {
+ std::shared_ptr<event> its_event = routing_->get_event(_service,
+ _instance, _event);
+ if (its_event && its_event->is_field() && its_event->is_set()) {
+ std::shared_ptr<message> its_message = runtime::get()->create_notification();
+ its_message->set_service(_service);
+ its_message->set_method(_event);
+ its_message->set_instance(_instance);
+ its_message->set_payload(its_event->get_payload());
+ its_message->set_initial(true);
+ on_message(its_message);
+ }
+}
+
+void application_impl::send_back_cached_eventgroup(service_t _service,
+ instance_t _instance,
+ eventgroup_t _eventgroup) {
+ std::set<std::shared_ptr<event>> its_events = routing_->find_events(_service, _instance,
+ _eventgroup);
+ for(const auto &its_event : its_events) {
+ if (its_event && its_event->is_field() && its_event->is_set()) {
+ std::shared_ptr<message> its_message = runtime::get()->create_notification();
+ its_message->set_service(_service);
+ its_message->set_method(its_event->get_event());
+ its_message->set_instance(_instance);
+ its_message->set_payload(its_event->get_payload());
+ its_message->set_initial(true);
+ on_message(its_message);
+ }
+ }
}
} // namespace vsomeip
diff --git a/implementation/runtime/src/error.cpp b/implementation/runtime/src/error.cpp
index e921227..8bd1d36 100644
--- a/implementation/runtime/src/error.cpp
+++ b/implementation/runtime/src/error.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/runtime/src/runtime.cpp b/implementation/runtime/src/runtime.cpp
index 68f6154..0259b2a 100644
--- a/implementation/runtime/src/runtime.cpp
+++ b/implementation/runtime/src/runtime.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -9,6 +9,14 @@
namespace vsomeip {
+std::string runtime::get_property(const std::string &_name) {
+ return runtime_impl::get_property(_name);
+}
+
+void runtime::set_property(const std::string &_name, const std::string &_value) {
+ runtime_impl::set_property(_name, _value);
+}
+
std::shared_ptr<runtime> runtime::get() {
return runtime_impl::get();
}
diff --git a/implementation/runtime/src/runtime_impl.cpp b/implementation/runtime/src/runtime_impl.cpp
index 2131da5..4943b6d 100644
--- a/implementation/runtime/src/runtime_impl.cpp
+++ b/implementation/runtime/src/runtime_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -12,8 +12,20 @@
namespace vsomeip {
+std::map<std::string, std::string> runtime_impl::properties_;
std::shared_ptr<runtime> runtime_impl::the_runtime_ = std::make_shared<runtime_impl>();
+std::string runtime_impl::get_property(const std::string &_name) {
+ auto found_property = properties_.find(_name);
+ if (found_property != properties_.end())
+ return found_property->second;
+ return "";
+}
+
+void runtime_impl::set_property(const std::string &_name, const std::string &_value) {
+ properties_[_name] = _value;
+}
+
std::shared_ptr<runtime> runtime_impl::get() {
return the_runtime_;
}
diff --git a/implementation/service_discovery/include/configuration_option_impl.hpp b/implementation/service_discovery/include/configuration_option_impl.hpp
index de8a97f..d2351bc 100644
--- a/implementation/service_discovery/include/configuration_option_impl.hpp
+++ b/implementation/service_discovery/include/configuration_option_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/constants.hpp b/implementation/service_discovery/include/constants.hpp
index cc476a7..01c55cb 100644
--- a/implementation/service_discovery/include/constants.hpp
+++ b/implementation/service_discovery/include/constants.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/defines.hpp b/implementation/service_discovery/include/defines.hpp
index 2d23c3c..52c7216 100644
--- a/implementation/service_discovery/include/defines.hpp
+++ b/implementation/service_discovery/include/defines.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -6,14 +6,24 @@
#ifndef VSOMEIP_SD_DEFINES_HPP
#define VSOMEIP_SD_DEFINES_HPP
+#include "../../configuration/include/internal.hpp"
+
+#define VSOMEIP_MAX_TCP_SD_PAYLOAD 4075 // Available for entries & options
+#define VSOMEIP_MAX_UDP_SD_PAYLOAD 1380
+
#define VSOMEIP_SOMEIP_SD_DATA_SIZE 12
#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_HEADER_SIZE 3
+#define VSOMEIP_SD_IPV4_OPTION_LENGTH 0x0009
+#define VSOMEIP_SD_IPV6_OPTION_LENGTH 0x0015
+
#define VSOMEIP_SD_SERVICE 0xFFFF
#define VSOMEIP_SD_INSTANCE 0x0000
#define VSOMEIP_SD_METHOD 0x8100
-#define VSOMEIP_SD_CLIENT 0x0000
+#define VSOMEIP_SD_CLIENT (VSOMEIP_DIAGNOSIS_ADDRESS << 8) // SIP_SD_1139
#define VSOMEIP_SD_DEFAULT_ENABLED true
@@ -25,7 +35,7 @@
#define VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MAX 3000
#define VSOMEIP_SD_DEFAULT_REPETITIONS_BASE_DELAY 10
#define VSOMEIP_SD_DEFAULT_REPETITIONS_MAX 3
-#define VSOMEIP_SD_DEFAULT_TTL 5
+#define VSOMEIP_SD_DEFAULT_TTL DEFAULT_TTL
#define VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY 1000
#define VSOMEIP_SD_DEFAULT_REQUEST_RESPONSE_DELAY 2000
diff --git a/implementation/service_discovery/include/deserializer.hpp b/implementation/service_discovery/include/deserializer.hpp
index 1625e80..085bc7c 100755
--- a/implementation/service_discovery/include/deserializer.hpp
+++ b/implementation/service_discovery/include/deserializer.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/entry_impl.hpp b/implementation/service_discovery/include/entry_impl.hpp
index fde425c..25f08d2 100755
--- a/implementation/service_discovery/include/entry_impl.hpp
+++ b/implementation/service_discovery/include/entry_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -46,8 +46,7 @@ public:
void set_ttl(ttl_t _ttl);
const std::vector<uint8_t> & get_options(uint8_t _run) const;
- void assign_option(const std::shared_ptr<option_impl> &_option,
- uint8_t _run);
+ void assign_option(const std::shared_ptr<option_impl> &_option);
bool is_service_entry() const;
bool is_eventgroup_entry() const;
diff --git a/implementation/service_discovery/include/enumeration_types.hpp b/implementation/service_discovery/include/enumeration_types.hpp
index 016fdae..6fb66f2 100644
--- a/implementation/service_discovery/include/enumeration_types.hpp
+++ b/implementation/service_discovery/include/enumeration_types.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/eventgroupentry_impl.hpp b/implementation/service_discovery/include/eventgroupentry_impl.hpp
index cde7497..0eb8893 100755
--- a/implementation/service_discovery/include/eventgroupentry_impl.hpp
+++ b/implementation/service_discovery/include/eventgroupentry_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -20,11 +20,22 @@ public:
eventgroup_t get_eventgroup() const;
void set_eventgroup(eventgroup_t _eventgroup);
+ uint16_t get_reserved() const;
+ void set_reserved(uint16_t _reserved);
+
+ uint8_t get_counter() const;
+ void set_counter(uint8_t _counter);
+
bool serialize(vsomeip::serializer *_to) const;
bool deserialize(vsomeip::deserializer *_from);
private:
eventgroup_t eventgroup_;
+ uint16_t reserved_;
+
+ // counter field to differentiate parallel subscriptions on same event group
+ // 4Bit only (max 16. parralel subscriptions)
+ uint8_t counter_;
};
} // namespace sd
diff --git a/implementation/service_discovery/include/fsm_base.hpp b/implementation/service_discovery/include/fsm_base.hpp
index 13b7158..ede92d3 100644
--- a/implementation/service_discovery/include/fsm_base.hpp
+++ b/implementation/service_discovery/include/fsm_base.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -19,15 +19,17 @@ public:
fsm_base(boost::asio::io_service &_io);
virtual ~fsm_base();
- void start_timer(uint32_t _ms);
- void stop_timer();
+ void start_timer(uint32_t _ms, bool _use_alt_timer = false);
+ void stop_timer(bool _use_alt_timer = false);
- uint32_t expired_from_now();
+ uint32_t expired_from_now(bool _use_alt_timer = false);
- virtual void timer_expired(const boost::system::error_code &_error) = 0;
+ virtual void timer_expired(const boost::system::error_code &_error,
+ bool _use_alt_timer) = 0;
private:
boost::asio::system_timer timer_;
+ boost::asio::system_timer alt_timer_;
};
} // namespace sd
diff --git a/implementation/service_discovery/include/fsm_events.hpp b/implementation/service_discovery/include/fsm_events.hpp
index 1624b00..75279e2 100644
--- a/implementation/service_discovery/include/fsm_events.hpp
+++ b/implementation/service_discovery/include/fsm_events.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -9,6 +9,7 @@
#include <boost/statechart/event.hpp>
#include <vsomeip/primitive_types.hpp>
+#include "../../routing/include/serviceinfo.hpp"
namespace sc = boost::statechart;
@@ -21,6 +22,9 @@ struct ev_none: sc::event<ev_none> {
struct ev_timeout: sc::event<ev_timeout> {
};
+struct ev_alt_timeout: sc::event<ev_alt_timeout> {
+};
+
struct ev_status_change: sc::event<ev_status_change> {
ev_status_change(bool _is_up)
: is_up_(_is_up) {
@@ -31,22 +35,25 @@ struct ev_status_change: sc::event<ev_status_change> {
struct ev_find_service: sc::event<ev_find_service> {
- ev_find_service(service_t _service, instance_t _instance,
- major_version_t _major, minor_version_t _minor, ttl_t _ttl)
- : service_(_service), instance_(_instance), major_(_major), minor_(
- _minor), ttl_(_ttl) {
+ ev_find_service(const std::shared_ptr<const serviceinfo> &_info, service_t _service, instance_t _instance,
+ major_version_t _major, minor_version_t _minor, bool _unicast_flag)
+ : info_(_info), service_(_service), instance_(_instance), major_(_major), minor_(
+ _minor), unicast_flag_(_unicast_flag) {
}
-
+ const std::shared_ptr<const serviceinfo> &info_;
service_t service_;
instance_t instance_;
major_version_t major_;
minor_version_t minor_;
- ttl_t ttl_;
+ bool unicast_flag_;
};
struct ev_offer_change: sc::event<ev_offer_change> {
};
+struct ev_request_service: sc::event<ev_request_service> {
+};
+
} // namespace sd
} // namespace vsomeip
diff --git a/implementation/service_discovery/include/ip_option_impl.hpp b/implementation/service_discovery/include/ip_option_impl.hpp
index 8fd426b..e753b4e 100644
--- a/implementation/service_discovery/include/ip_option_impl.hpp
+++ b/implementation/service_discovery/include/ip_option_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/ipv4_option_impl.hpp b/implementation/service_discovery/include/ipv4_option_impl.hpp
index b8051cc..c233f0f 100644
--- a/implementation/service_discovery/include/ipv4_option_impl.hpp
+++ b/implementation/service_discovery/include/ipv4_option_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/ipv6_option_impl.hpp b/implementation/service_discovery/include/ipv6_option_impl.hpp
index 48938b0..c2b962f 100644
--- a/implementation/service_discovery/include/ipv6_option_impl.hpp
+++ b/implementation/service_discovery/include/ipv6_option_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/load_balancing_option_impl.hpp b/implementation/service_discovery/include/load_balancing_option_impl.hpp
index 0308a06..7504657 100755
--- a/implementation/service_discovery/include/load_balancing_option_impl.hpp
+++ b/implementation/service_discovery/include/load_balancing_option_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/message_element_impl.hpp b/implementation/service_discovery/include/message_element_impl.hpp
index 39ae3a1..c05b76e 100755
--- a/implementation/service_discovery/include/message_element_impl.hpp
+++ b/implementation/service_discovery/include/message_element_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/message_impl.hpp b/implementation/service_discovery/include/message_impl.hpp
index b0702df..a8573b8 100755
--- a/implementation/service_discovery/include/message_impl.hpp
+++ b/implementation/service_discovery/include/message_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -14,6 +14,16 @@
#include "../include/primitive_types.hpp"
#include "../../message/include/message_base_impl.hpp"
+# if _MSC_VER >= 1300
+/*
+* Diamond inheritance is used for the vsomeip::message_base base class.
+* The Microsoft compiler put warning (C4250) using a desired c++ feature: "Delegating to a sister class"
+* A powerful technique that arises from using virtual inheritance is to delegate a method from a class in another class
+* by using a common abstract base class. This is also called cross delegation.
+*/
+# pragma warning( disable : 4250 )
+# endif
+
namespace vsomeip {
namespace sd {
diff --git a/implementation/service_discovery/include/option_impl.hpp b/implementation/service_discovery/include/option_impl.hpp
index 90a6a48..21e8b9c 100644
--- a/implementation/service_discovery/include/option_impl.hpp
+++ b/implementation/service_discovery/include/option_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/primitive_types.hpp b/implementation/service_discovery/include/primitive_types.hpp
index fd12698..13f4478 100644
--- a/implementation/service_discovery/include/primitive_types.hpp
+++ b/implementation/service_discovery/include/primitive_types.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/protection_option_impl.hpp b/implementation/service_discovery/include/protection_option_impl.hpp
index 565b22b..e1f8d1e 100755
--- a/implementation/service_discovery/include/protection_option_impl.hpp
+++ b/implementation/service_discovery/include/protection_option_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/request.hpp b/implementation/service_discovery/include/request.hpp
index 9e62deb..99fe507 100644
--- a/implementation/service_discovery/include/request.hpp
+++ b/implementation/service_discovery/include/request.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -29,10 +29,15 @@ public:
ttl_t get_ttl() const;
void set_ttl(ttl_t _ttl);
+ uint8_t get_sent_counter() const;
+ void set_sent_counter(uint8_t _sent_counter);
+
private:
major_version_t major_;
minor_version_t minor_;
ttl_t ttl_;
+
+ uint8_t sent_counter_;
};
} // namespace sd
diff --git a/implementation/service_discovery/include/runtime.hpp b/implementation/service_discovery/include/runtime.hpp
index 47255a2..656e2d5 100644
--- a/implementation/service_discovery/include/runtime.hpp
+++ b/implementation/service_discovery/include/runtime.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/runtime_impl.hpp b/implementation/service_discovery/include/runtime_impl.hpp
index cc0e14e..111d56e 100644
--- a/implementation/service_discovery/include/runtime_impl.hpp
+++ b/implementation/service_discovery/include/runtime_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/service_discovery.hpp b/implementation/service_discovery/include/service_discovery.hpp
index 894de0c..ebc81fa 100644
--- a/implementation/service_discovery/include/service_discovery.hpp
+++ b/implementation/service_discovery/include/service_discovery.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -11,6 +11,8 @@
#include <vsomeip/primitive_types.hpp>
#include <vsomeip/enumeration_types.hpp>
+#include "../../routing/include/serviceinfo.hpp"
+#include "../../endpoints/include/endpoint.hpp"
namespace vsomeip {
@@ -41,12 +43,28 @@ public:
eventgroup_t _eventgroup, client_t _client) = 0;
virtual void unsubscribe_all(service_t _service, instance_t _instance) = 0;
- virtual void send(bool _is_announcing) = 0;
+ virtual bool send(bool _is_announcing, bool _is_find = false) = 0;
virtual void on_message(const byte_t *_data, length_t _length,
- const boost::asio::ip::address &_sender) = 0;
+ const boost::asio::ip::address &_sender,
+ const boost::asio::ip::address &_destination) = 0;
virtual void on_offer_change() = 0;
+
+ virtual void send_subscriptions(service_t _service, instance_t _instance,
+ client_t _client, bool _reliable) = 0;
+
+ virtual void send_unicast_offer_service(const std::shared_ptr<const serviceinfo> &_info,
+ service_t _service, instance_t _instance,
+ major_version_t _major,
+ minor_version_t _minor) = 0;
+ virtual void send_multicast_offer_service(const std::shared_ptr<const serviceinfo>& _info,
+ service_t _service, instance_t _instance,
+ major_version_t _major,
+ minor_version_t _minor) = 0;
+ virtual void on_reliable_endpoint_connected(
+ service_t _service, instance_t _instance,
+ const std::shared_ptr<const vsomeip::endpoint> &_endpoint) = 0;
};
} // namespace sd
diff --git a/implementation/service_discovery/include/service_discovery_fsm.hpp b/implementation/service_discovery/include/service_discovery_fsm.hpp
index f3fe7fd..915b3e3 100644
--- a/implementation/service_discovery/include/service_discovery_fsm.hpp
+++ b/implementation/service_discovery/include/service_discovery_fsm.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -14,6 +14,8 @@
#include <boost/statechart/state.hpp>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/transition.hpp>
+#include "../../routing/include/serviceinfo.hpp"
+
#include "../include/fsm_base.hpp"
#include "../include/fsm_events.hpp"
@@ -40,7 +42,8 @@ struct fsm: sc::state_machine<fsm, inactive>, public fsm_base {
void set_fsm(std::shared_ptr<service_discovery_fsm> _fsm);
- void timer_expired(const boost::system::error_code &_error);
+ void timer_expired(const boost::system::error_code &_error,
+ bool _use_alt_timeout);
uint32_t initial_delay_;
uint32_t repetitions_base_delay_;
@@ -95,9 +98,15 @@ struct repeat: sc::state<repeat, active> {
sc::result react(const ev_find_service &_event);
};
-struct announce: sc::state<announce, active> {
+struct offer;
+struct find;
+struct main: sc::state<main, active, mpl::list<offer, find>> {
+ main(my_context _context);
+};
+
+struct offer: sc::state<offer, main::orthogonal<0> > {
- announce(my_context _context);
+ offer(my_context _context);
typedef mpl::list<sc::custom_reaction<ev_timeout>,
sc::custom_reaction<ev_find_service>,
@@ -106,9 +115,39 @@ struct announce: sc::state<announce, active> {
sc::result react(const ev_timeout &_event);
sc::result react(const ev_find_service &_event);
sc::result react(const ev_offer_change &_event);
+
+ uint8_t run_;
+};
+
+struct idle;
+struct find: sc::state<find, main::orthogonal<1>, idle> {
+
+ find(my_context _context);
+
+ uint8_t run_;
+};
+
+struct idle: sc::state<idle, find> {
+ idle(my_context _context);
+
+ typedef mpl::list<sc::custom_reaction<ev_request_service> >reactions;
+
+ sc::result react(const ev_request_service &_event);
};
-} // namespace _offer
+struct send: sc::state<send, find> {
+ send(my_context _context);
+
+ typedef mpl::list<
+ sc::custom_reaction<ev_alt_timeout>,
+ sc::custom_reaction<ev_none>
+ > reactions;
+
+ sc::result react(const ev_alt_timeout &_event);
+ sc::result react(const ev_none &_event);
+};
+
+} // namespace _sd
///////////////////////////////////////////////////////////////////////////////
// Interface
@@ -121,13 +160,36 @@ public:
void start();
void stop();
- void send(bool _is_announcing);
+ bool send(bool _is_announcing, bool _is_find = false);
+
+ void send_unicast_offer_service(
+ const std::shared_ptr<const serviceinfo> &_info,
+ service_t _service, instance_t _instance,
+ major_version_t _major,
+ minor_version_t _minor);
+
+ void send_multicast_offer_service(
+ const std::shared_ptr<const serviceinfo> &_info,
+ service_t _service, instance_t _instance,
+ major_version_t _major,
+ minor_version_t _minor);
inline void process(const sc::event_base &_event) {
std::lock_guard<std::mutex> its_lock(lock_);
fsm_->process_event(_event);
}
+ inline uint8_t get_repetition_max() const {
+ if (!fsm_)
+ return 0;
+
+ return fsm_->repetitions_max_;
+ }
+
+ std::chrono::milliseconds get_elapsed_offer_timer();
+
+ bool check_is_multicast_offer();
+
private:
std::weak_ptr<service_discovery> discovery_;
std::shared_ptr<_sd::fsm> fsm_;
diff --git a/implementation/service_discovery/include/service_discovery_host.hpp b/implementation/service_discovery/include/service_discovery_host.hpp
index 27d8007..1795d89 100644
--- a/implementation/service_discovery/include/service_discovery_host.hpp
+++ b/implementation/service_discovery/include/service_discovery_host.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -41,7 +41,7 @@ public:
bool _flush) = 0;
virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target,
- const byte_t *_data, uint32_t _size) = 0;
+ const byte_t *_data, uint32_t _size, uint16_t _sd_port) = 0;
virtual void add_routing_info(service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor, ttl_t _ttl,
@@ -53,12 +53,14 @@ public:
virtual void del_routing_info(service_t _service, instance_t _instance,
bool _has_reliable, bool _has_unreliable) = 0;
- virtual ttl_t update_routing_info(ttl_t _elapsed) = 0;
+ virtual std::chrono::milliseconds update_routing_info(
+ std::chrono::milliseconds _elapsed) = 0;
virtual void on_subscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup,
std::shared_ptr<endpoint_definition> _subscriber,
- std::shared_ptr<endpoint_definition> _target) = 0;
+ std::shared_ptr<endpoint_definition> _target,
+ const std::chrono::high_resolution_clock::time_point &_expiration) = 0;
virtual void on_unsubscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup,
@@ -67,11 +69,27 @@ public:
virtual void on_subscribe_ack(service_t _service, instance_t _instance,
const boost::asio::ip::address &_address, uint16_t _port) = 0;
- virtual std::shared_ptr<endpoint> find_or_create_remote_client(service_t _service,
- instance_t _instance, bool _reliable, client_t _client) = 0;
+ virtual void on_subscribe_ack(client_t _client,
+ service_t _service, instance_t _instance, eventgroup_t _eventgroup) = 0;
+
+ virtual std::shared_ptr<endpoint> find_or_create_remote_client(
+ service_t _service, instance_t _instance,
+ bool _reliable, client_t _client) = 0;
virtual void expire_subscriptions(const boost::asio::ip::address &_address) = 0;
virtual void expire_services(const boost::asio::ip::address &_address) = 0;
+
+ virtual bool on_subscribe_accepted(service_t _service, instance_t _instance,
+ eventgroup_t _eventgroup, std::shared_ptr<endpoint_definition> _target,
+ const std::chrono::high_resolution_clock::time_point &_expiration) = 0;
+
+ virtual void on_subscribe_nack(client_t _client,
+ service_t _service, instance_t _instance, eventgroup_t _eventgroup) = 0;
+
+ 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;
};
} // namespace sd
diff --git a/implementation/service_discovery/include/service_discovery_impl.hpp b/implementation/service_discovery/include/service_discovery_impl.hpp
index 7efb6eb..4e64328 100644
--- a/implementation/service_discovery/include/service_discovery_impl.hpp
+++ b/implementation/service_discovery/include/service_discovery_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -14,8 +14,11 @@
#include <boost/asio/system_timer.hpp>
#include "service_discovery.hpp"
+#include "../../endpoints/include/endpoint_definition.hpp"
#include "../../routing/include/types.hpp"
#include "ip_option_impl.hpp"
+#include "ipv4_option_impl.hpp"
+#include "ipv6_option_impl.hpp"
namespace vsomeip {
@@ -35,6 +38,15 @@ class subscription;
typedef std::map<service_t, std::map<instance_t, std::shared_ptr<request> > > requests_t;
+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;
+ vsomeip::service_t service_id;
+ vsomeip::instance_t instance_id;
+ vsomeip::eventgroup_t eventgroup_;
+};
+
class service_discovery_impl: public service_discovery,
public std::enable_shared_from_this<service_discovery_impl> {
public:
@@ -59,18 +71,36 @@ public:
eventgroup_t _eventgroup, client_t _client);
void unsubscribe_all(service_t _service, instance_t _instance);
- void send(bool _is_announcing);
+ bool send(bool _is_announcing, bool _is_find);
void on_message(const byte_t *_data, length_t _length,
- const boost::asio::ip::address &_sender);
+ const boost::asio::ip::address &_sender,
+ const boost::asio::ip::address &_destination);
void on_offer_change();
+ void send_unicast_offer_service(const std::shared_ptr<const serviceinfo> &_info,
+ service_t _service, instance_t _instance,
+ major_version_t _major,
+ minor_version_t _minor);
+
+ void send_multicast_offer_service(const std::shared_ptr<const serviceinfo>& _info,
+ service_t _service, instance_t _instance,
+ major_version_t _major,
+ minor_version_t _minor);
+
+ void on_reliable_endpoint_connected(
+ service_t _service, instance_t _instance,
+ const std::shared_ptr<const vsomeip::endpoint> &_endpoint);
+
private:
+
+
std::pair<session_t, bool> get_session(const boost::asio::ip::address &_address);
void increment_session(const boost::asio::ip::address &_address);
- bool is_reboot(const boost::asio::ip::address &_address,
+ bool is_reboot(const boost::asio::ip::address &_sender,
+ const boost::asio::ip::address &_destination,
bool _reboot_flag, session_t _session);
void insert_option(std::shared_ptr<message_impl> &_message,
@@ -78,24 +108,29 @@ private:
const boost::asio::ip::address &_address, uint16_t _port,
bool _is_reliable);
void insert_find_entries(std::shared_ptr<message_impl> &_message,
- requests_t &_requests);
+ requests_t &_requests, uint32_t _start, uint32_t &_size, bool &_done);
void insert_offer_entries(std::shared_ptr<message_impl> &_message,
- services_t &_services);
- void insert_offer_service(std::shared_ptr<message_impl> _message,
+ services_t &_services, uint32_t &_start, uint32_t _size, bool &_done);
+ bool insert_offer_service(std::shared_ptr<message_impl> _message,
service_t _service, instance_t _instance,
- const std::shared_ptr<const serviceinfo> &_info);
+ const std::shared_ptr<const serviceinfo> &_info,
+ uint32_t &_size);
void insert_subscription(std::shared_ptr<message_impl> &_message,
service_t _service, instance_t _instance, eventgroup_t _eventgroup,
+ std::shared_ptr<subscription> &_subscription, bool _insert_reliable, bool _insert_unreliable);
+ void insert_nack_subscription_on_resubscribe(std::shared_ptr<message_impl> &_message,
+ service_t _service, instance_t _instance, eventgroup_t _eventgroup,
std::shared_ptr<subscription> &_subscription);
void insert_subscription_ack(std::shared_ptr<message_impl> &_message,
service_t _service, instance_t _instance, eventgroup_t _eventgroup,
- std::shared_ptr<eventgroupinfo> &_info, ttl_t _ttl);
+ std::shared_ptr<eventgroupinfo> &_info, ttl_t _ttl, uint8_t _counter, major_version_t _major, uint16_t _reserved);
void insert_subscription_nack(std::shared_ptr<message_impl> &_message, service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
- std::shared_ptr<eventgroupinfo> &_info);
+ uint8_t _counter, major_version_t _major, uint16_t _reserved);
void process_serviceentry(std::shared_ptr<serviceentry_impl> &_entry,
- const std::vector<std::shared_ptr<option_impl> > &_options);
+ const std::vector<std::shared_ptr<option_impl> > &_options,
+ bool _unicast_flag);
void process_offerservice_serviceentry(
service_t _service, instance_t _instance, major_version_t _major,
minor_version_t _minor, ttl_t _ttl,
@@ -103,39 +138,63 @@ private:
uint16_t _reliable_port,
const boost::asio::ip::address &_unreliable_address,
uint16_t _unreliable_port);
- void send_unicast_offer_service(const std::shared_ptr<const serviceinfo>& _info,
- service_t _service, instance_t _instance,
- major_version_t _major,
- minor_version_t _minor);
- void process_findservice_serviceentry(service_t _service,
- instance_t _instance,
- major_version_t _major,
- minor_version_t _minor);
- void process_eventgroupentry(std::shared_ptr<eventgroupentry_impl> &_entry,
- const std::vector<std::shared_ptr<option_impl> > &_options);
+ void send_offer_service(
+ const std::shared_ptr<const serviceinfo> &_info, service_t _service,
+ instance_t _instance, major_version_t _major, minor_version_t _minor,
+ bool _unicast_flag);
+ void process_findservice_serviceentry(service_t _service,
+ instance_t _instance,
+ major_version_t _major,
+ minor_version_t _minor,
+ bool _unicast_flag);
+ void process_eventgroupentry(
+ std::shared_ptr<eventgroupentry_impl> &_entry,
+ const std::vector<std::shared_ptr<option_impl> > &_options,
+ std::shared_ptr < message_impl > &its_message_response,
+ std::vector <accepted_subscriber_t> &accepted_subscribers);
void handle_eventgroup_subscription(service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
- major_version_t _major, ttl_t _ttl,
- const boost::asio::ip::address &_reliable_address,
- uint16_t _reliable_port, uint16_t _unreliable_port);
+ major_version_t _major, ttl_t _ttl, uint8_t _counter, uint16_t _reserved,
+ const boost::asio::ip::address &_first_address, uint16_t _first_port,
+ bool _is_first_reliable,
+ const boost::asio::ip::address &_second_address, uint16_t _second_port,
+ bool _is_second_reliable,
+ std::shared_ptr < message_impl > &its_message,
+ std::vector <accepted_subscriber_t> &accepted_subscribers);
void handle_eventgroup_subscription_ack(service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
- major_version_t _major, ttl_t _ttl,
+ major_version_t _major, ttl_t _ttl, uint8_t _counter,
const boost::asio::ip::address &_address, uint16_t _port);
+ void handle_eventgroup_subscription_nack(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup, uint8_t _counter);
void serialize_and_send(std::shared_ptr<message_impl> _message,
const boost::asio::ip::address &_address);
+ bool is_tcp_connected(service_t _service,
+ instance_t _instance,
+ std::shared_ptr<vsomeip::endpoint_definition> its_endpoint);
+
void start_ttl_timer();
- ttl_t stop_ttl_timer();
+ std::chrono::milliseconds stop_ttl_timer();
+
void check_ttl(const boost::system::error_code &_error);
boost::asio::ip::address get_current_remote_address() const;
+
+ void start_subscription_expiration_timer();
+ void stop_subscription_expiration_timer();
+ void expire_subscriptions(const boost::system::error_code &_error);
+
+ bool check_ipv4_address(boost::asio::ip::address its_address);
+
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);
+ 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,
@@ -146,6 +205,28 @@ private:
service_t _service, instance_t _instance,
client_t _client) const;
+ void send_subscriptions(service_t _service, instance_t _instance, client_t _client, bool _reliable);
+
+ template<class Option, typename AddressType>
+ std::shared_ptr<option_impl> find_existing_option(
+ std::shared_ptr<message_impl> &_message,
+ AddressType _address, uint16_t _port,
+ layer_four_protocol_e _protocol,
+ option_type_e _option_type);
+ template<class Option, typename AddressType>
+ bool check_message_for_ip_option_and_assign_existing(
+ std::shared_ptr<message_impl> &_message,
+ std::shared_ptr<entry_impl> _entry, AddressType _address,
+ uint16_t _port, layer_four_protocol_e _protocol,
+ option_type_e _option_type);
+ template<class Option, typename AddressType>
+ void assign_ip_option_to_entry(std::shared_ptr<Option> _option,
+ AddressType _address, uint16_t _port,
+ layer_four_protocol_e _protocol,
+ std::shared_ptr<entry_impl> _entry);
+
+ std::shared_ptr<request> find_request(service_t _service, instance_t _instance);
+
private:
boost::asio::io_service &io_;
service_discovery_host *host_;
@@ -165,25 +246,31 @@ private:
std::mutex requested_mutex_;
std::map<service_t,
std::map<instance_t,
- std::map<eventgroup_t, std::map<client_t, std::shared_ptr<subscription> > > > > subscribed_;
+ std::map<eventgroup_t,
+ std::map<client_t,
+ std::shared_ptr<subscription> > > > > subscribed_;
std::mutex subscribed_mutex_;
std::mutex serialize_mutex_;
// Sessions
- std::map<boost::asio::ip::address, std::pair<session_t, bool> > sessions_;
- std::map<boost::asio::ip::address, session_t > sessions_receiving_;
-
- // Reboots
- std::set<boost::asio::ip::address> reboots_;
+ std::map<boost::asio::ip::address, std::pair<session_t, bool> > sessions_sent_;
+ std::map<boost::asio::ip::address,
+ std::tuple<session_t, session_t, bool> > sessions_received_;
// Runtime
std::weak_ptr<runtime> runtime_;
- // TTL handling
+ // TTL handling for services offered by other hosts
boost::asio::system_timer ttl_timer_;
- ttl_t smallest_ttl_;
+ 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_;
+
+ uint32_t max_message_size_;
};
} // namespace sd
diff --git a/implementation/service_discovery/include/serviceentry_impl.hpp b/implementation/service_discovery/include/serviceentry_impl.hpp
index f83e62a..1385f84 100644
--- a/implementation/service_discovery/include/serviceentry_impl.hpp
+++ b/implementation/service_discovery/include/serviceentry_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/include/subscription.hpp b/implementation/service_discovery/include/subscription.hpp
index 25df7b3..eb2fb66 100644
--- a/implementation/service_discovery/include/subscription.hpp
+++ b/implementation/service_discovery/include/subscription.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -6,6 +6,7 @@
#ifndef VSOMEIP_SD_SUBSCRIPTION_HPP
#define VSOMEIP_SD_SUBSCRIPTION_HPP
+#include <chrono>
#include <memory>
#include <vsomeip/primitive_types.hpp>
@@ -22,7 +23,9 @@ public:
subscription(major_version_t _major, ttl_t _ttl,
std::shared_ptr<endpoint> _reliable,
std::shared_ptr<endpoint> _unreliable,
- subscription_type_e _subscription_type);
+ subscription_type_e _subscription_type,
+ uint8_t _counter,
+ std::chrono::high_resolution_clock::time_point _expiration);
~subscription();
major_version_t get_major() const;
@@ -34,8 +37,16 @@ public:
bool is_acknowledged() const;
void set_acknowledged(bool _is_acknowledged);
+ bool is_tcp_connection_established() const;
+ void set_tcp_connection_established(bool _is_established);
+
subscription_type_e get_subscription_type() const;
+ 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);
+
private:
major_version_t major_;
ttl_t ttl_;
@@ -44,8 +55,13 @@ private:
std::shared_ptr<endpoint> unreliable_;
bool is_acknowledged_;
+ bool tcp_connection_established_;
subscription_type_e subscription_type_;
+
+ uint8_t counter_;
+
+ std::chrono::high_resolution_clock::time_point expiration_;
};
} // namespace sd
diff --git a/implementation/service_discovery/src/configuration_option_impl.cpp b/implementation/service_discovery/src/configuration_option_impl.cpp
index 793ec95..933f7b1 100755
--- a/implementation/service_discovery/src/configuration_option_impl.cpp
+++ b/implementation/service_discovery/src/configuration_option_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -92,38 +92,36 @@ bool configuration_option_impl::serialize(vsomeip::serializer *_to) const {
bool configuration_option_impl::deserialize(vsomeip::deserializer *_from) {
bool is_successful = option_impl::deserialize(_from);
- uint16_t l_length = 0;
- uint8_t l_itemLength;
+ uint8_t l_itemLength = 0;
std::string l_item(256, 0), l_key, l_value;
- is_successful = is_successful && _from->deserialize(l_length);
- if (l_length > _from->get_remaining()) {
- _from->set_remaining(0);
- return false;
- }
-
- if (l_length > 0) {
- do {
- is_successful = is_successful && _from->deserialize(l_itemLength);
- if (l_itemLength == 0)
- break;
-
- l_length = uint16_t(l_length - l_itemLength);
+ do {
+ l_itemLength = 0;
+ l_key.clear();
+ l_value.clear();
+ l_item.assign(256, '\0');
+ is_successful = is_successful && _from->deserialize(l_itemLength);
+ if (l_itemLength > 0) {
is_successful = is_successful
&& _from->deserialize((uint8_t*) &l_item[0], l_itemLength);
- size_t l_eqPos = l_item.find('=');
- l_key = l_item.substr(0, l_eqPos);
- l_value = l_item.substr(l_eqPos + 1);
-
- if (configuration_.end() == configuration_.find(l_key)) {
- configuration_[l_key] = l_value;
- } else {
- is_successful = false;
+ if (is_successful) {
+ size_t l_eqPos = l_item.find('='); //SWS_SD_00292
+ l_key = l_item.substr(0, l_eqPos);
+
+ //if no "=" is found, no value is present for key (SWS_SD_00466)
+ if( l_eqPos != std::string::npos )
+ l_value = l_item.substr(l_eqPos + 1);
+ if (configuration_.end() == configuration_.find(l_key)) {
+ configuration_[l_key] = l_value;
+ } else {
+ // TODO: log reason for failing deserialization
+ is_successful = false;
+ }
}
- } while (l_length > 0);
- }
+ }
+ } while (is_successful && _from->get_remaining() > 0);
return is_successful;
}
diff --git a/implementation/service_discovery/src/deserializer.cpp b/implementation/service_discovery/src/deserializer.cpp
index cb86c52..744c463 100644
--- a/implementation/service_discovery/src/deserializer.cpp
+++ b/implementation/service_discovery/src/deserializer.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/src/entry_impl.cpp b/implementation/service_discovery/src/entry_impl.cpp
index ea7a511..efff9da 100755
--- a/implementation/service_discovery/src/entry_impl.cpp
+++ b/implementation/service_discovery/src/entry_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -85,20 +85,27 @@ const std::vector<uint8_t> & entry_impl::get_options(uint8_t _run) const {
return invalid_options;
}
-void entry_impl::assign_option(const std::shared_ptr<option_impl> &_option,
- uint8_t _run) {
- if (_run > 0 && _run <= VSOMEIP_MAX_OPTION_RUN) {
- _run--; // Index = Run-1
-
- 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
- options_[_run].push_back(option_index);
- std::sort(options_[_run].begin(), options_[_run].end());
+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() ||
+ 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_[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: decide what to do if option does not belong to the message.
+ // TODO: copy data
}
} else {
- // TODO: decide what to do if an illegal index for the option run is provided
+ // TODO: decide what to do if option does not belong to the message.
}
}
diff --git a/implementation/service_discovery/src/eventgroupentry_impl.cpp b/implementation/service_discovery/src/eventgroupentry_impl.cpp
index 024756d..220fc47 100755
--- a/implementation/service_discovery/src/eventgroupentry_impl.cpp
+++ b/implementation/service_discovery/src/eventgroupentry_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -13,11 +13,13 @@ namespace sd {
eventgroupentry_impl::eventgroupentry_impl() {
eventgroup_ = 0xFFFF;
+ counter_ = 0;
}
eventgroupentry_impl::eventgroupentry_impl(const eventgroupentry_impl &_entry)
: entry_impl(_entry) {
eventgroup_ = _entry.eventgroup_;
+ counter_ = _entry.counter_;
}
eventgroupentry_impl::~eventgroupentry_impl() {
@@ -31,6 +33,22 @@ void eventgroupentry_impl::set_eventgroup(eventgroup_t _eventgroup) {
eventgroup_ = _eventgroup;
}
+uint16_t eventgroupentry_impl::get_reserved() const {
+ return reserved_;
+}
+
+void eventgroupentry_impl::set_reserved(uint16_t _reserved) {
+ reserved_ = _reserved;
+}
+
+uint8_t eventgroupentry_impl::get_counter() const {
+ return counter_;
+}
+
+void eventgroupentry_impl::set_counter(uint8_t _counter) {
+ counter_ = _counter;
+}
+
bool eventgroupentry_impl::serialize(vsomeip::serializer *_to) const {
bool is_successful = entry_impl::serialize(_to);
@@ -39,9 +57,25 @@ bool eventgroupentry_impl::serialize(vsomeip::serializer *_to) const {
is_successful = is_successful
&& _to->serialize(static_cast<uint32_t>(ttl_), true);
- is_successful = is_successful && _to->serialize(protocol::reserved_word);
+ // 4Bit only for counter field
+ if (counter_ >= 16) {
+ is_successful = false;
+ }
+ uint16_t counter_and_reserved = protocol::reserved_word;
+ if (!reserved_ ) {
+ //reserved was not set -> just store counter as uint16
+ counter_and_reserved = static_cast<uint16_t>(counter_);
+ }
+ else {
+ //reserved contains values -> put reserved and counter into 16 bit variable
+ counter_and_reserved = (uint16_t) (((uint16_t) reserved_ << 4) | counter_);
+ }
is_successful = is_successful
+ && _to->serialize((uint8_t)(counter_and_reserved >> 8)); // serialize reserved part 1
+ is_successful = is_successful
+ && _to->serialize((uint8_t)counter_and_reserved); // serialize reserved part 2 and counter
+ is_successful = is_successful
&& _to->serialize(static_cast<uint16_t>(eventgroup_));
return is_successful;
@@ -58,9 +92,20 @@ bool eventgroupentry_impl::deserialize(vsomeip::deserializer *_from) {
is_successful = is_successful && _from->deserialize(its_ttl, true);
ttl_ = static_cast<ttl_t>(its_ttl);
- uint16_t its_reserved1;
- is_successful = is_successful && _from->deserialize(its_reserved1);
+ uint8_t reserved1, reserved2;
+ is_successful = is_successful && _from->deserialize(reserved1); // deserialize reserved part 1
+ is_successful = is_successful && _from->deserialize(reserved2); // deserialize reserved part 2 and counter
+
+ reserved_ = (uint16_t) (((uint16_t)reserved1 << 8) | reserved2); // combine reserved parts and counter
+ reserved_ = (uint16_t) (reserved_ >> 4); //remove counter from reserved field
+
+ //set 4 bits of reserved part 2 field to zero
+ counter_ = (uint8_t) (reserved2 & (~(0xF0)));
+ // 4Bit only for counter field
+ if (counter_ >= 16) {
+ is_successful = false;
+ }
uint16_t its_eventgroup = 0;
is_successful = is_successful && _from->deserialize(its_eventgroup);
eventgroup_ = static_cast<eventgroup_t>(its_eventgroup);
diff --git a/implementation/service_discovery/src/fsm_base.cpp b/implementation/service_discovery/src/fsm_base.cpp
index 07a0def..e3c234b 100644
--- a/implementation/service_discovery/src/fsm_base.cpp
+++ b/implementation/service_discovery/src/fsm_base.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -9,26 +9,42 @@ namespace vsomeip {
namespace sd {
fsm_base::fsm_base(boost::asio::io_service &_io)
- : timer_(_io) {
+ : timer_(_io), alt_timer_(_io) {
}
fsm_base::~fsm_base() {
}
-void fsm_base::start_timer(uint32_t _milliseconds) {
- timer_.expires_from_now(std::chrono::milliseconds(_milliseconds));
- timer_.async_wait(
- std::bind(&fsm_base::timer_expired, shared_from_this(),
- std::placeholders::_1));
+void fsm_base::start_timer(uint32_t _milliseconds, bool _use_alt_timer) {
+ if (_use_alt_timer) {
+ alt_timer_.expires_from_now(std::chrono::milliseconds(_milliseconds));
+ alt_timer_.async_wait(
+ std::bind(&fsm_base::timer_expired, shared_from_this(),
+ std::placeholders::_1, true));
+ } else {
+ timer_.expires_from_now(std::chrono::milliseconds(_milliseconds));
+ timer_.async_wait(
+ std::bind(&fsm_base::timer_expired, shared_from_this(),
+ std::placeholders::_1, false));
+ }
}
-void fsm_base::stop_timer() {
- timer_.cancel();
+void fsm_base::stop_timer(bool _use_alt_timer) {
+ if (_use_alt_timer) {
+ alt_timer_.cancel();
+ } else {
+ timer_.cancel();
+ }
}
-uint32_t fsm_base::expired_from_now() {
- return (uint32_t) std::chrono::duration_cast < std::chrono::milliseconds
- > (timer_.expires_from_now()).count();
+uint32_t fsm_base::expired_from_now(bool _use_alt_timer) {
+ if (_use_alt_timer) {
+ return (uint32_t) std::chrono::duration_cast < std::chrono::milliseconds
+ > (alt_timer_.expires_from_now()).count();
+ } else {
+ return (uint32_t) std::chrono::duration_cast < std::chrono::milliseconds
+ > (timer_.expires_from_now()).count();
+ }
}
} // namespace sd
diff --git a/implementation/service_discovery/src/ip_option_impl.cpp b/implementation/service_discovery/src/ip_option_impl.cpp
index 3fcffac..08f78b9 100644
--- a/implementation/service_discovery/src/ip_option_impl.cpp
+++ b/implementation/service_discovery/src/ip_option_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/src/ipv4_option_impl.cpp b/implementation/service_discovery/src/ipv4_option_impl.cpp
index ca5a2c5..9f2cec4 100644
--- a/implementation/service_discovery/src/ipv4_option_impl.cpp
+++ b/implementation/service_discovery/src/ipv4_option_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -6,6 +6,7 @@
#include <vsomeip/constants.hpp>
#include "../include/constants.hpp"
+#include "../include/defines.hpp"
#include "../include/ipv4_option_impl.hpp"
#include "../../message/include/deserializer.hpp"
#include "../../message/include/serializer.hpp"
@@ -42,7 +43,8 @@ bool ipv4_option_impl::serialize(vsomeip::serializer *_to) const {
}
bool ipv4_option_impl::deserialize(vsomeip::deserializer *_from) {
- bool is_successful = option_impl::deserialize(_from);
+ bool is_successful = option_impl::deserialize(_from)
+ && length_ == VSOMEIP_SD_IPV4_OPTION_LENGTH;
uint8_t its_reserved;
_from->deserialize(address_.data(), 4);
_from->deserialize(its_reserved);
diff --git a/implementation/service_discovery/src/ipv6_option_impl.cpp b/implementation/service_discovery/src/ipv6_option_impl.cpp
index 1aa2570..089b509 100755
--- a/implementation/service_discovery/src/ipv6_option_impl.cpp
+++ b/implementation/service_discovery/src/ipv6_option_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -6,6 +6,7 @@
#include <cstring>
#include "../include/constants.hpp"
+#include "../include/defines.hpp"
#include "../include/ipv6_option_impl.hpp"
#include "../../message/include/deserializer.hpp"
#include "../../message/include/serializer.hpp"
@@ -42,7 +43,8 @@ bool ipv6_option_impl::serialize(vsomeip::serializer *_to) const {
}
bool ipv6_option_impl::deserialize(vsomeip::deserializer *_from) {
- bool is_successful = option_impl::deserialize(_from);
+ bool is_successful = option_impl::deserialize(_from)
+ && length_ == VSOMEIP_SD_IPV6_OPTION_LENGTH;;
uint8_t its_reserved;
_from->deserialize(address_.data(), 16);
_from->deserialize(its_reserved);
diff --git a/implementation/service_discovery/src/load_balancing_option_impl.cpp b/implementation/service_discovery/src/load_balancing_option_impl.cpp
index 47a5b70..5c12c39 100755
--- a/implementation/service_discovery/src/load_balancing_option_impl.cpp
+++ b/implementation/service_discovery/src/load_balancing_option_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/src/message_element_impl.cpp b/implementation/service_discovery/src/message_element_impl.cpp
index 6577115..4c1a683 100755
--- a/implementation/service_discovery/src/message_element_impl.cpp
+++ b/implementation/service_discovery/src/message_element_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/src/message_impl.cpp b/implementation/service_discovery/src/message_impl.cpp
index 3130dda..8159bd4 100755
--- a/implementation/service_discovery/src/message_impl.cpp
+++ b/implementation/service_discovery/src/message_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -204,6 +204,7 @@ bool message_impl::serialize(vsomeip::serializer *_to) const {
bool message_impl::deserialize(vsomeip::deserializer *_from) {
bool is_successful;
+ bool option_is_successful(true);
// header
is_successful = header_.deserialize(_from);
@@ -251,12 +252,12 @@ bool message_impl::deserialize(vsomeip::deserializer *_from) {
_from->set_remaining(options_length_);
}
- while (is_successful && _from->get_remaining()) {
+ while (option_is_successful && _from->get_remaining()) {
std::shared_ptr < option_impl > its_option(deserialize_option(_from));
if (its_option) {
options_.push_back(its_option);
- } else {
- is_successful = false;
+ } else {
+ option_is_successful = false;
}
}
diff --git a/implementation/service_discovery/src/option_impl.cpp b/implementation/service_discovery/src/option_impl.cpp
index cff6d61..71aa085 100755
--- a/implementation/service_discovery/src/option_impl.cpp
+++ b/implementation/service_discovery/src/option_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/src/protection_option_impl.cpp b/implementation/service_discovery/src/protection_option_impl.cpp
index 7197565..366f531 100755
--- a/implementation/service_discovery/src/protection_option_impl.cpp
+++ b/implementation/service_discovery/src/protection_option_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/src/request.cpp b/implementation/service_discovery/src/request.cpp
index 8673822..6ed2d66 100644
--- a/implementation/service_discovery/src/request.cpp
+++ b/implementation/service_discovery/src/request.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -9,8 +9,7 @@ namespace vsomeip {
namespace sd {
request::request(major_version_t _major, minor_version_t _minor, ttl_t _ttl)
- : major_(_major), minor_(_minor), ttl_(_ttl) {
-
+ : major_(_major), minor_(_minor), ttl_(_ttl), sent_counter_(0) {
}
major_version_t request::get_major() const {
@@ -37,5 +36,13 @@ void request::set_ttl(ttl_t _ttl) {
ttl_ = _ttl;
}
+uint8_t request::get_sent_counter() const {
+ return sent_counter_;
+}
+
+void request::set_sent_counter(uint8_t _sent_counter) {
+ sent_counter_ = _sent_counter;
+}
+
} // namespace sd
} // namespace vsomeip
diff --git a/implementation/service_discovery/src/runtime.cpp b/implementation/service_discovery/src/runtime.cpp
index f7d1a4f..be68d24 100644
--- a/implementation/service_discovery/src/runtime.cpp
+++ b/implementation/service_discovery/src/runtime.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/src/runtime_impl.cpp b/implementation/service_discovery/src/runtime_impl.cpp
index 2cc25d2..187b5bc 100644
--- a/implementation/service_discovery/src/runtime_impl.cpp
+++ b/implementation/service_discovery/src/runtime_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/src/service_discovery_fsm.cpp b/implementation/service_discovery/src/service_discovery_fsm.cpp
index d2428dd..a4ede7b 100644
--- a/implementation/service_discovery/src/service_discovery_fsm.cpp
+++ b/implementation/service_discovery/src/service_discovery_fsm.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -9,6 +9,8 @@
#include "../include/defines.hpp"
#include "../include/service_discovery.hpp"
#include "../include/service_discovery_fsm.hpp"
+#include "../../routing/include/serviceinfo.hpp"
+
#include "../../configuration/include/configuration.hpp"
#include "../../logging/include/logger.hpp"
@@ -31,11 +33,17 @@ void fsm::set_fsm(std::shared_ptr<service_discovery_fsm> _fsm) {
fsm_ = _fsm;
}
-void fsm::timer_expired(const boost::system::error_code &_error) {
+void fsm::timer_expired(const boost::system::error_code &_error,
+ bool _use_alt_timeout) {
if (!_error) {
std::shared_ptr<service_discovery_fsm> its_fsm = fsm_.lock();
- if (its_fsm)
- its_fsm->process(ev_timeout());
+ if (its_fsm) {
+ if (_use_alt_timeout) {
+ its_fsm->process(ev_alt_timeout());
+ } else {
+ its_fsm->process(ev_timeout());
+ }
+ }
}
}
@@ -96,7 +104,7 @@ sc::result active::react(const ev_status_change &_event) {
if (!outermost_context().is_up_)
return transit<inactive>();
- return discard_event();
+ return forward_event();
}
///////////////////////////////////////////////////////////////////////////////
@@ -129,53 +137,142 @@ repeat::repeat(my_context _context)
uint32_t its_timeout = (outermost_context().repetitions_base_delay_
<< outermost_context().run_);
outermost_context().run_++;
- fsm->send(false);
+ (void)fsm->send(false);
outermost_context().start_timer(its_timeout);
}
}
sc::result repeat::react(const ev_timeout &_event) {
(void)_event;
-
- if (outermost_context().run_ < outermost_context().repetitions_max_)
+ if (outermost_context().run_ < outermost_context().repetitions_max_) {
return transit<repeat>();
-
- return transit<announce>();
+ }
+ return transit<main>();
}
sc::result repeat::react(const ev_find_service &_event) {
- (void)_event;
- return discard_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) {
+ fsm->send_unicast_offer_service(_event.info_, _event.service_, _event.instance_,
+ _event.major_, _event.minor_);
+ }
+ return forward_event();
}
///////////////////////////////////////////////////////////////////////////////
-// State "Active.Announce"
+// State "Active.Main"
///////////////////////////////////////////////////////////////////////////////
-announce::announce(my_context _context)
- : sc::state<announce, active>(_context) {
+main::main(my_context _context)
+ : sc::state<main, active, mpl::list<offer, find> >(_context) {
+ VSOMEIP_TRACE << "sd::active.main";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// State "Active.Main.Offer"
+///////////////////////////////////////////////////////////////////////////////
+offer::offer(my_context _context)
+ : sc::state<offer, main::orthogonal<0> >(_context) {
std::shared_ptr < service_discovery_fsm > fsm =
outermost_context().fsm_.lock();
if (fsm) {
- VSOMEIP_TRACE << "sd::active.announce";
+ VSOMEIP_TRACE << "sd::active.main.offer";
outermost_context().start_timer(
outermost_context().cyclic_offer_delay_);
- fsm->send(true);
+ (void)fsm->send(true);
}
}
-sc::result announce::react(const ev_timeout &_event) {
+sc::result offer::react(const ev_timeout &_event) {
(void)_event;
- return transit<announce>();
+ return transit<offer>();
}
-sc::result announce::react(const ev_find_service &_event) {
+sc::result offer::react(const ev_find_service &_event) {
+ VSOMEIP_TRACE << "sd::active.main.react.find";
+ std::shared_ptr < service_discovery_fsm > fsm =
+ outermost_context().fsm_.lock();
+ if (fsm) {
+ if(_event.unicast_flag_) {
+ if( !fsm->check_is_multicast_offer()) { // SIP_SD_89
+ fsm->send_unicast_offer_service(_event.info_, _event.service_, _event.instance_,
+ _event.major_, _event.minor_);
+ } else { // SIP_SD_90
+ 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_,
+ _event.major_, _event.minor_);
+ }
+ }
+ return forward_event();
+}
+
+sc::result offer::react(const ev_offer_change &_event) {
(void)_event;
- return discard_event();
+ return transit<offer>();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// State "Active.Announce.Main.Find"
+///////////////////////////////////////////////////////////////////////////////
+find::find(my_context _context)
+ : sc::state<find, main::orthogonal<1>, idle>(_context) {
+ VSOMEIP_TRACE << "sd::active.main.find";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// State "Active.Announce.Idle"
+///////////////////////////////////////////////////////////////////////////////
+idle::idle(my_context _context)
+ : sc::state<idle, find>(_context) {
+ VSOMEIP_TRACE << "sd::active.main.find.idle";
+ context<find>().run_ = 0;
+}
+
+sc::result idle::react(const ev_request_service &_event) {
+ (void)_event;
+ return transit<send>();
}
-sc::result announce::react(const ev_offer_change &_event) {
+///////////////////////////////////////////////////////////////////////////////
+// State "Active.Announce.Main.Find.Send"
+///////////////////////////////////////////////////////////////////////////////
+send::send(my_context _context)
+ : sc::state<send, find>(_context) {
+ std::shared_ptr < service_discovery_fsm > fsm =
+ 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_++;
+ uint32_t its_timeout = (outermost_context().repetitions_base_delay_
+ << context<find>().run_);
+ if (fsm->send(true, true))
+ outermost_context().start_timer(its_timeout, true);
+ }
+ else {
+ post_event(ev_none());
+ }
+ } else {
+ post_event(ev_none());
+ }
+}
+
+sc::result send::react(const ev_alt_timeout &_event) {
+ (void)_event;
+ return transit<send>();
+}
+
+sc::result send::react(const ev_none &_event) {
(void)_event;
- return transit<announce>();
+ return transit<idle>();
}
} // namespace _sd
@@ -187,7 +284,6 @@ service_discovery_fsm::service_discovery_fsm(
std::shared_ptr<service_discovery> _discovery)
: discovery_(_discovery), fsm_(
std::make_shared < _sd::fsm > (_discovery->get_io())) {
-
std::shared_ptr < service_discovery > discovery = discovery_.lock();
if (discovery) {
std::shared_ptr < configuration > its_configuration =
@@ -232,10 +328,10 @@ service_discovery_fsm::service_discovery_fsm(
if (fsm_->cyclic_offer_delay_ <= 0)
fsm_->cyclic_offer_delay_ = VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY;
- VSOMEIP_INFO << "SD configuration [" << fsm_->initial_delay_ << ":"
- << fsm_->repetitions_base_delay_ << ":"
- << (int) fsm_->repetitions_max_ << ":"
- << fsm_->cyclic_offer_delay_ << "]";
+ VSOMEIP_INFO << "SD configuration [" << std::dec << fsm_->initial_delay_ << ":"
+ << std::dec << fsm_->repetitions_base_delay_ << ":"
+ << std::dec << (int) fsm_->repetitions_max_ << ":"
+ << std::dec << fsm_->cyclic_offer_delay_ << "]";
} else {
VSOMEIP_ERROR << "SD initialization failed";
}
@@ -249,10 +345,57 @@ void service_discovery_fsm::start() {
void service_discovery_fsm::stop() {
}
-void service_discovery_fsm::send(bool _is_announcing) {
+bool service_discovery_fsm::send(bool _is_announcing, bool _is_find) {
std::shared_ptr < service_discovery > discovery = discovery_.lock();
- if (discovery)
- discovery->send(_is_announcing);
+ if (discovery) {
+ return discovery->send(_is_announcing, _is_find);
+ }
+ return false;
+}
+
+void service_discovery_fsm::send_unicast_offer_service(
+ const std::shared_ptr<const serviceinfo> &_info,
+ service_t _service, instance_t _instance,
+ major_version_t _major,
+ minor_version_t _minor) {
+ std::shared_ptr < service_discovery > discovery = discovery_.lock();
+ if (discovery) {
+ discovery->send_unicast_offer_service(_info, _service,
+ _instance, _major, _minor );
+ }
+}
+
+void service_discovery_fsm::send_multicast_offer_service(
+ const std::shared_ptr<const serviceinfo> &_info, service_t _service,
+ instance_t _instance, major_version_t _major, minor_version_t _minor) {
+ std::shared_ptr < service_discovery > discovery = discovery_.lock();
+ if (discovery) {
+ discovery->send_multicast_offer_service(_info, _service,
+ _instance, _major, _minor );
+ }
+}
+
+std::chrono::milliseconds service_discovery_fsm::get_elapsed_offer_timer() {
+ //get remaining time to next offer since last offer
+ std::chrono::milliseconds remaining =
+ std::chrono::milliseconds(fsm_->expired_from_now(false));
+
+ if( std::chrono::milliseconds(0) > remaining) {
+ remaining = std::chrono::milliseconds(fsm_->cyclic_offer_delay_);
+ }
+ return std::chrono::milliseconds(fsm_->cyclic_offer_delay_) - remaining;
+}
+
+bool service_discovery_fsm::check_is_multicast_offer() {
+ bool is_multicast(false);
+ std::chrono::milliseconds elapsed_ = get_elapsed_offer_timer();
+ uint32_t half_cyclic_offer_delay_ = fsm_->cyclic_offer_delay_ / 2;
+
+ if( elapsed_ >= std::chrono::milliseconds(half_cyclic_offer_delay_)) {
+ // Response must be a multicast offer (SIP_SD_90)
+ is_multicast = true;
+ }
+ return is_multicast;
}
} // namespace sd
diff --git a/implementation/service_discovery/src/service_discovery_impl.cpp b/implementation/service_discovery/src/service_discovery_impl.cpp
index b5493b8..10c6c96 100644
--- a/implementation/service_discovery/src/service_discovery_impl.cpp
+++ b/implementation/service_discovery/src/service_discovery_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -40,7 +40,13 @@ service_discovery_impl::service_discovery_impl(service_discovery_host *_host)
serializer_(std::make_shared<serializer>()),
deserializer_(std::make_shared<deserializer>()),
ttl_timer_(_host->get_io()),
- smallest_ttl_(DEFAULT_TTL) {
+ smallest_ttl_(DEFAULT_TTL),
+ subscription_expiration_timer_(_host->get_io()) {
+ std::chrono::seconds smallest_ttl(DEFAULT_TTL);
+ 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);
}
service_discovery_impl::~service_discovery_impl() {
@@ -66,6 +72,8 @@ void service_discovery_impl::init() {
port_ = its_configuration->get_sd_port();
reliable_ = (its_configuration->get_sd_protocol()
== "tcp");
+ max_message_size_ = (reliable_ ? VSOMEIP_MAX_TCP_SD_PAYLOAD :
+ VSOMEIP_MAX_UDP_SD_PAYLOAD);
serializer_->create_data(
reliable_ ?
@@ -99,19 +107,26 @@ void service_discovery_impl::stop() {
void service_discovery_impl::request_service(service_t _service,
instance_t _instance, major_version_t _major, minor_version_t _minor,
ttl_t _ttl) {
- std::lock_guard<std::mutex> its_lock(requested_mutex_);
- auto find_service = requested_.find(_service);
- if (find_service != requested_.end()) {
- auto find_instance = find_service->second.find(_instance);
- if (find_instance != find_service->second.end()) {
- // TODO: check version and report errors
+ bool is_new_request(true);
+ {
+ std::lock_guard<std::mutex> its_lock(requested_mutex_);
+ auto find_service = requested_.find(_service);
+ if (find_service != requested_.end()) {
+ auto find_instance = find_service->second.find(_instance);
+ if (find_instance != find_service->second.end()) {
+ is_new_request = false;
+ // TODO: check version and report errors
+ } else {
+ find_service->second[_instance] = std::make_shared < request
+ > (_major, _minor, _ttl);
+ }
} else {
- find_service->second[_instance] = std::make_shared < request
+ requested_[_service][_instance] = std::make_shared < request
> (_major, _minor, _ttl);
}
- } else {
- requested_[_service][_instance] = std::make_shared < request
- > (_major, _minor, _ttl);
+ }
+ if (is_new_request) {
+ default_->process(ev_request_service());
}
}
@@ -123,11 +138,22 @@ void service_discovery_impl::release_service(service_t _service,
}
}
+std::shared_ptr<request>
+service_discovery_impl::find_request(service_t _service, instance_t _instance) {
+ auto find_service = requested_.find(_service);
+ if (find_service != requested_.end()) {
+ auto find_instance = find_service->second.find(_instance);
+ if (find_instance != find_service->second.end()) {
+ return find_instance->second;
+ }
+ }
+ return nullptr;
+}
+
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);
@@ -138,6 +164,8 @@ void service_discovery_impl::subscribe(service_t _service, instance_t _instance,
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 "
@@ -157,25 +185,57 @@ 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;
+ return;
+ }
+
// New subscription
std::shared_ptr < subscription > its_subscription = std::make_shared
- < subscription > (_major, _ttl, its_reliable, its_unreliable, _subscription_type);
+ < 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(false) &&
+ !host_->has_identified(_client, _service, _instance, false)) {
+ return;
+ }
+ }
+
std::shared_ptr<message_impl> its_message
= its_runtime->create_message();
-
- // TODO: consume major & ttl
- insert_subscription(its_message, _service, _instance, _eventgroup,
- its_subscription);
- serialize_and_send(its_message, its_address);
-
- its_subscription->set_acknowledged(false);
+ 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);
+ }
}
}
@@ -246,7 +306,7 @@ 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);
@@ -255,42 +315,33 @@ void service_discovery_impl::unsubscribe(service_t _service,
if (found_eventgroup != found_instance->second.end()) {
auto found_client = found_eventgroup->second.find(_client);
if (found_client != found_eventgroup->second.end()) {
- found_client->second->set_ttl(0);
+ 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;
+ auto endpoint = its_subscription->get_endpoint(false);
+ if (endpoint) {
+ endpoint->get_remote_address(its_address);
+ } else {
+ endpoint = its_subscription->get_endpoint(true);
+ if (endpoint) {
+ 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);
+ }
}
}
}
}
-
- boost::asio::ip::address its_address;
-
- std::shared_ptr < runtime > its_runtime = runtime_.lock();
- if (!its_runtime)
- return;
-
- std::shared_ptr < subscription > its_subscription =
- subscribed_[_service][_instance][_eventgroup][_client];
-
- auto endpoint = its_subscription->get_endpoint(false);
- if (endpoint) {
- endpoint->get_remote_address(its_address);
- } else {
- endpoint = its_subscription->get_endpoint(true);
- if (endpoint) {
- endpoint->get_remote_address(its_address);
- }
- }
-
- std::shared_ptr < message_impl > its_message
- = its_runtime->create_message();
-
- insert_subscription(its_message, _service, _instance, _eventgroup,
- its_subscription);
-
- std::pair<session_t, bool> its_session = get_session(its_address);
- its_message->set_session(its_session.first);
- its_message->set_reboot_flag(its_session.second);
-
- serialize_and_send(its_message, its_address);
}
void service_discovery_impl::unsubscribe_all(service_t _service, instance_t _instance) {
@@ -313,9 +364,9 @@ void service_discovery_impl::unsubscribe_all(service_t _service, instance_t _ins
std::pair<session_t, bool> service_discovery_impl::get_session(
const boost::asio::ip::address &_address) {
std::pair<session_t, bool> its_session;
- auto found_session = sessions_.find(_address);
- if (found_session == sessions_.end()) {
- its_session = sessions_[_address] = { 1, true };
+ auto found_session = sessions_sent_.find(_address);
+ if (found_session == sessions_sent_.end()) {
+ its_session = sessions_sent_[_address] = { 1, true };
} else {
its_session = found_session->second;
}
@@ -324,174 +375,363 @@ std::pair<session_t, bool> service_discovery_impl::get_session(
void service_discovery_impl::increment_session(
const boost::asio::ip::address &_address) {
- auto found_session = sessions_.find(_address);
- if (found_session != sessions_.end()) {
+ auto found_session = sessions_sent_.find(_address);
+ if (found_session != sessions_sent_.end()) {
found_session->second.first++;
- if (found_session->second.first == 0) { // Wrap
- found_session->second = { 1, false };
+ if (found_session->second.first == 0) { // Wrap --> change the reboot flag!
+ found_session->second = { 1, !found_session->second.second };
}
}
}
bool service_discovery_impl::is_reboot(
- const boost::asio::ip::address &_address,
+ const boost::asio::ip::address &_sender,
+ const boost::asio::ip::address &_destination,
bool _reboot_flag, session_t _session) {
-
bool result(false);
-#ifdef VSOMEIP_TODO
- // Reboot detection: Either the flag has changed from false to true,
- // or the session identifier overrun while the flag is true
- if (reboots_.find(_address) == reboots_.end()) {
- if (_reboot_flag) {
- reboots_.insert(_address);
- result = true;
- }
+
+ auto its_last_session = sessions_received_.find(_sender);
+ bool is_multicast = _destination.is_multicast();
+
+ session_t its_unicast_id = (is_multicast ? 0 : _session);
+ session_t its_multicast_id = (is_multicast ? _session : 0);
+
+ if (its_last_session == sessions_received_.end()) {
+ sessions_received_[_sender]
+ = std::make_tuple(its_multicast_id, its_unicast_id, _reboot_flag);
} else {
- auto its_last_session = sessions_receiving_.find(_address);
- if(its_last_session != sessions_receiving_.end()) {
- if (_reboot_flag && its_last_session->second >= _session) {
+ // Reboot detection: Either the flag has changed from false to true,
+ // or the session identifier overrun while the flag is true
+ if (its_last_session != sessions_received_.end()) {
+ if (!std::get<2>(its_last_session->second) && _reboot_flag) {
result = true;
+ } else {
+ session_t its_last_id = (is_multicast ?
+ std::get<0>(its_last_session->second) :
+ std::get<1>(its_last_session->second));
+
+ if (std::get<2>(its_last_session->second) && _reboot_flag &&
+ its_last_id >= _session) {
+ result = true;
+ }
}
}
+
+ if (result == false) {
+ // no reboot -> update session
+ if (is_multicast) {
+ std::get<0>(its_last_session->second) = its_multicast_id;
+ } else {
+ std::get<1>(its_last_session->second) = its_unicast_id;
+ }
+ } else {
+ // reboot -> reset the session
+ sessions_received_.erase(_sender);
+ }
}
- sessions_receiving_[_address] = _session;
-#else
- (void)_address;
- (void)_reboot_flag;
- (void)_session;
-#endif
return result;
}
+template<class Option, typename AddressType>
+std::shared_ptr<option_impl> service_discovery_impl::find_existing_option(
+ std::shared_ptr<message_impl> &_message,
+ AddressType _address,
+ uint16_t _port, layer_four_protocol_e _protocol,
+ option_type_e _option_type) {
+ if (_message->get_options().size() > 0) {
+ std::uint16_t option_length(0x0);
+ if(_option_type == option_type_e::IP4_ENDPOINT ||
+ _option_type == option_type_e::IP4_MULTICAST) {
+ option_length = 0x9;
+ } else if(_option_type == option_type_e::IP6_ENDPOINT ||
+ _option_type == option_type_e::IP6_MULTICAST) {
+ option_length = 0x15;
+ } else { // unsupported option type
+ return nullptr;
+ }
+
+ bool is_multicast(false);
+ if(_option_type == option_type_e::IP4_MULTICAST ||
+ _option_type == option_type_e::IP6_MULTICAST) {
+ is_multicast = true;
+ }
+
+ std::vector<std::shared_ptr<option_impl>> its_options =
+ _message->get_options();
+ for (const std::shared_ptr<option_impl>& opt : its_options) {
+ if (opt->get_length() == option_length &&
+ 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)->get_address() == _address) {
+ return opt;
+ }
+ }
+ }
+ return nullptr;
+}
+template<class Option, typename AddressType>
+bool service_discovery_impl::check_message_for_ip_option_and_assign_existing(
+ std::shared_ptr<message_impl> &_message,
+ std::shared_ptr<entry_impl> _entry, AddressType _address,
+ uint16_t _port, layer_four_protocol_e _protocol,
+ option_type_e _option_type) {
+
+ std::shared_ptr<option_impl> its_option
+ = find_existing_option<Option, AddressType>(_message, _address, _port, _protocol, _option_type);
+ if (its_option) {
+ _entry->assign_option(its_option);
+ return true;
+ }
+ return false;
+}
+
+template<class Option, typename AddressType>
+void service_discovery_impl::assign_ip_option_to_entry(
+ std::shared_ptr<Option> _option, AddressType _address,
+ uint16_t _port, layer_four_protocol_e _protocol,
+ std::shared_ptr<entry_impl> _entry) {
+ if (_option) {
+ _option->set_address(_address);
+ _option->set_port(_port);
+ _option->set_layer_four_protocol(_protocol);
+ _entry->assign_option(_option);
+ }
+}
+
void service_discovery_impl::insert_option(
std::shared_ptr<message_impl> &_message,
std::shared_ptr<entry_impl> _entry,
const boost::asio::ip::address &_address, uint16_t _port,
bool _is_reliable) {
+ layer_four_protocol_e its_protocol =
+ _is_reliable ? layer_four_protocol_e::TCP :
+ layer_four_protocol_e::UDP;
+ bool entry_assigned(false);
+
if (unicast_ == _address) {
if (unicast_.is_v4()) {
ipv4_address_t its_address = unicast_.to_v4().to_bytes();
- std::shared_ptr < ipv4_option_impl > its_option =
- _message->create_ipv4_option(false);
- if (its_option) {
- its_option->set_address(its_address);
- its_option->set_port(_port);
- its_option->set_layer_four_protocol(
- _is_reliable ? layer_four_protocol_e::TCP :
- layer_four_protocol_e::UDP);
- _entry->assign_option(its_option, 1);
+ entry_assigned = check_message_for_ip_option_and_assign_existing<
+ ipv4_option_impl, ipv4_address_t>(_message, _entry,
+ its_address, _port, its_protocol,
+ option_type_e::IP4_ENDPOINT);
+ if(!entry_assigned) {
+ std::shared_ptr < ipv4_option_impl > its_option =
+ _message->create_ipv4_option(false);
+ assign_ip_option_to_entry<ipv4_option_impl, ipv4_address_t>(
+ its_option, its_address, _port, its_protocol, _entry);
}
} else {
ipv6_address_t its_address = unicast_.to_v6().to_bytes();
- std::shared_ptr < ipv6_option_impl > its_option =
- _message->create_ipv6_option(false);
- if (its_option) {
- its_option->set_address(its_address);
- its_option->set_port(_port);
- its_option->set_layer_four_protocol(
- _is_reliable ? layer_four_protocol_e::TCP :
- layer_four_protocol_e::UDP);
- _entry->assign_option(its_option, 1);
+ entry_assigned = check_message_for_ip_option_and_assign_existing<
+ ipv6_option_impl, ipv6_address_t>(_message, _entry,
+ its_address, _port, its_protocol,
+ option_type_e::IP6_ENDPOINT);
+ if(!entry_assigned) {
+ std::shared_ptr < ipv6_option_impl > its_option =
+ _message->create_ipv6_option(false);
+ assign_ip_option_to_entry<ipv6_option_impl, ipv6_address_t>(
+ its_option, its_address, _port, its_protocol, _entry);
}
}
} else {
if (_address.is_v4()) {
ipv4_address_t its_address = _address.to_v4().to_bytes();
- std::shared_ptr < ipv4_option_impl > its_option =
- _message->create_ipv4_option(true);
- if (its_option) {
- its_option->set_address(its_address);
- its_option->set_port(_port);
- its_option->set_layer_four_protocol(
- _is_reliable ? layer_four_protocol_e::TCP :
- layer_four_protocol_e::UDP);
- _entry->assign_option(its_option, 1);
+ entry_assigned = check_message_for_ip_option_and_assign_existing<
+ ipv4_option_impl, ipv4_address_t>(_message, _entry,
+ its_address, _port, its_protocol,
+ option_type_e::IP4_MULTICAST);
+ if(!entry_assigned) {
+ std::shared_ptr < ipv4_option_impl > its_option =
+ _message->create_ipv4_option(true);
+ assign_ip_option_to_entry<ipv4_option_impl, ipv4_address_t>(
+ its_option, its_address, _port, its_protocol, _entry);
}
} else {
ipv6_address_t its_address = _address.to_v6().to_bytes();
- std::shared_ptr < ipv6_option_impl > its_option =
- _message->create_ipv6_option(true);
- if (its_option) {
- its_option->set_address(its_address);
- its_option->set_port(_port);
- its_option->set_layer_four_protocol(
- _is_reliable ? layer_four_protocol_e::TCP :
- layer_four_protocol_e::UDP);
- _entry->assign_option(its_option, 1);
+ entry_assigned = check_message_for_ip_option_and_assign_existing<
+ ipv6_option_impl, ipv6_address_t>(_message, _entry,
+ its_address, _port, its_protocol,
+ option_type_e::IP6_MULTICAST);
+ if(!entry_assigned) {
+ std::shared_ptr < ipv6_option_impl > its_option =
+ _message->create_ipv6_option(true);
+ assign_ip_option_to_entry<ipv6_option_impl, ipv6_address_t>(
+ its_option, its_address, _port, its_protocol, _entry);
}
}
}
}
void service_discovery_impl::insert_find_entries(
- std::shared_ptr<message_impl> &_message, requests_t &_requests) {
+ std::shared_ptr<message_impl> &_message, requests_t &_requests,
+ uint32_t _start, uint32_t &_size, bool &_done) {
std::lock_guard<std::mutex> its_lock(requested_mutex_);
+ uint32_t its_size(0);
+ uint32_t i = 0;
+
+ _done = true;
for (auto its_service : _requests) {
for (auto its_instance : its_service.second) {
auto its_request = its_instance.second;
- std::shared_ptr < serviceentry_impl > its_entry =
- _message->create_service_entry();
- if (its_entry) {
- its_entry->set_type(entry_type_e::FIND_SERVICE);
- its_entry->set_service(its_service.first);
- its_entry->set_instance(its_instance.first);
- its_entry->set_major_version(its_request->get_major());
- its_entry->set_minor_version(its_request->get_minor());
- its_entry->set_ttl(its_request->get_ttl());
- } else {
- VSOMEIP_ERROR << "Failed to create service entry!";
+ uint8_t its_sent_counter = its_request->get_sent_counter();
+ if (its_sent_counter != default_->get_repetition_max()) {
+ if (i >= _start) {
+ if (its_size + VSOMEIP_SOMEIP_SD_ENTRY_SIZE <= max_message_size_) {
+ std::shared_ptr < serviceentry_impl > its_entry =
+ _message->create_service_entry();
+ if (its_entry) {
+ its_entry->set_type(entry_type_e::FIND_SERVICE);
+ its_entry->set_service(its_service.first);
+ its_entry->set_instance(its_instance.first);
+ its_entry->set_major_version(its_request->get_major());
+ 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!";
+ }
+ } else {
+ _done = false;
+ _size = its_size;
+ return;
+ }
+ }
}
+ i++;
}
}
+ _size = its_size;
}
void service_discovery_impl::insert_offer_entries(
- std::shared_ptr<message_impl> &_message, services_t &_services) {
+ std::shared_ptr<message_impl> &_message, services_t &_services,
+ uint32_t &_start, uint32_t _size, bool &_done) {
+ uint32_t i = 0;
+ uint32_t its_size(_size);
for (auto its_service : _services) {
for (auto its_instance : its_service.second) {
- insert_offer_service(_message, its_service.first,
- its_instance.first, its_instance.second);
+ // Only insert services with configured endpoint(s)
+ if (its_instance.second->get_endpoint(false)
+ || its_instance.second->get_endpoint(true)) {
+ if (i >= _start) {
+ if (!insert_offer_service(_message, its_service.first,
+ its_instance.first, its_instance.second, its_size)) {
+ _start = i;
+ _done = false;
+ return;
+ }
+ }
+ }
+ i++;
}
}
+ _start = i;
+ _done = true;
}
void service_discovery_impl::insert_subscription(
std::shared_ptr<message_impl> &_message, service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
- std::shared_ptr<subscription> &_subscription) {
+ std::shared_ptr<subscription> &_subscription,
+ bool _insert_reliable, bool _insert_unreliable) {
+ if((_insert_reliable && !_insert_unreliable && !_subscription->get_endpoint(true)) ||
+ (_insert_unreliable && !_insert_reliable && !_subscription->get_endpoint(false))) {
+ // don't create an eventgroup entry if there isn't an endpoint option
+ // to insert
+ return;
+ }
std::shared_ptr < eventgroupentry_impl > its_entry =
_message->create_eventgroup_entry();
its_entry->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP);
its_entry->set_service(_service);
its_entry->set_instance(_instance);
its_entry->set_eventgroup(_eventgroup);
+ its_entry->set_counter(_subscription->get_counter());
its_entry->set_major_version(_subscription->get_major());
its_entry->set_ttl(_subscription->get_ttl());
- std::shared_ptr < endpoint > its_endpoint = _subscription->get_endpoint(
- true);
+ std::shared_ptr < endpoint > its_endpoint;
+ if (_insert_reliable) {
+ its_endpoint = _subscription->get_endpoint(true);
+ if (its_endpoint) {
+ insert_option(_message, its_entry, unicast_,
+ its_endpoint->get_local_port(), true);
+ }
+ }
+ if (_insert_unreliable) {
+ its_endpoint = _subscription->get_endpoint(false);
+ if (its_endpoint) {
+ insert_option(_message, its_entry, unicast_,
+ its_endpoint->get_local_port(), false);
+ }
+ }
+}
+
+void service_discovery_impl::insert_nack_subscription_on_resubscribe(std::shared_ptr<message_impl> &_message,
+ service_t _service, instance_t _instance, eventgroup_t _eventgroup,
+ std::shared_ptr<subscription> &_subscription) {
+
+ // SIP_SD_844:
+ // This method is used for not acknowledged subscriptions on renew subscription
+ // Two entries: Stop subscribe & subscribe within one SD-Message
+ // One option: Both entries reference it
+
+ std::shared_ptr < eventgroupentry_impl > its_stop_entry =
+ _message->create_eventgroup_entry();
+ its_stop_entry->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP);
+ its_stop_entry->set_service(_service);
+ its_stop_entry->set_instance(_instance);
+ its_stop_entry->set_eventgroup(_eventgroup);
+ its_stop_entry->set_counter(_subscription->get_counter());
+ its_stop_entry->set_major_version(_subscription->get_major());
+ its_stop_entry->set_ttl(0);
+
+ std::shared_ptr < eventgroupentry_impl > its_entry =
+ _message->create_eventgroup_entry();
+ its_entry->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP);
+ its_entry->set_service(_service);
+ its_entry->set_instance(_instance);
+ its_entry->set_eventgroup(_eventgroup);
+ its_entry->set_counter(_subscription->get_counter());
+ its_entry->set_major_version(_subscription->get_major());
+ its_entry->set_ttl(_subscription->get_ttl());
+
+ std::shared_ptr < endpoint > its_endpoint;
+ its_endpoint = _subscription->get_endpoint(true);
if (its_endpoint) {
- insert_option(_message, its_entry, unicast_, its_endpoint->get_local_port(),
- true);
+ insert_option(_message, its_stop_entry, unicast_,
+ its_endpoint->get_local_port(), true);
+ insert_option(_message, its_entry, unicast_,
+ its_endpoint->get_local_port(), true);
}
its_endpoint = _subscription->get_endpoint(false);
if (its_endpoint) {
- insert_option(_message, its_entry, unicast_, its_endpoint->get_local_port(),
- false);
+ insert_option(_message, its_stop_entry, unicast_,
+ its_endpoint->get_local_port(), false);
+ insert_option(_message, its_entry, unicast_,
+ its_endpoint->get_local_port(), false);
}
}
void service_discovery_impl::insert_subscription_ack(
std::shared_ptr<message_impl> &_message, service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
- std::shared_ptr<eventgroupinfo> &_info, ttl_t _ttl) {
+ std::shared_ptr<eventgroupinfo> &_info, ttl_t _ttl, uint8_t _counter, major_version_t _major, uint16_t _reserved) {
std::shared_ptr < eventgroupentry_impl > its_entry =
_message->create_eventgroup_entry();
its_entry->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP_ACK);
its_entry->set_service(_service);
its_entry->set_instance(_instance);
its_entry->set_eventgroup(_eventgroup);
- its_entry->set_major_version(_info->get_major());
+ its_entry->set_major_version(_major);
+ its_entry->set_reserved(_reserved);
+ its_entry->set_counter(_counter);
// SWS_SD_00315
its_entry->set_ttl(_ttl);
@@ -505,7 +745,7 @@ void service_discovery_impl::insert_subscription_ack(
void service_discovery_impl::insert_subscription_nack(
std::shared_ptr<message_impl> &_message, service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
- std::shared_ptr<eventgroupinfo> &_info) {
+ uint8_t _counter, major_version_t _major, uint16_t _reserved) {
std::shared_ptr < eventgroupentry_impl > its_entry =
_message->create_eventgroup_entry();
// SWS_SD_00316 and SWS_SD_00385
@@ -513,51 +753,75 @@ void service_discovery_impl::insert_subscription_nack(
its_entry->set_service(_service);
its_entry->set_instance(_instance);
its_entry->set_eventgroup(_eventgroup);
- its_entry->set_major_version(_info->get_major());
+ its_entry->set_major_version(_major);
+ its_entry->set_reserved(_reserved);
+ its_entry->set_counter(_counter);
// SWS_SD_00432
its_entry->set_ttl(0x0);
-
- boost::asio::ip::address its_address;
- uint16_t its_port;
- if (_info->get_multicast(its_address, its_port)) {
- insert_option(_message, its_entry, its_address, its_port, false);
- }
}
-void service_discovery_impl::send(bool _is_announcing) {
-
+bool service_discovery_impl::send(bool _is_announcing, bool _is_find) {
std::shared_ptr < runtime > its_runtime = runtime_.lock();
- if (!its_runtime)
- return;
-
- std::shared_ptr < message_impl > its_message =
- its_runtime->create_message();
-
- // TODO: optimize building of SD message (common options, utilize the two runs)
-
- // If we are not in main phase, include "FindOffer"-entries
- if (!_is_announcing) {
- insert_find_entries(its_message, requested_);
- }
+ if (its_runtime) {
+ std::vector< std::shared_ptr< message_impl > > its_messages;
+ std::shared_ptr < message_impl > its_message;
+
+ uint32_t its_remaining(max_message_size_);
+
+ if (_is_find || !_is_announcing) {
+ uint32_t its_start(0);
+ uint32_t its_size(0);
+ bool is_done(false);
+ while (!is_done) {
+ its_message = its_runtime->create_message();
+ its_messages.push_back(its_message);
+
+ insert_find_entries(its_message, requested_, its_start, its_size, is_done);
+ its_start += its_size / VSOMEIP_SOMEIP_SD_ENTRY_SIZE;
+ };
+ its_remaining -= its_size;
+ } else {
+ its_message = its_runtime->create_message();
+ its_messages.push_back(its_message);
+ }
- // Always include the "OfferService"-entries for the service group
- services_t its_offers = host_->get_offered_services();
- insert_offer_entries(its_message, its_offers);
+ if (!_is_find) {
+ services_t its_offers = host_->get_offered_services();
+
+ uint32_t its_start(0);
+ bool is_done(false);
+ while (!is_done) {
+ insert_offer_entries(its_message, its_offers, its_start, its_remaining, is_done);
+ if (!is_done) {
+ its_remaining = max_message_size_;
+ its_message = its_runtime->create_message();
+ its_messages.push_back(its_message);
+ }
+ }
+ }
- // Serialize and send
- 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_);
+ // 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_);
+ }
+ has_sent = true;
+ }
}
+ return has_sent;
}
+ return false;
}
// Interface endpoint_host
void service_discovery_impl::on_message(const byte_t *_data, length_t _length,
- const boost::asio::ip::address &_sender) {
+ const boost::asio::ip::address &_sender,
+ const boost::asio::ip::address &_destination) {
#if 0
std::stringstream msg;
msg << "sdi::on_message: ";
@@ -574,30 +838,51 @@ void service_discovery_impl::on_message(const byte_t *_data, length_t _length,
return;
}
// Expire all subscriptions / services in case of reboot
- if (is_reboot(_sender,
+ if (is_reboot(_sender, _destination,
its_message->get_reboot_flag(), its_message->get_session())) {
host_->expire_subscriptions(_sender);
host_->expire_services(_sender);
}
- ttl_t expired = stop_ttl_timer();
+ std::chrono::milliseconds expired = stop_ttl_timer();
smallest_ttl_ = host_->update_routing_info(expired);
std::vector < std::shared_ptr<option_impl> > its_options =
its_message->get_options();
+
+ std::shared_ptr<runtime> its_runtime = runtime_.lock();
+ if (!its_runtime) {
+ return;
+ }
+
+ std::shared_ptr < message_impl > its_message_response
+ = its_runtime->create_message();
+ std::vector <accepted_subscriber_t> accepted_subscribers;
+
for (auto its_entry : its_message->get_entries()) {
if (its_entry->is_service_entry()) {
std::shared_ptr < serviceentry_impl > its_service_entry =
std::dynamic_pointer_cast < serviceentry_impl
> (its_entry);
- process_serviceentry(its_service_entry, its_options);
+ bool its_unicast_flag = its_message->get_unicast_flag();
+ process_serviceentry(its_service_entry, its_options, its_unicast_flag );
} else {
std::shared_ptr < eventgroupentry_impl > its_eventgroup_entry =
std::dynamic_pointer_cast < eventgroupentry_impl
> (its_entry);
- process_eventgroupentry(its_eventgroup_entry, its_options);
+ process_eventgroupentry( its_eventgroup_entry, its_options, its_message_response, accepted_subscribers);
}
}
+
+ //send ACK / NACK if present
+ if( 0 < its_message_response->get_entries().size() && its_message_response ) {
+ serialize_and_send(its_message_response, _sender);
+ }
+
+ for( const auto &a : accepted_subscribers) {
+ host_->on_subscribe(a.service_id, a.instance_id, a.eventgroup_, a.subscriber, a.target, a.its_expiration);
+ }
+ accepted_subscribers.clear();
start_ttl_timer();
} else {
VSOMEIP_ERROR << "service_discovery_impl::on_message: deserialization error.";
@@ -612,7 +897,8 @@ void service_discovery_impl::on_offer_change() {
// Entry processing
void service_discovery_impl::process_serviceentry(
std::shared_ptr<serviceentry_impl> &_entry,
- const std::vector<std::shared_ptr<option_impl> > &_options) {
+ const std::vector<std::shared_ptr<option_impl> > &_options,
+ bool _unicast_flag) {
// Read service info from entry
entry_type_e its_type = _entry->get_type();
@@ -629,56 +915,60 @@ void service_discovery_impl::process_serviceentry(
boost::asio::ip::address its_unreliable_address;
uint16_t its_unreliable_port(ILLEGAL_PORT);
-
for (auto i : { 1, 2 }) {
for (auto its_index : _entry->get_options(uint8_t(i))) {
- std::shared_ptr < option_impl > its_option = _options[its_index];
+ if( _options.size() > its_index ) {
+ std::shared_ptr < option_impl > its_option = _options[its_index];
- switch (its_option->get_type()) {
- case option_type_e::IP4_ENDPOINT: {
- std::shared_ptr < ipv4_option_impl > its_ipv4_option =
- std::dynamic_pointer_cast < ipv4_option_impl
- > (its_option);
+ switch (its_option->get_type()) {
+ case option_type_e::IP4_ENDPOINT: {
+ std::shared_ptr < ipv4_option_impl > its_ipv4_option =
+ std::dynamic_pointer_cast < ipv4_option_impl
+ > (its_option);
- boost::asio::ip::address_v4 its_ipv4_address(
- its_ipv4_option->get_address());
+ boost::asio::ip::address_v4 its_ipv4_address(
+ its_ipv4_option->get_address());
- if (its_ipv4_option->get_layer_four_protocol()
- == layer_four_protocol_e::UDP) {
- its_unreliable_address = its_ipv4_address;
- its_unreliable_port = its_ipv4_option->get_port();
- } else {
- its_reliable_address = its_ipv4_address;
- its_reliable_port = its_ipv4_option->get_port();
+ if (its_ipv4_option->get_layer_four_protocol()
+ == layer_four_protocol_e::UDP) {
+
+
+ its_unreliable_address = its_ipv4_address;
+ its_unreliable_port = its_ipv4_option->get_port();
+ } else {
+ its_reliable_address = its_ipv4_address;
+ its_reliable_port = its_ipv4_option->get_port();
+ }
+ break;
}
- break;
- }
- case option_type_e::IP6_ENDPOINT: {
- std::shared_ptr < ipv6_option_impl > its_ipv6_option =
- std::dynamic_pointer_cast < ipv6_option_impl
- > (its_option);
+ case option_type_e::IP6_ENDPOINT: {
+ std::shared_ptr < ipv6_option_impl > its_ipv6_option =
+ std::dynamic_pointer_cast < ipv6_option_impl
+ > (its_option);
- boost::asio::ip::address_v6 its_ipv6_address(
- its_ipv6_option->get_address());
+ boost::asio::ip::address_v6 its_ipv6_address(
+ its_ipv6_option->get_address());
- if (its_ipv6_option->get_layer_four_protocol()
- == layer_four_protocol_e::UDP) {
- its_unreliable_address = its_ipv6_address;
- its_unreliable_port = its_ipv6_option->get_port();
- } else {
- its_reliable_address = its_ipv6_address;
- its_reliable_port = its_ipv6_option->get_port();
+ if (its_ipv6_option->get_layer_four_protocol()
+ == layer_four_protocol_e::UDP) {
+ its_unreliable_address = its_ipv6_address;
+ its_unreliable_port = its_ipv6_option->get_port();
+ } else {
+ its_reliable_address = its_ipv6_address;
+ its_reliable_port = its_ipv6_option->get_port();
+ }
+ break;
+ }
+ case option_type_e::IP4_MULTICAST:
+ case option_type_e::IP6_MULTICAST:
+ break;
+ case option_type_e::CONFIGURATION:
+ break;
+ case option_type_e::UNKNOWN:
+ default:
+ VSOMEIP_ERROR << "Unsupported service option";
+ break;
}
- break;
- }
- case option_type_e::IP4_MULTICAST:
- case option_type_e::IP6_MULTICAST:
- VSOMEIP_ERROR << "Invalid service option (Multicast)";
- break;
- case option_type_e::UNKNOWN:
- default:
- VSOMEIP_ERROR << "Unsupported service option";
- break;
}
}
}
@@ -687,7 +977,7 @@ void service_discovery_impl::process_serviceentry(
switch(its_type) {
case entry_type_e::FIND_SERVICE:
process_findservice_serviceentry(its_service, its_instance,
- its_major, its_minor);
+ its_major, its_minor, _unicast_flag);
break;
case entry_type_e::OFFER_SERVICE:
process_offerservice_serviceentry(its_service, its_instance,
@@ -701,6 +991,10 @@ 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());
+
unsubscribe_all(its_service, its_instance);
host_->del_routing_info(its_service, its_instance,
(its_reliable_port != ILLEGAL_PORT),
@@ -719,6 +1013,10 @@ void service_discovery_impl::process_offerservice_serviceentry(
if (!its_runtime)
return;
+ std::shared_ptr<request> its_request = find_request(_service, _instance);
+ if (its_request)
+ its_request->set_sent_counter(default_->get_repetition_max());
+
host_->add_routing_info(_service, _instance,
_major, _minor, _ttl,
_reliable_address, _reliable_port,
@@ -732,31 +1030,54 @@ void service_discovery_impl::process_offerservice_serviceentry(
if (0 < found_instance->second.size()) {
std::shared_ptr<message_impl> its_message
= 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;
+ bool has_address(false);
+ boost::asio::ip::address its_address;
+ get_subscription_endpoints(
+ its_client.second->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);
if (its_subscription->is_acknowledged()) {
- 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(
- its_client.second->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);
-
- // TODO: consume major & ttl
- insert_subscription(its_message,
- _service, _instance,
- its_eventgroup.first,
- its_subscription);
+ if (its_subscription->get_endpoint(true)
+ && its_subscription->get_endpoint(true)->is_connected()) {
+ insert_subscription(its_message,
+ _service, _instance,
+ its_eventgroup.first,
+ 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,
+ its_eventgroup.first,
+ its_subscription, false, true);
+ its_client.second->set_tcp_connection_established(false);
+ }
its_subscription->set_acknowledged(false);
+ } else {
+ insert_nack_subscription_on_resubscribe(its_message,
+ _service, _instance, its_eventgroup.first,
+ its_subscription);
}
}
}
@@ -780,7 +1101,7 @@ void service_discovery_impl::process_offerservice_serviceentry(
serializer_->serialize(its_message.get());
if (host_->send_to(its_target,
serializer_->get_data(),
- serializer_->get_size())) {
+ serializer_->get_size(), port_)) {
increment_session(its_target->get_address());
}
serializer_->reset();
@@ -793,7 +1114,7 @@ void service_discovery_impl::process_offerservice_serviceentry(
void service_discovery_impl::process_findservice_serviceentry(
service_t _service, instance_t _instance, major_version_t _major,
- minor_version_t _minor) {
+ minor_version_t _minor, bool _unicast_flag) {
services_t offered_services = host_->get_offered_services();
auto found_service = offered_services.find(_service);
if (found_service != offered_services.end()) {
@@ -801,14 +1122,18 @@ void service_discovery_impl::process_findservice_serviceentry(
auto found_instance = found_service->second.find(_instance);
if (found_instance != found_service->second.end()) {
std::shared_ptr<serviceinfo> its_info = found_instance->second;
- send_unicast_offer_service(its_info, _service, _instance,
- _major, _minor);
+
+ ev_find_service find_event(its_info, _service,
+ _instance, _major, _minor, _unicast_flag );
+ default_->process(find_event);
}
} else {
// send back all available instances
for (const auto &found_instance : found_service->second) {
- send_unicast_offer_service(found_instance.second, _service,
- _instance, _major, _minor);
+
+ ev_find_service find_event(found_instance.second, _service,
+ _instance, _major, _minor, _unicast_flag );
+ default_->process(find_event);
}
}
}
@@ -818,76 +1143,224 @@ void service_discovery_impl::send_unicast_offer_service(
const std::shared_ptr<const serviceinfo> &_info, service_t _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()) {
+ 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();
- insert_offer_service(its_message, _service, _instance, _info);
+
+ 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());
}
}
}
-void service_discovery_impl::insert_offer_service(
+void service_discovery_impl::send_multicast_offer_service(
+ const std::shared_ptr<const serviceinfo> &_info, service_t _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_);
+ }
+ }
+ }
+ }
+}
+
+void service_discovery_impl::on_reliable_endpoint_connected(
+ service_t _service, instance_t _instance,
+ const std::shared_ptr<const vsomeip::endpoint> &_endpoint) {
+ std::shared_ptr<runtime> its_runtime = runtime_.lock();
+ if (!its_runtime) {
+ return;
+ }
+
+ // 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_);
+
+ 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;
+
+ 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);
+ }
+ }
+ }
+ }
+ }
+ if (0 < its_message->get_entries().size() && has_address) {
+ serialize_and_send(its_message, its_address);
+ }
+ }
+ }
+ }
+}
+
+bool service_discovery_impl::insert_offer_service(
std::shared_ptr < message_impl > _message, service_t _service,
- instance_t _instance, const std::shared_ptr<const serviceinfo> &_info) {
- std::shared_ptr < serviceentry_impl > its_entry =
- _message->create_service_entry();
- if (its_entry) {
- its_entry->set_type(entry_type_e::OFFER_SERVICE);
- its_entry->set_service(_service);
- its_entry->set_instance(_instance);
- its_entry->set_major_version(_info->get_major());
- its_entry->set_minor_version(_info->get_minor());
-
- ttl_t its_ttl = _info->get_ttl();
- if (its_ttl > 0)
- its_ttl = ttl_;
- its_entry->set_ttl(its_ttl);
-
- std::shared_ptr < endpoint > its_endpoint =
- _info->get_endpoint(true);
- if (its_endpoint) {
- insert_option(_message, its_entry, unicast_,
- its_endpoint->get_local_port(), true);
- if (0 == _info->get_ttl()) {
- host_->del_routing_info(_service,
- _instance, true, false);
+ instance_t _instance, const std::shared_ptr<const serviceinfo> &_info,
+ uint32_t &_size) {
+
+ std::shared_ptr < endpoint > its_reliable = _info->get_endpoint(true);
+ std::shared_ptr < endpoint > its_unreliable = _info->get_endpoint(false);
+
+ uint32_t its_size = VSOMEIP_SOMEIP_SD_ENTRY_SIZE;
+ if (its_reliable) {
+ uint32_t its_endpoint_size(0);
+ if (unicast_.is_v4()) {
+ if (!find_existing_option<ipv4_option_impl, ipv4_address_t>(_message,
+ unicast_.to_v4().to_bytes(), its_reliable->get_local_port(),
+ layer_four_protocol_e::TCP, option_type_e::IP4_ENDPOINT)) {
+ its_endpoint_size = VSOMEIP_SOMEIP_SD_IPV4_OPTION_SIZE;
+ }
+ } else {
+ if (!find_existing_option<ipv6_option_impl, ipv6_address_t>(_message,
+ unicast_.to_v6().to_bytes(), its_reliable->get_local_port(),
+ layer_four_protocol_e::TCP, option_type_e::IP6_ENDPOINT)) {
+ its_endpoint_size = VSOMEIP_SOMEIP_SD_IPV6_OPTION_SIZE;
}
}
+ its_size += its_endpoint_size;
+ }
+ if (its_unreliable) {
+ uint32_t its_endpoint_size(0);
+ if (unicast_.is_v4()) {
+ if (!find_existing_option<ipv4_option_impl, ipv4_address_t>(_message,
+ unicast_.to_v4().to_bytes(), its_unreliable->get_local_port(),
+ layer_four_protocol_e::UDP, option_type_e::IP4_ENDPOINT)) {
+ its_endpoint_size = VSOMEIP_SOMEIP_SD_IPV4_OPTION_SIZE;
+ }
+ } else {
+ if (!find_existing_option<ipv6_option_impl, ipv6_address_t>(_message,
+ unicast_.to_v6().to_bytes(), its_reliable->get_local_port(),
+ layer_four_protocol_e::UDP, option_type_e::IP6_ENDPOINT)) {
+ its_endpoint_size = VSOMEIP_SOMEIP_SD_IPV6_OPTION_SIZE;
+ }
+ }
+ its_size += its_endpoint_size;
+ }
- its_endpoint = _info->get_endpoint(false);
- if (its_endpoint) {
- insert_option(_message, its_entry, unicast_,
- its_endpoint->get_local_port(), false);
- if (0 == _info->get_ttl()) {
- host_->del_routing_info(_service,
- _instance, false, true);
+ if (its_size <= _size) {
+ _size -= its_size;
+
+ std::shared_ptr < serviceentry_impl > its_entry =
+ _message->create_service_entry();
+ if (its_entry) {
+ its_entry->set_type(entry_type_e::OFFER_SERVICE);
+ its_entry->set_service(_service);
+ its_entry->set_instance(_instance);
+ its_entry->set_major_version(_info->get_major());
+ its_entry->set_minor_version(_info->get_minor());
+
+ ttl_t its_ttl = _info->get_ttl();
+ if (its_ttl > 0)
+ its_ttl = ttl_;
+ its_entry->set_ttl(its_ttl);
+
+ if (its_reliable) {
+ insert_option(_message, its_entry, unicast_,
+ its_reliable->get_local_port(), true);
+ if (0 == _info->get_ttl()) {
+ host_->del_routing_info(_service,
+ _instance, true, false);
+ }
+ }
+
+ if (its_unreliable) {
+ insert_option(_message, its_entry, unicast_,
+ its_unreliable->get_local_port(), false);
+ if (0 == _info->get_ttl()) {
+ host_->del_routing_info(_service,
+ _instance, false, true);
+ }
}
+ // This would be a clean solution but does _not_ work with the ANDi tool
+ //unsubscribe_all(_service, _instance);
+ } else {
+ VSOMEIP_ERROR << "Failed to create service entry.";
}
- } else {
- VSOMEIP_ERROR << "Failed to create service entry.";
+ return true;
}
+
+ return false;
}
void service_discovery_impl::process_eventgroupentry(
std::shared_ptr<eventgroupentry_impl> &_entry,
- const std::vector<std::shared_ptr<option_impl> > &_options) {
+ const std::vector<std::shared_ptr<option_impl> > &_options,
+ std::shared_ptr < message_impl > &its_message_response,
+ std::vector <accepted_subscriber_t> &accepted_subscribers) {
service_t its_service = _entry->get_service();
instance_t its_instance = _entry->get_instance();
eventgroup_t its_eventgroup = _entry->get_eventgroup();
entry_type_e its_type = _entry->get_type();
major_version_t its_major = _entry->get_major_version();
ttl_t its_ttl = _entry->get_ttl();
+ uint16_t its_reserved = _entry->get_reserved();
+ uint8_t its_counter = _entry->get_counter();
if (_entry->get_owning_message()->get_return_code() != return_code) {
VSOMEIP_ERROR << "Invalid return code in SD header";
- send_eventgroup_subscription_nack(its_service, its_instance,
- its_eventgroup, its_major);
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
return;
}
@@ -895,30 +1368,35 @@ 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";
- send_eventgroup_subscription_nack(its_service, its_instance,
- its_eventgroup, its_major);
+ 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";
- send_eventgroup_subscription_nack(its_service, its_instance,
- its_eventgroup, its_major);
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
return;
}
if (_options.size()
- < (_entry->get_num_options(1) + _entry->get_num_options(2))) {
+ // cast is needed in order to get unsigned type since int will be promoted
+ // by the + operator on 16 bit or higher machines.
+ < static_cast<std::vector<std::shared_ptr<option_impl>>::size_type>(
+ (_entry->get_num_options(1)) + (_entry->get_num_options(2)))) {
VSOMEIP_ERROR << "Fewer options in SD message than "
- "referenced in EventGroup entry";
- send_eventgroup_subscription_nack(its_service, its_instance,
- its_eventgroup, its_major);
+ "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);
return;
}
}
- boost::asio::ip::address its_reliable_address;
- uint16_t its_reliable_port(ILLEGAL_PORT);
- boost::asio::ip::address its_unreliable_address;
- uint16_t its_unreliable_port(ILLEGAL_PORT);
+ boost::asio::ip::address its_first_address;
+ uint16_t its_first_port(ILLEGAL_PORT);
+ bool is_first_reliable(false);
+ boost::asio::ip::address its_second_address;
+ uint16_t its_second_port(ILLEGAL_PORT);
+ bool is_second_reliable(false);
for (auto i : { 1, 2 }) {
for (auto its_index : _entry->get_options(uint8_t(i))) {
@@ -926,12 +1404,15 @@ void service_discovery_impl::process_eventgroupentry(
try {
its_option = _options.at(its_index);
} catch(const std::out_of_range& e) {
+#ifdef WIN32
+ e; // silence MSVC warining C4101
+#endif
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) {
- send_eventgroup_subscription_nack(its_service, its_instance,
- its_eventgroup, its_major);
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
}
return;
}
@@ -945,18 +1426,40 @@ 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)) {
- send_eventgroup_subscription_nack(its_service,
- its_instance, its_eventgroup, its_major);
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
return;
}
- // TODO: add error handling (port already set) here
- if (its_ipv4_option->get_layer_four_protocol()
- == layer_four_protocol_e::UDP) {
- its_unreliable_address = its_ipv4_address;
- its_unreliable_port = its_ipv4_option->get_port();
+
+ if (its_first_port == ILLEGAL_PORT) {
+ its_first_address = its_ipv4_address;
+ its_first_port = its_ipv4_option->get_port();
+ is_first_reliable = (its_ipv4_option->get_layer_four_protocol()
+ == layer_four_protocol_e::TCP);
+
+ 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!";
+ return;
+ }
+ } else
+ if (its_second_port == ILLEGAL_PORT) {
+ its_second_address = its_ipv4_address;
+ its_second_port = its_ipv4_option->get_port();
+ is_second_reliable = (its_ipv4_option->get_layer_four_protocol()
+ == layer_four_protocol_e::TCP);
+
+ 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!";
+ return;
+ }
} else {
- its_reliable_address = its_ipv4_address;
- its_reliable_port = its_ipv4_option->get_port();
+ // TODO: error message, too many endpoint options!
}
} else {
VSOMEIP_ERROR
@@ -973,18 +1476,24 @@ 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)) {
- send_eventgroup_subscription_nack(its_service,
- its_instance, its_eventgroup, its_major);
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
return;
}
- // TODO: add error handling (port already set) here
- if (its_ipv6_option->get_layer_four_protocol()
- == layer_four_protocol_e::UDP) {
- its_unreliable_address = its_ipv6_address;
- its_unreliable_port = its_ipv6_option->get_port();
+
+ if (its_first_port == ILLEGAL_PORT) {
+ its_first_address = its_ipv6_address;
+ its_first_port = its_ipv6_option->get_port();
+ is_first_reliable = (its_ipv6_option->get_layer_four_protocol()
+ == layer_four_protocol_e::TCP);
+ } else
+ if (its_second_port == ILLEGAL_PORT) {
+ its_second_address = its_ipv6_address;
+ its_second_port = its_ipv6_option->get_port();
+ is_second_reliable = (its_ipv6_option->get_layer_four_protocol()
+ == layer_four_protocol_e::TCP);
} else {
- its_reliable_address = its_ipv6_address;
- its_reliable_port = its_ipv6_option->get_port();
+ // TODO: error message, too many endpoint options!
}
} else {
VSOMEIP_ERROR
@@ -1001,8 +1510,16 @@ void service_discovery_impl::process_eventgroupentry(
boost::asio::ip::address_v4 its_ipv4_address(
its_ipv4_option->get_address());
- its_unreliable_address = its_ipv4_address;
- its_unreliable_port = its_ipv4_option->get_port();
+ if (its_first_port == ILLEGAL_PORT) {
+ its_first_address = its_ipv4_address;
+ its_first_port = its_ipv4_option->get_port();
+ } else
+ if (its_second_port == ILLEGAL_PORT) {
+ its_second_address = its_ipv4_address;
+ its_second_port = its_ipv4_option->get_port();
+ } else {
+ // TODO: error message, too many endpoint options!
+ }
} else {
VSOMEIP_ERROR
<< "Invalid eventgroup option (IPv4 Multicast)";
@@ -1017,18 +1534,32 @@ void service_discovery_impl::process_eventgroupentry(
boost::asio::ip::address_v6 its_ipv6_address(
its_ipv6_option->get_address());
- its_unreliable_address = its_ipv6_address;
- its_unreliable_port = its_ipv6_option->get_port();
+ if (its_first_port == ILLEGAL_PORT) {
+ its_first_address = its_ipv6_address;
+ its_first_port = its_ipv6_option->get_port();
+ } else
+ if (its_second_port == ILLEGAL_PORT) {
+ its_second_address = its_ipv6_address;
+ its_second_port = its_ipv6_option->get_port();
+ } else {
+ // TODO: error message, too many endpoint options!
+ }
} else {
VSOMEIP_ERROR
<< "Invalid eventgroup option (IPv6 Multicast)";
}
break;
+ case option_type_e::CONFIGURATION: {
+ if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type) {
+ }
+ break;
+ }
case option_type_e::UNKNOWN:
default:
VSOMEIP_WARNING << "Unsupported eventgroup option";
- send_eventgroup_subscription_nack(its_service, its_instance,
- its_eventgroup, its_major);
+ insert_subscription_nack(its_message_response, its_service, its_instance,
+ its_eventgroup, its_counter, its_major, its_reserved);
+
break;
}
}
@@ -1036,93 +1567,180 @@ void service_discovery_impl::process_eventgroupentry(
if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type) {
handle_eventgroup_subscription(its_service, its_instance,
- its_eventgroup, its_major, its_ttl,
- (its_reliable_port != ILLEGAL_PORT ?
- its_reliable_address : its_unreliable_address),
- its_reliable_port, its_unreliable_port);
+ its_eventgroup, its_major, its_ttl, its_counter, its_reserved,
+ its_first_address, its_first_port, is_first_reliable,
+ its_second_address, its_second_port, is_second_reliable, its_message_response, accepted_subscribers);
} else {
- handle_eventgroup_subscription_ack(its_service, its_instance,
- its_eventgroup, its_major, its_ttl, its_unreliable_address,
- its_unreliable_port);
+ if( entry_type_e::SUBSCRIBE_EVENTGROUP_ACK == its_type) { //this type is used for ACK and NACK messages
+ if(its_ttl > 0) {
+ handle_eventgroup_subscription_ack(its_service, its_instance,
+ its_eventgroup, its_major, its_ttl, its_counter,
+ its_first_address, its_first_port);
+ } else {
+ handle_eventgroup_subscription_nack(its_service, its_instance, its_eventgroup, its_counter);
+ }
+ }
}
}
void service_discovery_impl::handle_eventgroup_subscription(service_t _service,
instance_t _instance, eventgroup_t _eventgroup, major_version_t _major,
- ttl_t _ttl, const boost::asio::ip::address &_address,
- uint16_t _reliable_port, uint16_t _unreliable_port) {
+ ttl_t _ttl, uint8_t _counter, uint16_t _reserved,
+ const boost::asio::ip::address &_first_address, uint16_t _first_port, bool _is_first_reliable,
+ const boost::asio::ip::address &_second_address, uint16_t _second_port, bool _is_second_reliable,
+ std::shared_ptr < message_impl > &its_message,
+ std::vector <accepted_subscriber_t> &accepted_subscribers) {
- 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);
bool is_nack(false);
- std::shared_ptr < endpoint_definition > its_reliable_subscriber,
- its_unreliable_subscriber;
- std::shared_ptr < endpoint_definition > its_reliable_target,
- its_unreliable_target;
+ std::shared_ptr < endpoint_definition > its_first_subscriber,
+ its_second_subscriber;
+ std::shared_ptr < endpoint_definition > its_first_target,
+ its_second_target;
// 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
its_info = std::make_shared < eventgroupinfo > (_major, 0);
is_nack = true;
- insert_subscription_nack(its_message, _service, _instance, _eventgroup,
- its_info);
- serialize_and_send(its_message, _address);
- //TODO add check if required tcp connection is open
+ insert_subscription_nack(its_message, _service, _instance,
+ _eventgroup, _counter, _major, _reserved);
return;
} else {
- boost::asio::ip::address its_target_address;
- uint16_t its_target_port;
- if (ILLEGAL_PORT != _unreliable_port) {
- its_unreliable_subscriber = endpoint_definition::get(
- _address, _unreliable_port, false);
- if (its_info->get_multicast(its_target_address,
- its_target_port)) {
- its_unreliable_target = endpoint_definition::get(
- its_target_address, its_target_port, false);
- } else {
- its_unreliable_target = its_unreliable_subscriber;
+ boost::asio::ip::address its_first_address, its_second_address;
+ uint16_t its_first_port, its_second_port;
+ if (ILLEGAL_PORT != _first_port) {
+ its_first_subscriber = endpoint_definition::get(
+ _first_address, _first_port, _is_first_reliable);
+ if (!_is_first_reliable &&
+ its_info->get_multicast(its_first_address, its_first_port)) { // udp multicast
+ its_first_target = endpoint_definition::get(
+ its_first_address, its_first_port, false);
+ } 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;
+ insert_subscription_nack(its_message, _service, _instance,
+ _eventgroup, _counter, _major, _reserved);
+ return;
+ }
+ } else { // udp unicast
+ its_first_target = its_first_subscriber;
}
}
- if (ILLEGAL_PORT != _reliable_port) {
- its_reliable_subscriber = endpoint_definition::get(
- _address, _reliable_port, true);
- its_reliable_target = its_reliable_subscriber;
+ if (ILLEGAL_PORT != _second_port) {
+ its_second_subscriber = endpoint_definition::get(
+ _second_address, _second_port, _is_second_reliable);
+ if (!_is_second_reliable &&
+ its_info->get_multicast(its_second_address, its_second_port)) { // udp multicast
+ its_second_target = endpoint_definition::get(
+ its_second_address, its_second_port, false);
+ } 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;
+ insert_subscription_nack(its_message, _service, _instance,
+ _eventgroup, _counter, _major, _reserved);
+ return;
+ }
+ } else { // udp unicast
+ its_second_target = its_second_subscriber;
+ }
}
}
if (_ttl == 0) { // --> unsubscribe
- if (its_unreliable_target) {
- host_->on_unsubscribe(_service, _instance, _eventgroup, its_unreliable_target);
+ if (its_first_subscriber) {
+ host_->on_unsubscribe(_service, _instance, _eventgroup, its_first_subscriber);
}
- if (its_reliable_target) {
- host_->on_unsubscribe(_service, _instance, _eventgroup, its_reliable_target);
+ if (its_second_subscriber) {
+ host_->on_unsubscribe(_service, _instance, _eventgroup, its_second_subscriber);
}
return;
}
- insert_subscription_ack(its_message, _service, _instance, _eventgroup,
- its_info, _ttl);
+ std::chrono::high_resolution_clock::time_point its_expiration
+ = std::chrono::high_resolution_clock::now() + std::chrono::seconds(_ttl);
+
+ if (its_first_target) {
+ if(!host_->on_subscribe_accepted(_service, _instance, _eventgroup,
+ its_first_subscriber, its_expiration)) {
+ is_nack = true;
+ insert_subscription_nack(its_message, _service, _instance, _eventgroup,
+ _counter, _major, _reserved);
+ }
+ }
+ if (its_second_subscriber) {
+ if(!host_->on_subscribe_accepted(_service, _instance, _eventgroup,
+ its_second_subscriber, its_expiration)) {
+ is_nack = true;
+ insert_subscription_nack(its_message, _service, _instance, _eventgroup,
+ _counter, _major, _reserved);
+ }
+ }
+
+ if (!is_nack)
+ {
+ insert_subscription_ack(its_message, _service, _instance, _eventgroup,
+ its_info, _ttl, _counter, _major, _reserved);
+
+ if (its_expiration < next_subscription_expiration_) {
+ stop_subscription_expiration_timer();
+ next_subscription_expiration_ = its_expiration;
+ start_subscription_expiration_timer();
+ }
- serialize_and_send(its_message, _address);
+ if (its_first_target && its_first_subscriber) {
+ accepted_subscriber_t subscriber_;
+ subscriber_.service_id = _service;
+ subscriber_.instance_id = _instance;
+ subscriber_.eventgroup_ = _eventgroup;
+ subscriber_.subscriber = its_first_subscriber;
+ subscriber_.target = its_first_target;
+ subscriber_.its_expiration = its_expiration;
- // Finally register the new subscriber and send him all the fields(!)
- if (!is_nack) {
- if (its_unreliable_target && its_unreliable_subscriber) {
- host_->on_subscribe(_service, _instance, _eventgroup,
- its_unreliable_subscriber, its_unreliable_target);
+ accepted_subscribers.push_back(subscriber_);
+ }
+ if (its_second_target && its_second_subscriber) {
+ accepted_subscriber_t subscriber_;
+ subscriber_.service_id = _service;
+ subscriber_.instance_id = _instance;
+ subscriber_.eventgroup_ = _eventgroup;
+ subscriber_.subscriber = its_second_subscriber;
+ subscriber_.target = its_second_target;
+ subscriber_.its_expiration = its_expiration;
+
+ accepted_subscribers.push_back(subscriber_);
}
- if (its_reliable_target && its_reliable_subscriber) {
- host_->on_subscribe(_service, _instance, _eventgroup,
- its_reliable_subscriber, its_reliable_target);
+ }
+ }
+}
+
+void service_discovery_impl::handle_eventgroup_subscription_nack(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup, uint8_t _counter) {
+ client_t nackedClient = 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()) {
+ for (auto client : found_eventgroup->second) {
+ if (client.second->get_counter() == _counter) {
+ // Deliver nack
+ nackedClient = client.first;
+ host_->on_subscribe_nack(client.first, _service, _instance, _eventgroup);
+ break;
+ }
+ }
+ // Remove nacked subscription
+ found_eventgroup->second.erase(nackedClient);
}
}
}
@@ -1130,11 +1748,11 @@ void service_discovery_impl::handle_eventgroup_subscription(service_t _service,
void service_discovery_impl::handle_eventgroup_subscription_ack(
service_t _service, instance_t _instance, eventgroup_t _eventgroup,
- major_version_t _major, ttl_t _ttl,
+ major_version_t _major, ttl_t _ttl, uint8_t _counter,
const boost::asio::ip::address &_address, uint16_t _port) {
(void)_major;
(void)_ttl;
-
+ 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);
@@ -1142,16 +1760,48 @@ void service_discovery_impl::handle_eventgroup_subscription_ack(
auto found_eventgroup = found_instance->second.find(_eventgroup);
if (found_eventgroup != found_instance->second.end()) {
for (auto its_client : found_eventgroup->second) {
- its_client.second->set_acknowledged(true);
+ if (its_client.second->get_counter() == _counter) {
+ its_client.second->set_acknowledged(true);
+ }
if (_address.is_multicast()) {
host_->on_subscribe_ack(_service, _instance, _address,
_port);
}
+ host_->on_subscribe_ack(its_client.first, _service,
+ _instance, _eventgroup);
}
+ }
+ }
+ }
+}
+bool service_discovery_impl::is_tcp_connected(service_t _service,
+ instance_t _instance,
+ std::shared_ptr<vsomeip::endpoint_definition> its_endpoint) {
+ bool is_connected = false;
+ services_t offered_services = host_->get_offered_services();
+ auto found_service = offered_services.find(_service);
+ if (found_service != offered_services.end()) {
+ if (_instance != ANY_INSTANCE) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ std::shared_ptr<serviceinfo> its_info = found_instance->second;
+ if(its_info) {
+ //get reliable server endpoint
+ auto its_reliable_endpoint = its_info->get_endpoint(true);
+ if(its_reliable_endpoint) {
+ std::shared_ptr<tcp_server_endpoint_impl> its_ptr(std::static_pointer_cast<tcp_server_endpoint_impl>(its_reliable_endpoint));
+ if( !its_ptr->is_established(its_endpoint)) {
+ }
+ else {
+ is_connected = true;
+ }
+ }
+ }
}
}
}
+ return is_connected;
}
void service_discovery_impl::serialize_and_send(
@@ -1165,23 +1815,23 @@ void service_discovery_impl::serialize_and_send(
return;
}
if (host_->send_to(endpoint_definition::get(_address, port_, reliable_),
- serializer_->get_data(), serializer_->get_size())) {
+ serializer_->get_data(), serializer_->get_size(), port_)) {
increment_session(_address);
}
serializer_->reset();
}
void service_discovery_impl::start_ttl_timer() {
- ttl_timer_.expires_from_now(std::chrono::seconds(smallest_ttl_));
+ ttl_timer_.expires_from_now(std::chrono::milliseconds(smallest_ttl_));
ttl_timer_.async_wait(
std::bind(&service_discovery_impl::check_ttl, shared_from_this(),
std::placeholders::_1));
}
-ttl_t service_discovery_impl::stop_ttl_timer() {
- ttl_t remaining = ttl_t(std::chrono::duration_cast<
- std::chrono::seconds
- >(ttl_timer_.expires_from_now()).count());
+std::chrono::milliseconds service_discovery_impl::stop_ttl_timer() {
+ std::chrono::milliseconds remaining = std::chrono::duration_cast<
+ std::chrono::milliseconds
+ >(ttl_timer_.expires_from_now());
ttl_timer_.cancel();
return (smallest_ttl_ - remaining);
}
@@ -1215,11 +1865,17 @@ bool service_discovery_impl::check_static_header_fields(
VSOMEIP_ERROR << "Invalid message type in SD header";
return false;
}
+ if(_message->get_return_code() > return_code_e::E_OK
+ && _message->get_return_code()< return_code_e::E_UNKNOWN) {
+ VSOMEIP_ERROR << "Invalid return code in SD header";
+ return false;
+ }
return true;
}
void service_discovery_impl::send_eventgroup_subscription_nack(
- service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major) {
+ 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;
@@ -1233,7 +1889,7 @@ void service_discovery_impl::send_eventgroup_subscription_nack(
its_info = std::make_shared < eventgroupinfo > (_major, 0);
}
insert_subscription_nack(its_message, _service, _instance, _eventgroup,
- its_info);
+ _counter, _major, _reserved);
serialize_and_send(its_message, get_current_remote_address());
}
}
@@ -1247,5 +1903,113 @@ bool service_discovery_impl::check_layer_four_protocol(
return true;
}
+void service_discovery_impl::send_subscriptions(service_t _service, instance_t _instance,
+ client_t _client, bool _reliable) {
+ std::shared_ptr<runtime> its_runtime = runtime_.lock();
+ 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()) {
+ 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);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void service_discovery_impl::start_subscription_expiration_timer() {
+ subscription_expiration_timer_.expires_at(next_subscription_expiration_);
+ subscription_expiration_timer_.async_wait(
+ std::bind(&service_discovery_impl::expire_subscriptions,
+ shared_from_this(),
+ std::placeholders::_1));
+}
+
+void service_discovery_impl::stop_subscription_expiration_timer() {
+ subscription_expiration_timer_.cancel();
+}
+
+void service_discovery_impl::expire_subscriptions(const boost::system::error_code &_error) {
+ if (!_error) {
+ next_subscription_expiration_ = host_->expire_subscriptions();
+ start_subscription_expiration_timer();
+ }
+}
+
+bool service_discovery_impl::check_ipv4_address(
+ boost::asio::ip::address its_address) {
+ //Check unallowed ipv4 address
+ bool is_valid = true;
+ std::shared_ptr<configuration> its_configuration =
+ host_->get_configuration();
+
+ if(its_configuration) {
+ boost::asio::ip::address_v4::bytes_type its_unicast_address =
+ its_configuration.get()->get_unicast_address().to_v4().to_bytes();
+ boost::asio::ip::address_v4::bytes_type endpoint_address =
+ its_address.to_v4().to_bytes();
+
+ //same address as unicast address of DUT not allowed
+ if(its_unicast_address
+ == endpoint_address) {
+ VSOMEIP_ERROR << "Subscribers endpoint IP address is same as DUT's address! : "
+ << its_address.to_string();
+ is_valid = false;
+ }
+
+ // first 3 triples must match
+ its_unicast_address[3] = 0x00;
+ endpoint_address[3] = 0x00;
+
+ if(its_unicast_address
+ != endpoint_address) {
+#if 1
+ VSOMEIP_ERROR<< "First 3 triples of subscribers endpoint IP address are not valid!";
+#endif
+ is_valid = false;
+
+ } else {
+#if 0
+ VSOMEIP_DEBUG << "First 3 triples of subscribers endpoint IP address are valid!";
+#endif
+ }
+ }
+ return is_valid;
+}
+
} // namespace sd
} // namespace vsomeip
diff --git a/implementation/service_discovery/src/serviceentry_impl.cpp b/implementation/service_discovery/src/serviceentry_impl.cpp
index fe31703..9f82b83 100755
--- a/implementation/service_discovery/src/serviceentry_impl.cpp
+++ b/implementation/service_discovery/src/serviceentry_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/service_discovery/src/subscription.cpp b/implementation/service_discovery/src/subscription.cpp
index dcb2461..402304c 100644
--- a/implementation/service_discovery/src/subscription.cpp
+++ b/implementation/service_discovery/src/subscription.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -11,11 +11,16 @@ namespace sd {
subscription::subscription(major_version_t _major, ttl_t _ttl,
std::shared_ptr<endpoint> _reliable,
std::shared_ptr<endpoint> _unreliable,
- subscription_type_e _subscription_type)
+ subscription_type_e _subscription_type,
+ uint8_t _counter,
+ std::chrono::high_resolution_clock::time_point _expiration)
: major_(_major), ttl_(_ttl),
reliable_(_reliable), unreliable_(_unreliable),
is_acknowledged_(true),
- subscription_type_(_subscription_type) {
+ tcp_connection_established_(false),
+ subscription_type_(_subscription_type),
+ counter_(_counter),
+ expiration_(_expiration) {
}
subscription::~subscription() {
@@ -53,9 +58,28 @@ void subscription::set_acknowledged(bool _is_acknowledged) {
is_acknowledged_ = _is_acknowledged;
}
+bool subscription::is_tcp_connection_established() const {
+ return tcp_connection_established_;
+}
+void subscription::set_tcp_connection_established(bool _is_established) {
+ tcp_connection_established_ = _is_established;
+}
+
subscription_type_e subscription::get_subscription_type() const {
return subscription_type_;
}
+uint8_t subscription::get_counter() const {
+ return counter_;
+}
+
+std::chrono::high_resolution_clock::time_point subscription::get_expiration() const {
+ return expiration_;
+}
+
+void subscription::set_expiration(std::chrono::high_resolution_clock::time_point _expiration) {
+ expiration_ = _expiration;
+}
+
} // namespace sd
} // namespace vsomeip
diff --git a/implementation/tracing/include/defines.hpp b/implementation/tracing/include/defines.hpp
new file mode 100644
index 0000000..84ad5b6
--- /dev/null
+++ b/implementation/tracing/include/defines.hpp
@@ -0,0 +1,12 @@
+// 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 TRACING_INCLUDE_DEFINES_HPP_
+#define TRACING_INCLUDE_DEFINES_HPP_
+
+#define VSOMEIP_TC_DEFAULT_CHANNEL_NAME "Trace Connector Network Logging"
+#define VSOMEIP_TC_DEFAULT_CHANNEL_ID "TC"
+
+#endif /* TRACING_INCLUDE_DEFINES_HPP_ */
diff --git a/implementation/tracing/include/enumeration_types.hpp b/implementation/tracing/include/enumeration_types.hpp
new file mode 100644
index 0000000..18ac861
--- /dev/null
+++ b/implementation/tracing/include/enumeration_types.hpp
@@ -0,0 +1,21 @@
+// 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_TC_ENUMERATION_TYPES_HPP
+#define VSOMEIP_TC_ENUMERATION_TYPES_HPP
+
+namespace vsomeip {
+namespace tc {
+
+enum class filter_criteria_e : uint8_t {
+ SERVICES = 0x00,
+ METHODS = 0x01,
+ CLIENTS = 0x02,
+};
+
+} // namespace tc
+} // namespace vsomeip
+
+#endif // VSOMEIP_TC_ENUMERATION_TYPES_HPP
diff --git a/implementation/tracing/include/trace_connector.hpp b/implementation/tracing/include/trace_connector.hpp
new file mode 100644
index 0000000..95803c3
--- /dev/null
+++ b/implementation/tracing/include/trace_connector.hpp
@@ -0,0 +1,100 @@
+// 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_TC_TRACE_CONNECTOR_HPP
+#define VSOMEIP_TC_TRACE_CONNECTOR_HPP
+
+#include <vsomeip/primitive_types.hpp>
+#include <vsomeip/export.hpp>
+#include <boost/shared_ptr.hpp>
+#include <mutex>
+#include <vector>
+#include <map>
+
+#ifdef USE_DLT
+#include <dlt/dlt.h>
+#endif
+
+#include "enumeration_types.hpp"
+#include "trace_header.hpp"
+#include "../../endpoints/include/buffer.hpp"
+
+namespace vsomeip
+{
+namespace tc
+{
+
+class trace_connector {
+public:
+ typedef uint16_t filter_expression_t;
+ typedef std::vector<filter_expression_t> filter_expressions_t;
+ typedef std::map<filter_criteria_e, std::vector<filter_expression_t>> filter_rule_t;
+
+ typedef std::map<trace_channel_t, std::string> channels_t;
+ typedef std::map<trace_channel_t, filter_rule_t> filter_rules_t;
+
+#ifdef USE_DLT
+ typedef std::map<trace_channel_t, DltContext*> dlt_contexts_t;
+#endif
+
+ VSOMEIP_EXPORT static std::shared_ptr<trace_connector> get();
+
+ VSOMEIP_EXPORT trace_connector();
+ VSOMEIP_EXPORT virtual ~trace_connector();
+
+ VSOMEIP_EXPORT void init();
+ VSOMEIP_EXPORT void reset();
+
+ VSOMEIP_EXPORT void set_enabled(const bool _enabled);
+ VSOMEIP_EXPORT bool is_enabled();
+
+ VSOMEIP_EXPORT bool add_channel(const trace_channel_t &_id,const std::string &_name);
+ VSOMEIP_EXPORT bool remove_channel(const trace_channel_t &_id);
+
+ VSOMEIP_EXPORT bool add_filter_rule(const trace_channel_t &_channel_id,
+ const filter_rule_t _filter_rule);
+ VSOMEIP_EXPORT bool add_filter_expression(const trace_channel_t &_channel_id,
+ const filter_criteria_e _criteria,
+ const filter_expression_t _expression);
+ VSOMEIP_EXPORT bool change_filter_expressions(const trace_channel_t &_channel_id,
+ const filter_criteria_e _criteria,
+ const filter_expressions_t _expressions);
+ VSOMEIP_EXPORT bool remove_filter_rule(const trace_channel_t &_channel_id);
+
+ VSOMEIP_EXPORT void trace(const byte_t *_header, uint16_t _header_size,
+ const byte_t *_data, uint16_t _data_size);
+
+ VSOMEIP_EXPORT channels_t get_channels();
+ VSOMEIP_EXPORT filter_rules_t get_filter_rules();
+ VSOMEIP_EXPORT filter_rule_t get_filter_rule(const trace_channel_t &_channel_id);
+
+private:
+
+ bool apply_filter_rules(const byte_t *_data, const uint16_t _data_size,
+ std::vector<trace_channel_t> &_send_msg_over_channels);
+
+ bool filter_expressions_match(const filter_criteria_e _criteria,
+ const filter_expressions_t _expressions,
+ const byte_t *_data, const uint16_t _data_size);
+
+ bool is_enabled_;
+ bool is_initialized_;
+
+ channels_t channels_;
+ filter_rules_t filter_rules_;
+
+#ifdef USE_DLT
+ dlt_contexts_t dlt_contexts_;
+#endif
+
+ std::mutex channels_mutex_;
+ std::mutex filter_rules_mutex_;
+ std::mutex dlt_contexts_mutex;
+};
+
+} // namespace tc
+} // namespace vsomeip
+
+#endif // VSOMEIP_TC_TRACE_CONNECTOR_HPP
diff --git a/implementation/tracing/include/trace_header.hpp b/implementation/tracing/include/trace_header.hpp
new file mode 100644
index 0000000..9e86d84
--- /dev/null
+++ b/implementation/tracing/include/trace_header.hpp
@@ -0,0 +1,38 @@
+// 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_TC_TRACE_HEADER_HPP
+#define VSOMEIP_TC_TRACE_HEADER_HPP
+
+#include <memory>
+
+#include <vsomeip/primitive_types.hpp>
+
+#define VSOMEIP_TRACE_HEADER_SIZE 8
+
+namespace vsomeip {
+
+class endpoint;
+
+namespace tc {
+
+enum class protocol_e : uint8_t {
+ local = 0x0,
+ udp = 0x1,
+ tcp = 0x2,
+ unknown = 0xFF
+};
+
+struct trace_header {
+ bool prepare(const std::shared_ptr<endpoint> &_endpoint, bool _is_sending);
+ bool prepare(const endpoint* _endpoint, bool _is_sending);
+
+ byte_t data_[VSOMEIP_TRACE_HEADER_SIZE];
+};
+
+} // namespace tc
+} // namespace vsomeip
+
+#endif // VSOMEIP_TC_TRACE_HEADER_HPP
diff --git a/implementation/tracing/src/trace_connector.cpp b/implementation/tracing/src/trace_connector.cpp
new file mode 100644
index 0000000..dc01aa2
--- /dev/null
+++ b/implementation/tracing/src/trace_connector.cpp
@@ -0,0 +1,361 @@
+// 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 "../include/trace_connector.hpp"
+
+#include <vsomeip/constants.hpp>
+
+#include "../include/defines.hpp"
+#include "../../configuration/include/internal.hpp"
+
+namespace vsomeip {
+namespace tc {
+
+std::shared_ptr<trace_connector> trace_connector::get() {
+ static std::shared_ptr<trace_connector> instance = std::make_shared<trace_connector>();
+ return instance;
+}
+
+trace_connector::trace_connector() :
+ is_enabled_(false),
+ is_initialized_(false),
+ channels_(),
+ filter_rules_()
+ {
+ channels_.insert(std::make_pair(VSOMEIP_TC_DEFAULT_CHANNEL_ID, VSOMEIP_TC_DEFAULT_CHANNEL_NAME));
+}
+
+trace_connector::~trace_connector() {
+ reset();
+}
+
+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);
+ }
+#endif
+ is_initialized_ = true;
+}
+
+void trace_connector::reset() {
+ std::lock_guard<std::mutex> its_lock_channels(channels_mutex_);
+ std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_);
+ std::lock_guard<std::mutex> its_lock_dlt_contexts(dlt_contexts_mutex);
+
+#ifdef USE_DLT
+ // unregister channels/contexts
+ for(auto it = dlt_contexts_.begin(); it != dlt_contexts_.end(); ++it) {
+ DLT_UNREGISTER_CONTEXT(*it->second);
+ }
+#endif
+
+ // reset to default
+
+ channels_.clear();
+ channels_.insert(std::make_pair(VSOMEIP_TC_DEFAULT_CHANNEL_ID, VSOMEIP_TC_DEFAULT_CHANNEL_NAME));
+
+ filter_rules_.clear();
+}
+
+void trace_connector::set_enabled(const bool _enabled) {
+ is_enabled_ = _enabled;
+}
+
+bool trace_connector::is_enabled() {
+ return is_enabled_;
+}
+
+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);
+
+ bool channel_inserted = false;
+ bool dlt_context_registered = false;
+
+ // add channel
+ channel_inserted = channels_.insert(std::make_pair(_id, _name)).second;
+
+ // register context
+#ifdef USE_DLT
+ if(channel_inserted) {
+ DltContext *dlt_context = new DltContext();
+ dlt_context_registered = dlt_contexts_.insert(std::make_pair(_id, dlt_context)).second;
+ DLT_REGISTER_CONTEXT_LL_TS(*dlt_context, _id.c_str(), _name.c_str(), DLT_LOG_DEBUG, DLT_TRACE_STATUS_ON);
+ }
+#endif
+
+ return (channel_inserted && dlt_context_registered);
+}
+
+bool trace_connector::remove_channel(const trace_channel_t &_id) {
+
+ if(_id == VSOMEIP_TC_DEFAULT_CHANNEL_ID) {
+ // the default channel can not be removed
+ return false;
+ }
+
+ std::lock_guard<std::mutex> its_lock_channels(channels_mutex_);
+ std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_);
+ std::lock_guard<std::mutex> its_lock_dlt_contexts(dlt_contexts_mutex);
+
+ bool channel_removed = false;
+ bool dlt_context_unregistered = false;
+
+ // remove channel
+ channel_removed = (channels_.erase(_id) == 1);
+ if(channel_removed) {
+
+ // unregister context
+#ifdef USE_DLT
+ auto it = dlt_contexts_.find(_id);
+ if(it != dlt_contexts_.end()) {
+ DltContext *dlt_context = it->second;
+ DLT_UNREGISTER_CONTEXT(*dlt_context);
+ dlt_context_unregistered = true;
+ }
+#endif
+
+ // remove filter
+ filter_rules_.erase(_id);
+ }
+ return (channel_removed && dlt_context_unregistered);
+}
+
+bool trace_connector::add_filter_rule(const trace_channel_t &_channel_id,
+ const filter_rule_t _filter_rule) {
+ std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_);
+ std::lock_guard<std::mutex> its_lock_channels(channels_mutex_);
+
+ // find channel
+ auto it = channels_.find(_channel_id);
+ if(it != channels_.end()) {
+ // add filter rule
+ return filter_rules_.insert(std::make_pair(_channel_id, _filter_rule)).second;
+ }
+ return false;
+}
+
+bool trace_connector::add_filter_expression(const trace_channel_t &_channel_id,
+ const filter_criteria_e _criteria,
+ const filter_expression_t _expression) {
+ std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_);
+
+ // find filter rule
+ auto it_filter_rules = filter_rules_.find(_channel_id);
+ if(it_filter_rules != filter_rules_.end()) {
+ filter_rule_t its_filter_rule = it_filter_rules->second;
+
+ // find filter criteria
+ auto it_filter_rule = its_filter_rule.find(_criteria);
+ if(it_filter_rule != its_filter_rule.end()) {
+ // add expression
+ it_filter_rule->second.push_back(_expression);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool trace_connector::change_filter_expressions(const trace_channel_t &_channel_id,
+ const filter_criteria_e _criteria,
+ const filter_expressions_t _expressions) {
+ std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_);
+
+ // find filter rule
+ auto it_filter_rules = filter_rules_.find(_channel_id);
+ if(it_filter_rules != filter_rules_.end()) {
+ filter_rule_t its_filter_rule = it_filter_rules->second;
+
+ // find filter criteria
+ auto it_filter_rule = its_filter_rule.find(_criteria);
+ if(it_filter_rule != its_filter_rule.end()) {
+ // change expressions
+ it_filter_rule->second = _expressions;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool trace_connector::remove_filter_rule(const trace_channel_t &_channel_id) {
+ std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_);
+
+ auto it = filter_rules_.find(_channel_id);
+ if(it != filter_rules_.end()) {
+ return (filter_rules_.erase(_channel_id) == 1);
+ }
+ return false;
+}
+
+void trace_connector::trace(const byte_t *_header, uint16_t _header_size,
+ const byte_t *_data, uint16_t _data_size) {
+#ifdef USE_DLT
+ if(!is_enabled_)
+ return;
+
+ std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_);
+ std::lock_guard<std::mutex> its_lock_channels(channels_mutex_);
+ std::lock_guard<std::mutex> its_lock_dlt_contexts(dlt_contexts_mutex);
+
+ if (_data_size == 0)
+ return; // no data
+
+ // check if filter rules match
+ std::vector<trace_channel_t> its_channels;
+ if (apply_filter_rules(_data, _data_size, its_channels)) {
+ // send message over 'its_channels'
+ for(auto channel_id : its_channels) {
+ //find dlt context
+ auto it = dlt_contexts_.find(channel_id);
+ if (it != dlt_contexts_.end()) {
+ DltContext *dlt_context = it->second;
+ DLT_TRACE_NETWORK_SEGMENTED(*dlt_context,
+ DLT_NW_TRACE_IPC,
+ _header_size, (void * )_header,
+ _data_size, (void * )_data);
+ }
+ }
+ }
+#else
+ (void)_header;
+ (void)_header_size;
+ (void)_data;
+ (void)_data_size;
+#endif
+}
+
+trace_connector::channels_t trace_connector::get_channels() {
+ std::lock_guard<std::mutex>its_lock_channels(channels_mutex_);
+ return channels_;
+}
+
+trace_connector::filter_rules_t trace_connector::get_filter_rules() {
+ std::lock_guard<std::mutex> its_lock_filters(filter_rules_mutex_);
+ return filter_rules_;
+}
+
+trace_connector::filter_rule_t trace_connector::get_filter_rule(const trace_channel_t &_channel_id) {
+ std::lock_guard<std::mutex> its_lock_filters(filter_rules_mutex_);
+
+ // find filter
+ auto it = filter_rules_.find(_channel_id);
+ if (it != filter_rules_.end()) {
+ return filter_rules_[_channel_id];
+ } else {
+ return filter_rule_t();
+ }
+}
+
+bool trace_connector::apply_filter_rules(const byte_t *_data, uint16_t _data_size,
+ std::vector<trace_channel_t> &_send_msg_over_channels) {
+ _send_msg_over_channels.clear();
+ if (filter_rules_.size() == 0) {
+ // no filter rules -> send message over all channels to DLT
+ for(auto it=channels_.begin(); it !=channels_.end(); ++it)
+ _send_msg_over_channels.push_back(it->first);
+ return true;
+ }
+
+ // loop through filter rules
+ for(auto it_filter_rules = filter_rules_.begin(); it_filter_rules != filter_rules_.end(); ++it_filter_rules) {
+ trace_channel_t its_channel = it_filter_rules->first;
+ filter_rule_t its_filter_rule = it_filter_rules->second;
+
+ // apply filter rule
+ bool filter_rule_matches = false;
+ for(auto it_filter_rule = its_filter_rule.begin(); it_filter_rule != its_filter_rule.end(); ++it_filter_rule) {
+ filter_criteria_e its_criteria = it_filter_rule->first;
+ auto &its_filter_expressions = it_filter_rule->second;
+
+ // check if filter expressions of filter criteria match
+ filter_rule_matches = filter_expressions_match(its_criteria, its_filter_expressions, _data, _data_size);
+ if(!filter_rule_matches) {
+ // filter expressions of filter criteria does not match
+ break;
+ }
+ }
+
+ if(filter_rule_matches) {
+ //filter rule matches -> send message over 'its_channel' to DLT
+ _send_msg_over_channels.push_back(its_channel);
+ }
+ }
+ return (_send_msg_over_channels.size() != 0);
+}
+
+bool trace_connector::filter_expressions_match(
+ const filter_criteria_e _criteria, const filter_expressions_t _expressions,
+ const byte_t *_data, uint16_t _data_size) {
+
+ // ignore empty filter expressions
+ if (_expressions.size() == 0) {
+ return true;
+ }
+
+ // extract criteria from message
+ bool is_successful(false);
+ byte_t first = 0;
+ byte_t second = 0;
+ switch (_criteria) {
+ case filter_criteria_e::SERVICES:
+ if (VSOMEIP_SERVICE_POS_MAX < _data_size) {
+ first = _data[VSOMEIP_SERVICE_POS_MIN];
+ second = _data[VSOMEIP_SERVICE_POS_MAX];
+ is_successful = true;
+ }
+ break;
+ case filter_criteria_e::METHODS:
+ if (VSOMEIP_SERVICE_POS_MAX < _data_size) {
+ first = _data[VSOMEIP_METHOD_POS_MIN];
+ second = _data[VSOMEIP_METHOD_POS_MAX];
+ is_successful = true;
+ }
+ break;
+ case filter_criteria_e::CLIENTS:
+ if (VSOMEIP_CLIENT_POS_MAX < _data_size) {
+ first = _data[VSOMEIP_CLIENT_POS_MIN];
+ second = _data[VSOMEIP_CLIENT_POS_MAX];
+ is_successful = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ // if extraction is successful, filter
+ if (is_successful) {
+ for (auto it_expressions = _expressions.begin();
+ it_expressions != _expressions.end();
+ ++it_expressions) {
+ filter_expression_t its_filter_expression = *it_expressions;
+ uint16_t its_message_value = 0;
+
+
+ // check if one expression matches (byte order is sometimes wrong -> check both)
+ its_message_value = (uint16_t)((its_message_value << 8) + first);
+ its_message_value = (uint16_t)((its_message_value << 8) + second);
+ if(its_filter_expression == its_message_value) {
+ return true;
+ }
+
+ its_message_value = 0;
+ its_message_value = (uint16_t)((its_message_value << 8) + second);
+ its_message_value = (uint16_t)((its_message_value << 8) + first);
+ if(its_filter_expression == its_message_value) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+} // namespace tc
+} // namespace vsomeip
diff --git a/implementation/tracing/src/trace_header.cpp b/implementation/tracing/src/trace_header.cpp
new file mode 100644
index 0000000..6609412
--- /dev/null
+++ b/implementation/tracing/src/trace_header.cpp
@@ -0,0 +1,58 @@
+// 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/.
+
+#include <cstring>
+
+#include "../include/trace_header.hpp"
+#include "../../endpoints/include/endpoint.hpp"
+#include "../../utility/include/byteorder.hpp"
+
+namespace vsomeip {
+namespace tc {
+
+bool trace_header::prepare(const std::shared_ptr<endpoint> &_endpoint, bool _is_sending) {
+ return prepare(_endpoint.get(), _is_sending);
+}
+
+bool trace_header::prepare(const endpoint *_endpoint, bool _is_sending) {
+ if (!_endpoint)
+ return false;
+
+ boost::asio::ip::address its_address;
+ if (_endpoint->get_remote_address(its_address)) {
+ if (its_address.is_v6())
+ return false;
+
+ unsigned long its_address_as_long = its_address.to_v4().to_ulong();
+
+ data_[0] = VSOMEIP_LONG_BYTE0(its_address_as_long);
+ data_[1] = VSOMEIP_LONG_BYTE1(its_address_as_long);
+ data_[2] = VSOMEIP_LONG_BYTE2(its_address_as_long);
+ data_[3] = VSOMEIP_LONG_BYTE3(its_address_as_long);
+
+ unsigned short its_port = _endpoint->get_remote_port();
+ data_[4] = VSOMEIP_WORD_BYTE0(its_port);
+ data_[5] = VSOMEIP_WORD_BYTE1(its_port);
+
+ if (_endpoint->is_local()) {
+ data_[6] = static_cast<byte_t>(protocol_e::local);
+ } else {
+ if (_endpoint->is_reliable()) {
+ data_[6] = static_cast<byte_t>(protocol_e::tcp);
+ } else {
+ data_[6] = static_cast<byte_t>(protocol_e::udp);
+ }
+ }
+
+ data_[7] = static_cast<byte_t>(_is_sending);
+
+ } else {
+ std::memset(data_, 0, VSOMEIP_TRACE_HEADER_SIZE);
+ }
+ return true;
+}
+
+} // namespace tc
+} // namespace vsomeip
diff --git a/implementation/utility/include/byteorder.hpp b/implementation/utility/include/byteorder.hpp
index baea175..2774618 100644
--- a/implementation/utility/include/byteorder.hpp
+++ b/implementation/utility/include/byteorder.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/implementation/utility/include/utility.hpp b/implementation/utility/include/utility.hpp
index 1b3f7eb..9f3a7e3 100644
--- a/implementation/utility/include/utility.hpp
+++ b/implementation/utility/include/utility.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -73,13 +73,17 @@ public:
static bool is_folder(const std::string &_path);
static struct configuration_data_t *the_configuration_data__;
- static bool auto_configuration_init();
+ static bool auto_configuration_init(const std::string &_name);
static void auto_configuration_exit();
static bool is_routing_manager_host__;
static bool is_routing_manager_host();
- static client_t get_client_id();
+ static bool is_used_client_id(client_t _client);
+ static client_t request_client_id(client_t _client);
+ static void release_client_id(client_t _client);
+
+ static uint16_t its_configuration_refs__;
};
} // namespace vsomeip
diff --git a/implementation/utility/src/utility.cpp b/implementation/utility/src/utility.cpp
index e2cbde4..c711320 100644
--- a/implementation/utility/src/utility.cpp
+++ b/implementation/utility/src/utility.cpp
@@ -1,29 +1,36 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
#ifdef WIN32
-#include <Windows.h>
-#include <iostream>
+ #include <iostream>
#else
-#include <dlfcn.h>
-#include <sys/mman.h>
+ #include <dlfcn.h>
+ #include <sys/mman.h>
#endif
#include <sys/stat.h>
#ifndef WIN32
-#include <fcntl.h>
+ #include <fcntl.h>
#endif
+#include <vsomeip/constants.hpp>
#include <vsomeip/defines.hpp>
#include "../include/byteorder.hpp"
#include "../include/utility.hpp"
+#include "../../configuration/include/configuration.hpp"
#include "../../configuration/include/internal.hpp"
#include "../../logging/include/logger.hpp"
+#ifdef WIN32
+ #ifndef _WINSOCKAPI_
+ #include <Windows.h>
+ #endif
+#endif
+
namespace vsomeip {
uint32_t utility::get_message_size(const byte_t *_data, uint32_t _size) {
@@ -109,36 +116,153 @@ bool utility::is_folder(const std::string &_path) {
configuration_data_t *utility::the_configuration_data__(nullptr);
bool utility::is_routing_manager_host__(false);
+uint16_t utility::its_configuration_refs__(0);
-bool utility::auto_configuration_init() {
-#ifndef WIN32
- int its_descriptor = shm_open(VSOMEIP_SHM_NAME, O_RDWR|O_CREAT|O_EXCL, 0660);
+#ifdef WIN32
+HANDLE its_descriptor;
+#endif
+
+bool utility::auto_configuration_init(const std::string &_name) {
+ 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_);
+ }
+ } else {
+ // TODO: Error
+ }
+#else
+ const mode_t previous_mask(::umask(static_cast<mode_t>(its_config->get_umask())));
+ int its_descriptor = shm_open(VSOMEIP_SHM_NAME, O_RDWR | O_CREAT | O_EXCL,
+ static_cast<mode_t>(its_config->get_permissions_shm()));
+ ::umask(previous_mask);
if (its_descriptor > -1) {
- if (0 == ftruncate(its_descriptor, sizeof(configuration_data_t))) {
+ if (-1 == ftruncate(its_descriptor, sizeof(configuration_data_t))) {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: "
+ "ftruncate failed: " << std::strerror(errno);
+ } else {
void *its_segment = mmap(0, sizeof(configuration_data_t),
PROT_READ | PROT_WRITE, MAP_SHARED,
its_descriptor, 0);
- the_configuration_data__
- = reinterpret_cast<configuration_data_t *>(its_segment);
- if (the_configuration_data__ != nullptr) {
- std::lock_guard<std::mutex> its_lock(the_configuration_data__->mutex_);
- the_configuration_data__->ref_ = 0;
- the_configuration_data__->next_client_id_ = (VSOMEIP_DIAGNOSIS_ADDRESS << 8);
- is_routing_manager_host__ = true;
+ if(MAP_FAILED == its_segment) {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: "
+ "mmap failed: " << std::strerror(errno);
+ } 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;
+ ret = pthread_mutexattr_init(&attr);
+ if (0 == ret) {
+ ret = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+ if (0 != ret) {
+ VSOMEIP_ERROR << "pthread_mutexattr_setpshared() failed " << ret;
+ }
+ } else {
+ VSOMEIP_ERROR << "pthread_mutexattr_init() failed " << ret;
+ }
+ ret = pthread_mutex_init(&the_configuration_data__->mutex_, (0==ret)?&attr:NULL);
+ if (0 != ret) {
+ VSOMEIP_ERROR << "pthread_mutex_init() failed " << ret;
+ }
+ ret = pthread_mutex_lock(&the_configuration_data__->mutex_);
+ if (0 != ret) {
+ VSOMEIP_ERROR << "pthread_mutex_lock() failed " << ret;
+ }
+
+ 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__++;
+
+ ret = pthread_mutex_unlock(&the_configuration_data__->mutex_);
+ if (0 != ret) {
+ VSOMEIP_ERROR << "pthread_mutex_unlock() failed " << ret;
+ }
+ }
}
- } else {
- // TODO: an error message
}
} else {
- its_descriptor = shm_open(VSOMEIP_SHM_NAME, O_RDWR, 0660);
- if (its_descriptor > -1) {
+ 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()));
+ ::umask(previous_mask);
+ if (-1 == its_descriptor) {
+ 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);
- the_configuration_data__
- = reinterpret_cast<configuration_data_t *>(its_segment);
- } else {
- // TODO: an error message
+ if(MAP_FAILED == its_segment) {
+ VSOMEIP_ERROR << "utility::auto_configuration_init: "
+ "mmap failed: " << std::strerror(errno);
+ } 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);
+ }
+#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
+ }
}
}
#endif
@@ -146,25 +270,110 @@ bool utility::auto_configuration_init() {
}
void utility::auto_configuration_exit() {
-#ifndef WIN32
if (the_configuration_data__) {
- munmap(the_configuration_data__, sizeof(configuration_data_t));
+#ifdef WIN32
+ WaitForSingleObject(the_configuration_data__->mutex_, INFINITE);
+ its_configuration_refs__--;
+ ReleaseMutex(the_configuration_data__->mutex_);
+
+ if (its_configuration_refs__ == 0) {
+ UnmapViewOfFile(the_configuration_data__);
+ }
+
+ if (is_routing_manager_host__) {
+ CloseHandle(its_descriptor);
+ }
+#else
+ pthread_mutex_lock(&the_configuration_data__->mutex_);
+ its_configuration_refs__--;
+ pthread_mutex_unlock(&the_configuration_data__->mutex_);
+
+ if (its_configuration_refs__ == 0) {
+ if (-1 == ::munmap(the_configuration_data__, sizeof(configuration_data_t))) {
+ VSOMEIP_ERROR << "utility::auto_configuration_exit: "
+ "munmap failed: " << std::strerror(errno);
+ } else {
+ VSOMEIP_DEBUG << "utility::auto_configuration_exit: "
+ "munmap succeeded.";
+ the_configuration_data__ = nullptr;
+ }
+ }
if (is_routing_manager_host__) {
shm_unlink(VSOMEIP_SHM_NAME);
}
- }
#endif
+ }
}
-client_t utility::get_client_id() {
+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)
+ return true;
+ }
+ return false;
+}
+
+client_t utility::request_client_id(client_t _client) {
if (the_configuration_data__ != nullptr) {
- std::lock_guard<std::mutex> its_lock(the_configuration_data__->mutex_);
- the_configuration_data__->next_client_id_++;
- return the_configuration_data__->next_client_id_;
+#ifdef WIN32
+ WaitForSingleObject(the_configuration_data__->mutex_, INFINITE);
+#else
+ pthread_mutex_lock(&the_configuration_data__->mutex_);
+#endif
+ if (the_configuration_data__->max_used_client_ids_index_
+ == VSOMEIP_MAX_CLIENTS) {
+ return ILLEGAL_CLIENT;
+ }
+
+ if (_client == ILLEGAL_CLIENT || is_used_client_id(_client)) {
+ _client = the_configuration_data__->client_base_;
+ }
+
+ while (is_used_client_id(_client)) _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_);
+#else
+ pthread_mutex_unlock(&the_configuration_data__->mutex_);
+#endif
+ return _client;
}
return VSOMEIP_DIAGNOSIS_ADDRESS;
}
+void utility::release_client_id(client_t _client) {
+ if (the_configuration_data__ != nullptr) {
+#ifdef WIN32
+ WaitForSingleObject(the_configuration_data__->mutex_, INFINITE);
+#else
+ pthread_mutex_lock(&the_configuration_data__->mutex_);
+#endif
+ int i = 0;
+ while (the_configuration_data__->used_client_ids_[i] != _client &&
+ i < the_configuration_data__->max_used_client_ids_index_) {
+ i++;
+ }
+
+ 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]
+ = the_configuration_data__->used_client_ids_[i+1];
+ }
+ }
+#ifdef WIN32
+ ReleaseMutex(the_configuration_data__->mutex_);
+#else
+ pthread_mutex_unlock(&the_configuration_data__->mutex_);
+#endif
+ }
+}
+
bool utility::is_routing_manager_host() {
return is_routing_manager_host__;
}
diff --git a/initial.txt b/initial.txt
deleted file mode 100644
index 7411280..0000000
--- a/initial.txt
+++ /dev/null
@@ -1 +0,0 @@
-Initial commit from maintainer to the new repository.
diff --git a/interface/vsomeip/application.hpp b/interface/vsomeip/application.hpp
index dc4784d..67b35b5 100644
--- a/interface/vsomeip/application.hpp
+++ b/interface/vsomeip/application.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -40,8 +40,9 @@ public:
major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor =
DEFAULT_MINOR) = 0;
- virtual void stop_offer_service(service_t _service,
- instance_t _instance) = 0;
+ virtual void stop_offer_service(service_t _service, instance_t _instance,
+ major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor =
+ DEFAULT_MINOR) = 0;
virtual void offer_event(service_t _service,
instance_t _instance, event_t _event,
@@ -65,12 +66,14 @@ public:
virtual void subscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, major_version_t _major = DEFAULT_MAJOR,
- subscription_type_e _subscription_type = subscription_type_e::SU_RELIABLE_AND_UNRELIABLE) = 0;
+ subscription_type_e _subscription_type = subscription_type_e::SU_RELIABLE_AND_UNRELIABLE,
+ event_t _event = ANY_EVENT) = 0;
virtual void unsubscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup) = 0;
- virtual bool is_available(service_t _service, instance_t _instance) const = 0;
+ virtual bool is_available(service_t _service, instance_t _instance,
+ major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR) const = 0;
// Send a message
virtual void send(std::shared_ptr<message> _message, bool _flush = true) = 0;
@@ -96,9 +99,11 @@ public:
// [Un]Register handler for availability reporting
virtual void register_availability_handler(service_t _service,
- instance_t _instance, availability_handler_t _handler) = 0;
+ instance_t _instance, availability_handler_t _handler,
+ major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR) = 0;
virtual void unregister_availability_handler(service_t _service,
- instance_t _instance) = 0;
+ instance_t _instance,
+ major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR) = 0;
// [Un]Register handler for subscriptions
virtual void register_subscription_handler(service_t _service,
@@ -106,6 +111,18 @@ public:
subscription_handler_t _handler) = 0;
virtual void unregister_subscription_handler(service_t _service,
instance_t _instance, eventgroup_t _eventgroup) = 0;
+
+ // [Un]Register handler for subscription errors
+ virtual void register_subscription_error_handler(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup,
+ error_handler_t _handler) = 0;
+ virtual void unregister_subscription_error_handler(service_t _service,
+ instance_t _instance, eventgroup_t _eventgroup) = 0;
+
+ virtual void clear_all_handler() = 0;
+
+ // Routing/SD hosted by this application!?
+ virtual bool is_routing() const = 0;
};
} // namespace vsomeip
diff --git a/interface/vsomeip/constants.hpp b/interface/vsomeip/constants.hpp
index 8062b12..da184b8 100644
--- a/interface/vsomeip/constants.hpp
+++ b/interface/vsomeip/constants.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -14,21 +14,25 @@
namespace vsomeip {
const major_version_t DEFAULT_MAJOR = 0x00;
-const minor_version_t DEFAULT_MINOR = 0x000000;
+const minor_version_t DEFAULT_MINOR = 0x00000000;
const ttl_t DEFAULT_TTL = 0xFFFFFF; // "until next reboot"
const std::string DEFAULT_MULTICAST = "224.0.0.0";
const uint16_t DEFAULT_PORT = 30500;
const uint16_t ILLEGAL_PORT = 0xFFFF;
+const uint16_t NO_TRACE_FILTER_EXPRESSION = 0x0000;
+
const service_t ANY_SERVICE = 0xFFFF;
const instance_t ANY_INSTANCE = 0xFFFF;
const method_t ANY_METHOD = 0xFFFF;
const major_version_t ANY_MAJOR = 0xFF;
-const minor_version_t ANY_MINOR = 0xFFFFFF;
+const minor_version_t ANY_MINOR = 0xFFFFFFFF;
const eventgroup_t DEFAULT_EVENTGROUP = 0x0001;
+const client_t ILLEGAL_CLIENT = 0x0000;
+
const byte_t MAGIC_COOKIE_CLIENT_MESSAGE = 0x00;
const byte_t MAGIC_COOKIE_SERVICE_MESSAGE = 0x80;
const length_t MAGIC_COOKIE_SIZE = 0x00000008;
@@ -47,6 +51,8 @@ const byte_t CLIENT_COOKIE[] = { 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
const byte_t SERVICE_COOKIE[] = { 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
0x08, 0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x01, 0x02, 0x00 };
+const event_t ANY_EVENT = 0xFFFF;
+
} // namespace vsomeip
#endif // VSOMEIP_CONSTANTS_HPP
diff --git a/interface/vsomeip/defines.hpp b/interface/vsomeip/defines.hpp
index d384d50..2323c19 100644
--- a/interface/vsomeip/defines.hpp
+++ b/interface/vsomeip/defines.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -10,7 +10,7 @@
#define VSOMEIP_MAX_LOCAL_MESSAGE_SIZE 32768
#define VSOMEIP_MAX_TCP_MESSAGE_SIZE 4095
-#define VSOMEIP_MAX_UDP_MESSAGE_SIZE 1446
+#define VSOMEIP_MAX_UDP_MESSAGE_SIZE 1416
#define VSOMEIP_PACKET_SIZE VSOMEIP_MAX_UDP_MESSAGE_SIZE
diff --git a/interface/vsomeip/enumeration_types.hpp b/interface/vsomeip/enumeration_types.hpp
index a71e677..b9b0a50 100644
--- a/interface/vsomeip/enumeration_types.hpp
+++ b/interface/vsomeip/enumeration_types.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/interface/vsomeip/error.hpp b/interface/vsomeip/error.hpp
index b655174..da74482 100644
--- a/interface/vsomeip/error.hpp
+++ b/interface/vsomeip/error.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/interface/vsomeip/export.hpp b/interface/vsomeip/export.hpp
index 7e8ddad..ab4af7f 100644
--- a/interface/vsomeip/export.hpp
+++ b/interface/vsomeip/export.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/interface/vsomeip/handler.hpp b/interface/vsomeip/handler.hpp
index a703569..1363914 100644
--- a/interface/vsomeip/handler.hpp
+++ b/interface/vsomeip/handler.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -19,6 +19,7 @@ typedef std::function< void (state_type_e) > state_handler_t;
typedef std::function< void (const std::shared_ptr< message > &) > message_handler_t;
typedef std::function< void (service_t, instance_t, bool) > availability_handler_t;
typedef std::function< bool (client_t, bool) > subscription_handler_t;
+typedef std::function< void (const uint16_t) > error_handler_t;
} // namespace vsomeip
diff --git a/interface/vsomeip/internal/deserializable.hpp b/interface/vsomeip/internal/deserializable.hpp
index fb11dfd..103c8cf 100644
--- a/interface/vsomeip/internal/deserializable.hpp
+++ b/interface/vsomeip/internal/deserializable.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/interface/vsomeip/internal/serializable.hpp b/interface/vsomeip/internal/serializable.hpp
index 4c22bf7..7f08944 100644
--- a/interface/vsomeip/internal/serializable.hpp
+++ b/interface/vsomeip/internal/serializable.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/interface/vsomeip/message.hpp b/interface/vsomeip/message.hpp
index 6b91712..a1c8d2c 100644
--- a/interface/vsomeip/message.hpp
+++ b/interface/vsomeip/message.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/interface/vsomeip/message_base.hpp b/interface/vsomeip/message_base.hpp
index 225ec19..d077be0 100644
--- a/interface/vsomeip/message_base.hpp
+++ b/interface/vsomeip/message_base.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -57,6 +57,8 @@ public:
// No part of the SOME/IP protocol header
VSOMEIP_EXPORT virtual bool is_reliable() const = 0;
VSOMEIP_EXPORT virtual void set_reliable(bool _is_reliable) = 0;
+ VSOMEIP_EXPORT virtual bool is_initial() const = 0;
+ VSOMEIP_EXPORT virtual void set_initial(bool _is_initial) = 0;
};
} // namespace vsomeip
diff --git a/interface/vsomeip/payload.hpp b/interface/vsomeip/payload.hpp
index 693d5ba..0186d30 100644
--- a/interface/vsomeip/payload.hpp
+++ b/interface/vsomeip/payload.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/interface/vsomeip/primitive_types.hpp b/interface/vsomeip/primitive_types.hpp
index 3cc2b9a..b75203e 100644
--- a/interface/vsomeip/primitive_types.hpp
+++ b/interface/vsomeip/primitive_types.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -39,6 +39,8 @@ typedef uint8_t byte_t;
typedef std::array<byte_t, 4> ipv4_address_t;
typedef std::array<byte_t, 16> ipv6_address_t;
+typedef std::string trace_channel_t;
+
} // namespace vsomeip
#endif // VSOMEIP_PRIMITIVE_TYPES_HPP
diff --git a/interface/vsomeip/runtime.hpp b/interface/vsomeip/runtime.hpp
index fb9c2ab..fbdbded 100644
--- a/interface/vsomeip/runtime.hpp
+++ b/interface/vsomeip/runtime.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -21,6 +21,10 @@ class payload;
class VSOMEIP_EXPORT runtime {
public:
+
+ static std::string get_property(const std::string &_name);
+ static void set_property(const std::string &_name, const std::string &_value);
+
static std::shared_ptr<runtime> get();
virtual ~runtime() {
diff --git a/interface/vsomeip/vsomeip.hpp b/interface/vsomeip/vsomeip.hpp
index 3ee5819..e0aecd4 100644
--- a/interface/vsomeip/vsomeip.hpp
+++ b/interface/vsomeip/vsomeip.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 43254a5..e56ab54 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
@@ -111,12 +111,24 @@ if(NOT ${TESTS_BAT})
${TEST_APPLICATION}
)
+ set(TEST_APPLICATION_CONFIGURATION_FILE_DAEMON ${TEST_APPLICATION}_daemon.json)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/application_tests/${TEST_APPLICATION_CONFIGURATION_FILE_DAEMON}
+ ${PROJECT_BINARY_DIR}/test/${TEST_APPLICATION_CONFIGURATION_FILE_DAEMON}
+ ${TEST_APPLICATION}
+ )
+
set(TEST_APPLICATION_NO_DISPATCH_CONFIGURATION_FILE ${TEST_APPLICATION}_no_dispatch_threads.json)
copy_to_builddir(${PROJECT_SOURCE_DIR}/test/application_tests/${TEST_APPLICATION_NO_DISPATCH_CONFIGURATION_FILE}
${PROJECT_BINARY_DIR}/test/${TEST_APPLICATION_NO_DISPATCH_CONFIGURATION_FILE}
${TEST_APPLICATION}
)
+ set(TEST_APPLICATION_NO_DISPATCH_CONFIGURATION_FILE_DAEMON ${TEST_APPLICATION}_no_dispatch_threads_daemon.json)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/application_tests/${TEST_APPLICATION_NO_DISPATCH_CONFIGURATION_FILE_DAEMON}
+ ${PROJECT_BINARY_DIR}/test/${TEST_APPLICATION_NO_DISPATCH_CONFIGURATION_FILE_DAEMON}
+ ${TEST_APPLICATION}
+ )
+
set(TEST_APPLICATION_STARTER ${TEST_APPLICATION}_starter.sh)
copy_to_builddir(${PROJECT_SOURCE_DIR}/test/application_tests/${TEST_APPLICATION_STARTER}
${PROJECT_BINARY_DIR}/test/${TEST_APPLICATION_STARTER}
@@ -774,6 +786,30 @@ if(NOT ${TESTS_BAT})
${TEST_CLIENT_ID_SERVICE}
)
+ set(TEST_CLIENT_ID_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE
+ ${TEST_CLIENT_ID_NAME}_diff_client_ids_partial_same_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/client_id_tests/conf/${TEST_CLIENT_ID_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/client_id_tests/${TEST_CLIENT_ID_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/client_id_tests/${TEST_CLIENT_ID_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_CLIENT_ID_SERVICE}
+ )
+
+ set(TEST_CLIENT_ID_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_CLIENT_ID_NAME}_diff_client_ids_partial_same_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/client_id_tests/conf/${TEST_CLIENT_ID_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/client_id_tests/${TEST_CLIENT_ID_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/client_id_tests/${TEST_CLIENT_ID_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${TEST_CLIENT_ID_SERVICE}
+ )
+
set(TEST_CLIENT_ID_SAME_IDS_SAME_PORTS_MASTER_CONFIG_FILE
${TEST_CLIENT_ID_NAME}_same_client_ids_same_ports_master.json)
configure_file(
@@ -836,6 +872,296 @@ if(NOT ${TESTS_BAT})
endif()
##############################################################################
+# subscribe notify tests
+##############################################################################
+if(NOT ${TESTS_BAT})
+ set(TEST_SUBSCRIBE_NOTIFY_NAME subscribe_notify_test)
+ set(TEST_SUBSCRIBE_NOTIFY_SERVICE ${TEST_SUBSCRIBE_NOTIFY_NAME}_service)
+ add_executable(${TEST_SUBSCRIBE_NOTIFY_SERVICE} subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_NAME}_service.cpp)
+ target_link_libraries(${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ # Copy config files for test into $BUILDDIR/test
+ set(TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_partial_same_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_PARTIAL_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_partial_same_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_PARTIAL_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_SAME_IDS_SAME_PORTS_MASTER_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_same_client_ids_same_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_SAME_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_SAME_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_SAME_IDS_SAME_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_same_client_ids_same_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_SAME_PORTS_SLAVE_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_SAME_IDS_DIFF_PORTS_MASTER_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_same_client_ids_diff_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_SAME_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_NAME}_same_client_ids_diff_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/conf/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_SAME_IDS_DIFF_PORTS_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}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+ set(TEST_SUBSCRIBE_NOTIFY_SLAVE_STARTER ${TEST_SUBSCRIBE_NOTIFY_NAME}_slave_starter.sh)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/subscribe_notify_tests/${TEST_SUBSCRIBE_NOTIFY_SLAVE_STARTER}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_SLAVE_STARTER}
+ ${TEST_SUBSCRIBE_NOTIFY_SERVICE}
+ )
+endif()
+
+##############################################################################
+# subscribe notify one tests
+##############################################################################
+if(NOT ${TESTS_BAT})
+ set(TEST_SUBSCRIBE_NOTIFY_ONE_NAME subscribe_notify_one_test)
+ set(TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE ${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_service)
+ add_executable(${TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE} subscribe_notify_one_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_service.cpp)
+ target_link_libraries(${TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE}
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ # Copy config files for test into $BUILDDIR/test
+ set(TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_diff_client_ids_diff_ports_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_one_tests/conf/${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_one_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_one_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE}
+ )
+
+ set(TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE
+ ${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_diff_client_ids_diff_ports_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_one_tests/conf/${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_one_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/subscribe_notify_one_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_SLAVE_CONFIG_FILE}
+ ${TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE}
+ )
+
+ # copy starter scripts into builddir
+ set(TEST_SUBSCRIBE_NOTIFY_ONE_MASTER_STARTER ${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_master_starter.sh)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/subscribe_notify_one_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_MASTER_STARTER}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_MASTER_STARTER}
+ ${TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE}
+ )
+ set(TEST_SUBSCRIBE_NOTIFY_ONE_SLAVE_STARTER ${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_slave_starter.sh)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/subscribe_notify_one_tests/${TEST_SUBSCRIBE_NOTIFY_ONE_SLAVE_STARTER}
+ ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_SLAVE_STARTER}
+ ${TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE}
+ )
+endif()
+
+##############################################################################
+# cpu-load-test
+##############################################################################
+
+if(NOT ${TESTS_BAT})
+ set(TEST_CPU_LOAD_NAME cpu_load_test)
+
+ set(TEST_CPU_LOAD_SERVICE cpu_load_test_service)
+ add_executable(${TEST_CPU_LOAD_SERVICE}
+ cpu_load_tests/${TEST_CPU_LOAD_SERVICE}.cpp
+ cpu_load_tests/cpu_load_measurer.cpp
+ )
+ target_link_libraries(${TEST_CPU_LOAD_SERVICE}
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ # Copy config files for test into $BUILDDIR/test
+ set(TEST_CPU_LOAD_SERVICE_MASTER_CONFIG_FILE ${TEST_CPU_LOAD_NAME}_service_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/conf/${TEST_CPU_LOAD_SERVICE_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/${TEST_CPU_LOAD_SERVICE_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/${TEST_CPU_LOAD_SERVICE_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_CPU_LOAD_SERVICE_MASTER_CONFIG_FILE}
+ ${TEST_CPU_LOAD_SERVICE}
+ )
+ set(TEST_CPU_LOAD_SERVICE_SLAVE_CONFIG_FILE ${TEST_CPU_LOAD_NAME}_service_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/conf/${TEST_CPU_LOAD_SERVICE_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/${TEST_CPU_LOAD_SERVICE_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/${TEST_CPU_LOAD_SERVICE_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_CPU_LOAD_SERVICE_SLAVE_CONFIG_FILE}
+ ${TEST_CPU_LOAD_SERVICE}
+ )
+
+ ##############################################################################
+ set(TEST_CPU_LOAD_CLIENT cpu_load_test_client)
+ add_executable(${TEST_CPU_LOAD_CLIENT}
+ cpu_load_tests/${TEST_CPU_LOAD_CLIENT}.cpp
+ cpu_load_tests/cpu_load_measurer.cpp
+ )
+ target_link_libraries(${TEST_CPU_LOAD_CLIENT}
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ set(TEST_CPU_LOAD_CLIENT_MASTER_CONFIG_FILE ${TEST_CPU_LOAD_NAME}_client_master.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/conf/${TEST_CPU_LOAD_CLIENT_MASTER_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/${TEST_CPU_LOAD_CLIENT_MASTER_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/${TEST_CPU_LOAD_CLIENT_MASTER_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_CPU_LOAD_CLIENT_MASTER_CONFIG_FILE}
+ ${TEST_CPU_LOAD_CLIENT}
+ )
+ set(TEST_CPU_LOAD_CLIENT_SLAVE_CONFIG_FILE ${TEST_CPU_LOAD_NAME}_client_slave.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/conf/${TEST_CPU_LOAD_CLIENT_SLAVE_CONFIG_FILE}.in
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/${TEST_CPU_LOAD_CLIENT_SLAVE_CONFIG_FILE}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/cpu_load_tests/${TEST_CPU_LOAD_CLIENT_SLAVE_CONFIG_FILE}
+ ${PROJECT_BINARY_DIR}/test/${TEST_CPU_LOAD_CLIENT_SLAVE_CONFIG_FILE}
+ ${TEST_CPU_LOAD_CLIENT}
+ )
+
+ ##############################################################################
+ # copy starter scripts into builddir
+ set(TEST_CPU_LOAD_MASTER_STARTER ${TEST_CPU_LOAD_NAME}_master_starter.sh)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/cpu_load_tests/${TEST_CPU_LOAD_MASTER_STARTER}
+ ${PROJECT_BINARY_DIR}/test/${TEST_CPU_LOAD_MASTER_STARTER}
+ ${TEST_CPU_LOAD_SERVICE}
+ )
+ set(TEST_CPU_LOAD_SLAVE_STARTER ${TEST_CPU_LOAD_NAME}_slave_starter.sh)
+ copy_to_builddir(${PROJECT_SOURCE_DIR}/test/cpu_load_tests/${TEST_CPU_LOAD_SLAVE_STARTER}
+ ${PROJECT_BINARY_DIR}/test/${TEST_CPU_LOAD_SLAVE_STARTER}
+ ${TEST_CPU_LOAD_SERVICE}
+ )
+endif()
+
+
+##############################################################################
# Add for every test a dependency to gtest
##############################################################################
@@ -855,6 +1181,10 @@ if(NOT ${TESTS_BAT})
add_dependencies(${TEST_BIG_PAYLOAD_SERVICE} gtest)
add_dependencies(${TEST_BIG_PAYLOAD_CLIENT} gtest)
add_dependencies(${TEST_CLIENT_ID_SERVICE} gtest)
+ add_dependencies(${TEST_SUBSCRIBE_NOTIFY_SERVICE} gtest)
+ add_dependencies(${TEST_SUBSCRIBE_NOTIFY_ONE_SERVICE} gtest)
+ add_dependencies(${TEST_CPU_LOAD_SERVICE} gtest)
+ add_dependencies(${TEST_CPU_LOAD_CLIENT} gtest)
else()
add_dependencies(${TEST_LOCAL_ROUTING_SERVICE} gtest)
add_dependencies(${TEST_LOCAL_ROUTING_CLIENT} gtest)
@@ -880,6 +1210,10 @@ if(NOT ${TESTS_BAT})
add_dependencies(build_tests ${TEST_BIG_PAYLOAD_SERVICE})
add_dependencies(build_tests ${TEST_BIG_PAYLOAD_CLIENT})
add_dependencies(build_tests ${TEST_CLIENT_ID_SERVICE})
+ add_dependencies(build_tests ${TEST_SUBSCRIBE_NOTIFY_SERVICE})
+ 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})
else()
add_dependencies(build_tests ${TEST_LOCAL_ROUTING_SERVICE})
add_dependencies(build_tests ${TEST_LOCAL_ROUTING_CLIENT})
@@ -903,7 +1237,7 @@ if(NOT ${TESTS_BAT})
add_test(NAME ${TEST_APPLICATION}
COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_APPLICATION_STARTER}
)
- set_tests_properties(${TEST_APPLICATION} PROPERTIES TIMEOUT 20)
+ set_tests_properties(${TEST_APPLICATION} PROPERTIES TIMEOUT 40)
# magic cookies test
add_test(NAME ${TEST_MAGIC_COOKIES_NAME}
@@ -957,9 +1291,86 @@ if(NOT ${TESTS_BAT})
add_test(NAME ${TEST_CLIENT_ID_NAME}_diff_client_ids_diff_ports
COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_MASTER_STARTER} ${TEST_CLIENT_ID_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
set_tests_properties(${TEST_CLIENT_ID_NAME}_diff_client_ids_diff_ports PROPERTIES TIMEOUT 60)
+
add_test(NAME ${TEST_CLIENT_ID_NAME}_diff_client_ids_same_ports
COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_CLIENT_ID_MASTER_STARTER} ${TEST_CLIENT_ID_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE})
set_tests_properties(${TEST_CLIENT_ID_NAME}_diff_client_ids_same_ports PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_CLIENT_ID_NAME}_diff_client_ids_partial_same_ports
+ 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
+ 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)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_tcp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} TCP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_tcp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_both_tcp_and_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} TCP_AND_UDP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_both_tcp_and_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_prefer_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} PREFER_UDP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_prefer_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_prefer_tcp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} PREFER_TCP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_diff_ports_prefer_tcp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} UDP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_tcp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} TCP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_tcp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_both_tcp_and_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} TCP_AND_UDP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_both_tcp_and_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_prefer_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} PREFER_UDP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_prefer_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_prefer_tcp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_MASTER_STARTER} PREFER_TCP ${TEST_SUBSCRIBE_NOTIFY_DIFF_IDS_SAME_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_same_ports_prefer_tcp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_NAME}_diff_client_ids_partial_same_ports_both_tcp_and_udp
+ 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_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)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_diff_client_ids_diff_ports_tcp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_MASTER_STARTER} TCP ${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_diff_client_ids_diff_ports_tcp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_diff_client_ids_diff_ports_both_tcp_and_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_MASTER_STARTER} TCP_AND_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_both_tcp_and_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_diff_client_ids_diff_ports_prefer_udp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_MASTER_STARTER} PREFER_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_prefer_udp PROPERTIES TIMEOUT 60)
+
+ add_test(NAME ${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_diff_client_ids_diff_ports_prefer_tcp
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_SUBSCRIBE_NOTIFY_ONE_MASTER_STARTER} PREFER_TCP ${TEST_SUBSCRIBE_NOTIFY_ONE_DIFF_IDS_DIFF_PORTS_MASTER_CONFIG_FILE})
+ set_tests_properties(${TEST_SUBSCRIBE_NOTIFY_ONE_NAME}_diff_client_ids_diff_ports_prefer_tcp PROPERTIES TIMEOUT 60)
+
+ # cpu load tests
+ add_test(NAME ${TEST_CPU_LOAD_NAME}
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_CPU_LOAD_MASTER_STARTER}
+ )
+ set_tests_properties(${TEST_CPU_LOAD_NAME} PROPERTIES TIMEOUT 1500)
else()
# Routing tests
add_test(NAME ${TEST_LOCAL_ROUTING_NAME}
diff --git a/test/application_tests/application_test.cpp b/test/application_tests/application_test.cpp
index d52e0a1..c73a90f 100644
--- a/test/application_tests/application_test.cpp
+++ b/test/application_tests/application_test.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -16,13 +16,26 @@
using namespace vsomeip;
class someip_application_test: public ::testing::Test {
+public:
+ someip_application_test() :
+ registered_(false) {
+ }
protected:
void SetUp() {
app_ = runtime::get()->create_application("application_test");
app_->init();
+
+ app_->register_state_handler(
+ std::bind(&someip_application_test::on_state, this,
+ std::placeholders::_1));
}
+ void on_state(vsomeip::state_type_e _state) {
+ registered_ = (_state == vsomeip::state_type_e::ST_REGISTERED);
+ }
+
+ bool registered_;
std::shared_ptr<application> app_;
};
@@ -55,6 +68,25 @@ TEST_F(someip_application_test, start_stop_application_multiple)
}
/**
+ * @test Start and stop application multiple times and offer a service
+ */
+TEST_F(someip_application_test, start_stop_application_multiple_offer_service)
+{
+ for (int i = 0; i < 10; ++i) {
+ std::thread t([&]() {
+ app_->start();
+ });
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID);
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID);
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ app_->stop();
+ t.join();
+ }
+}
+
+/**
* @test Try to start an already running application again
*/
TEST_F(someip_application_test, restart_without_stopping)
@@ -92,6 +124,7 @@ class someip_application_shutdown_test: public ::testing::Test {
protected:
void SetUp() {
is_registered_ = false;
+ is_available_ = false;
app_ = runtime::get()->create_application("application_test");
app_->init();
@@ -105,6 +138,13 @@ protected:
app_->register_state_handler(
std::bind(&someip_application_shutdown_test::on_state, this,
std::placeholders::_1));
+ app_->register_availability_handler(
+ vsomeip_test::TEST_SERVICE_SERVICE_ID,
+ vsomeip_test::TEST_SERVICE_INSTANCE_ID,
+ std::bind(&someip_application_shutdown_test::on_availability,
+ this, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+
shutdown_thread_ = std::thread(&someip_application_shutdown_test::send_shutdown_message, this);
app_->start();
@@ -118,13 +158,23 @@ protected:
void on_state(vsomeip::state_type_e _state) {
if(_state == vsomeip::state_type_e::ST_REGISTERED)
{
- app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID);
std::lock_guard<std::mutex> its_lock(mutex_);
is_registered_ = true;
cv_.notify_one();
}
}
+ void on_availability(vsomeip::service_t _service,
+ vsomeip::instance_t _instance, bool _is_available) {
+ (void)_service;
+ (void)_instance;
+ if(_is_available) {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ is_available_ = _is_available;
+ cv_.notify_one();
+ }
+ }
+
void on_message_shutdown(const std::shared_ptr<message>& _request)
{
(void)_request;
@@ -141,6 +191,11 @@ protected:
while(!is_registered_) {
cv_.wait(its_lock);
}
+ app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID);
+ while(!is_available_) {
+ cv_.wait(its_lock);
+ }
+
std::shared_ptr<message> r = runtime::get()->create_request();
r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID);
r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID);
@@ -149,6 +204,7 @@ protected:
}
bool is_registered_;
+ bool is_available_;
std::shared_ptr<application> app_;
std::condition_variable cv_;
std::mutex mutex_;
@@ -172,3 +228,4 @@ int main(int argc, char** argv)
+
diff --git a/test/application_tests/application_test.json b/test/application_tests/application_test.json
index a50eb35..66abf3a 100644
--- a/test/application_tests/application_test.json
+++ b/test/application_tests/application_test.json
@@ -33,13 +33,6 @@
"enable":"true",
"multicast":"224.0.0.1",
"port":"30490",
- "protocol":"udp",
- "initial_delay_min" : "10",
- "initial_delay_max" : "100",
- "repetitions_base_delay" : "200",
- "repetitions_max" : "3",
- "ttl" : "3",
- "cyclic_offer_delay" : "2000",
- "request_response_delay" : "1500"
+ "protocol":"udp"
}
}
diff --git a/test/application_tests/application_test_daemon.json b/test/application_tests/application_test_daemon.json
new file mode 100644
index 0000000..6b4a946
--- /dev/null
+++ b/test/application_tests/application_test_daemon.json
@@ -0,0 +1,38 @@
+{
+ "unicast":"127.0.0.1",
+ "logging":
+ {
+ "level":"warning",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/someip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"application_test",
+ "id":"0x7788",
+ "num_dispatchers":"5"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x1234",
+ "instance":"0x5678",
+ "reliable":"30503"
+ }
+ ],
+ "routing":"vsomeipd",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+}
diff --git a/test/application_tests/application_test_no_dispatch_threads_daemon.json b/test/application_tests/application_test_no_dispatch_threads_daemon.json
new file mode 100644
index 0000000..e33190b
--- /dev/null
+++ b/test/application_tests/application_test_no_dispatch_threads_daemon.json
@@ -0,0 +1,37 @@
+{
+ "unicast":"127.0.0.1",
+ "logging":
+ {
+ "level":"warning",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/someip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"application_test",
+ "id":"0x7788"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x1234",
+ "instance":"0x5678",
+ "reliable":"30503"
+ }
+ ],
+ "routing":"vsomeipd",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ }
+}
diff --git a/test/application_tests/application_test_starter.sh b/test/application_tests/application_test_starter.sh
index 2968393..a72c6c7 100755
--- a/test/application_tests/application_test_starter.sh
+++ b/test/application_tests/application_test_starter.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
@@ -22,6 +22,35 @@ then
((FAIL+=1))
fi
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Now running same tests with vsomeipd
+*******************************************************************************
+*******************************************************************************
+End-of-message
+export VSOMEIP_CONFIGURATION=application_test_no_dispatch_threads_daemon.json
+../daemon/./vsomeipd &
+DAEMON_PID=$!
+./application_test
+if [ $? -ne 0 ]
+then
+ ((FAIL+=1))
+fi
+
+kill $DAEMON_PID
+
+export VSOMEIP_CONFIGURATION=application_test_daemon.json
+../daemon/./vsomeipd &
+DAEMON_PID=$!
+./application_test
+if [ $? -ne 0 ]
+then
+ ((FAIL+=1))
+fi
+
+kill $DAEMON_PID
+
# Check if both exited successfully
if [ $FAIL -eq 0 ]
then
diff --git a/test/big_payload_tests/big_payload_test_client.cpp b/test/big_payload_tests/big_payload_test_client.cpp
index 4f96c1c..15e0a14 100644
--- a/test/big_payload_tests/big_payload_test_client.cpp
+++ b/test/big_payload_tests/big_payload_test_client.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/big_payload_tests/big_payload_test_client.hpp b/test/big_payload_tests/big_payload_test_client.hpp
index f1ee7c2..3524123 100644
--- a/test/big_payload_tests/big_payload_test_client.hpp
+++ b/test/big_payload_tests/big_payload_test_client.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/big_payload_tests/big_payload_test_globals.hpp b/test/big_payload_tests/big_payload_test_globals.hpp
index 851545a..28a6205 100644
--- a/test/big_payload_tests/big_payload_test_globals.hpp
+++ b/test/big_payload_tests/big_payload_test_globals.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/big_payload_tests/big_payload_test_service.cpp b/test/big_payload_tests/big_payload_test_service.cpp
index fecaf19..fc8690e 100644
--- a/test/big_payload_tests/big_payload_test_service.cpp
+++ b/test/big_payload_tests/big_payload_test_service.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/big_payload_tests/big_payload_test_service.hpp b/test/big_payload_tests/big_payload_test_service.hpp
index 9888f41..58d070d 100644
--- a/test/big_payload_tests/big_payload_test_service.hpp
+++ b/test/big_payload_tests/big_payload_test_service.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/client_id_tests/client_id_test_globals.hpp b/test/client_id_tests/client_id_test_globals.hpp
index 30ee575..49e07dd 100644
--- a/test/client_id_tests/client_id_test_globals.hpp
+++ b/test/client_id_tests/client_id_test_globals.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -14,16 +14,17 @@ struct service_info {
vsomeip::method_t method_id;
};
-static constexpr std::array<service_info, 6> service_infos = {{
+static constexpr std::array<service_info, 7> service_infos = {{
// placeholder to be consistent w/ client ids, service ids, app names
{ 0xFFFF, 0xFFFF, 0xFFFF },
// node 1
{ 0x1000, 0x1, 0x1111 },
{ 0x2000, 0x1, 0x2222 },
- // node 2
{ 0x3000, 0x1, 0x3333 },
+ // node 2
{ 0x4000, 0x1, 0x4444 },
- { 0x5000, 0x1, 0x5555 }
+ { 0x5000, 0x1, 0x5555 },
+ { 0x6000, 0x1, 0x6666 }
}};
static constexpr int messages_to_send = 10;
diff --git a/test/client_id_tests/client_id_test_master_starter.sh b/test/client_id_tests/client_id_test_master_starter.sh
index f8550c5..6b4e53b 100755
--- a/test/client_id_tests/client_id_test_master_starter.sh
+++ b/test/client_id_tests/client_id_test_master_starter.sh
@@ -6,9 +6,9 @@
# 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 two binaries for one testcase. Therefore
+# 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 both exit successfully.
+# and checks that all exit successfully.
if [ $# -lt 1 ]
then
@@ -31,7 +31,11 @@ export VSOMEIP_APPLICATION_NAME=client_id_test_service_two
export VSOMEIP_CONFIGURATION=$1
./client_id_test_service 2 &
+export VSOMEIP_APPLICATION_NAME=client_id_test_service_three
+export VSOMEIP_CONFIGURATION=$1
+./client_id_test_service 3 &
+sleep 1
cat <<End-of-message
*******************************************************************************
diff --git a/test/client_id_tests/client_id_test_service.cpp b/test/client_id_tests/client_id_test_service.cpp
index 57c6353..36bfeb8 100644
--- a/test/client_id_tests/client_id_test_service.cpp
+++ b/test/client_id_tests/client_id_test_service.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -239,7 +239,7 @@ 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;
- std::cerr << "Valid service numbers are in the range of [0,4]" << std::endl;
+ std::cerr << "Valid service numbers are in the range of [1,6]" << std::endl;
return 1;
}
service_number = std::stoi(std::string(argv[1]), nullptr);
diff --git a/test/client_id_tests/client_id_test_slave_starter.sh b/test/client_id_tests/client_id_test_slave_starter.sh
index 94ff78b..59291cb 100755
--- a/test/client_id_tests/client_id_test_slave_starter.sh
+++ b/test/client_id_tests/client_id_test_slave_starter.sh
@@ -10,8 +10,6 @@
# the testcase simply executes this script. This script then runs the services
# and checks that all exit successfully.
-FAIL=0
-
if [ $# -lt 1 ]
then
echo "Please pass a json file to this script."
@@ -19,11 +17,9 @@ then
exit 1
fi
-# Start the services
-export VSOMEIP_APPLICATION_NAME=client_id_test_service_three
-export VSOMEIP_CONFIGURATION=$1
-./client_id_test_service 3 &
+FAIL=0
+# Start the services
export VSOMEIP_APPLICATION_NAME=client_id_test_service_four
export VSOMEIP_CONFIGURATION=$1
./client_id_test_service 4 &
@@ -32,6 +28,10 @@ export VSOMEIP_APPLICATION_NAME=client_id_test_service_five
export VSOMEIP_CONFIGURATION=$1
./client_id_test_service 5 &
+export VSOMEIP_APPLICATION_NAME=client_id_test_service_six
+export VSOMEIP_CONFIGURATION=$1
+./client_id_test_service 6 &
+
# Wait until all applications are finished
for job in $(jobs -p)
diff --git a/test/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_master.json.in b/test/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_master.json.in
index fe2248d..a986dd9 100644
--- a/test/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_master.json.in
+++ b/test/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_master.json.in
@@ -20,6 +20,10 @@
{
"name":"client_id_test_service_two",
"id":"0x2222"
+ },
+ {
+ "name":"client_id_test_service_three",
+ "id":"0x3333"
}
],
"services":
@@ -43,6 +47,16 @@
"port":"40002",
"enable-magic-cookies":"false"
}
+ },
+ {
+ "service":"0x3000",
+ "instance":"0x0001",
+ "unreliable":"30003",
+ "reliable":
+ {
+ "port":"40003",
+ "enable-magic-cookies":"false"
+ }
}
],
"routing":"client_id_test_service_one",
diff --git a/test/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_slave.json.in b/test/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_slave.json.in
index 62aee87..596f842 100644
--- a/test/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_slave.json.in
+++ b/test/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_slave.json.in
@@ -14,52 +14,52 @@
"applications":
[
{
- "name":"client_id_test_service_three",
- "id":"0x3333"
- },
- {
"name":"client_id_test_service_four",
"id":"0x4444"
},
{
"name":"client_id_test_service_five",
"id":"0x5555"
+ },
+ {
+ "name":"client_id_test_service_six",
+ "id":"0x6666"
}
],
"services":
[
{
- "service":"0x3000",
+ "service":"0x4000",
"instance":"0x0001",
- "unreliable":"30003",
+ "unreliable":"30004",
"reliable":
{
- "port":"40003",
+ "port":"40004",
"enable-magic-cookies":"false"
}
},
{
- "service":"0x4000",
+ "service":"0x5000",
"instance":"0x0001",
- "unreliable":"30004",
+ "unreliable":"30005",
"reliable":
{
- "port":"40004",
+ "port":"40005",
"enable-magic-cookies":"false"
}
},
{
- "service":"0x5000",
+ "service":"0x6000",
"instance":"0x0001",
- "unreliable":"30005",
+ "unreliable":"30006",
"reliable":
{
- "port":"40005",
+ "port":"40006",
"enable-magic-cookies":"false"
}
}
],
- "routing":"client_id_test_service_three",
+ "routing":"client_id_test_service_four",
"service-discovery":
{
"enable":"true",
diff --git a/test/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_master.json.in b/test/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_master.json.in
new file mode 100644
index 0000000..bb3507b
--- /dev/null
+++ b/test/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_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":"client_id_test_service_one",
+ "id":"0x1111"
+ },
+ {
+ "name":"client_id_test_service_two",
+ "id":"0x2222"
+ },
+ {
+ "name":"client_id_test_service_three",
+ "id":"0x3333"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x1000",
+ "instance":"0x0001",
+ "unreliable":"30001",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x2000",
+ "instance":"0x0001",
+ "unreliable":"30002",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x3000",
+ "instance":"0x0001",
+ "unreliable":"30003",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ }
+ ],
+ "routing":"client_id_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/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_slave.json.in b/test/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_slave.json.in
new file mode 100644
index 0000000..a7337e9
--- /dev/null
+++ b/test/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_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":"client_id_test_service_four",
+ "id":"0x4444"
+ },
+ {
+ "name":"client_id_test_service_five",
+ "id":"0x5555"
+ },
+ {
+ "name":"client_id_test_service_six",
+ "id":"0x6666"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x4000",
+ "instance":"0x0001",
+ "unreliable":"30004",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x5000",
+ "instance":"0x0001",
+ "unreliable":"30005",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ },
+ {
+ "service":"0x6000",
+ "instance":"0x0001",
+ "unreliable":"30006",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
+ }
+ ],
+ "routing":"client_id_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/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_master.json.in b/test/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_master.json.in
index b0c833b..9f7062f 100644
--- a/test/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_master.json.in
+++ b/test/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_master.json.in
@@ -20,6 +20,10 @@
{
"name":"client_id_test_service_two",
"id":"0x2222"
+ },
+ {
+ "name":"client_id_test_service_three",
+ "id":"0x3333"
}
],
"services":
@@ -43,6 +47,16 @@
"port":"40000",
"enable-magic-cookies":"false"
}
+ },
+ {
+ "service":"0x3000",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
}
],
"routing":"client_id_test_service_one",
diff --git a/test/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_slave.json.in b/test/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_slave.json.in
index a9084fc..1aaf2cb 100644
--- a/test/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_slave.json.in
+++ b/test/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_slave.json.in
@@ -14,22 +14,22 @@
"applications":
[
{
- "name":"client_id_test_service_three",
- "id":"0x3333"
- },
- {
"name":"client_id_test_service_four",
"id":"0x4444"
},
{
"name":"client_id_test_service_five",
"id":"0x5555"
+ },
+ {
+ "name":"client_id_test_service_six",
+ "id":"0x6666"
}
],
"services":
[
{
- "service":"0x3000",
+ "service":"0x4000",
"instance":"0x0001",
"unreliable":"30000",
"reliable":
@@ -39,7 +39,7 @@
}
},
{
- "service":"0x4000",
+ "service":"0x5000",
"instance":"0x0001",
"unreliable":"30000",
"reliable":
@@ -49,7 +49,7 @@
}
},
{
- "service":"0x5000",
+ "service":"0x6000",
"instance":"0x0001",
"unreliable":"30000",
"reliable":
@@ -59,7 +59,7 @@
}
}
],
- "routing":"client_id_test_service_three",
+ "routing":"client_id_test_service_four",
"service-discovery":
{
"enable":"true",
diff --git a/test/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_master.json.in b/test/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_master.json.in
index fe2248d..a986dd9 100644
--- a/test/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_master.json.in
+++ b/test/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_master.json.in
@@ -20,6 +20,10 @@
{
"name":"client_id_test_service_two",
"id":"0x2222"
+ },
+ {
+ "name":"client_id_test_service_three",
+ "id":"0x3333"
}
],
"services":
@@ -43,6 +47,16 @@
"port":"40002",
"enable-magic-cookies":"false"
}
+ },
+ {
+ "service":"0x3000",
+ "instance":"0x0001",
+ "unreliable":"30003",
+ "reliable":
+ {
+ "port":"40003",
+ "enable-magic-cookies":"false"
+ }
}
],
"routing":"client_id_test_service_one",
diff --git a/test/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_slave.json.in b/test/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_slave.json.in
index dc8f5ae..2acb37b 100644
--- a/test/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_slave.json.in
+++ b/test/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_slave.json.in
@@ -14,52 +14,52 @@
"applications":
[
{
- "name":"client_id_test_service_three",
+ "name":"client_id_test_service_four",
"id":"0x1111"
},
{
- "name":"client_id_test_service_four",
+ "name":"client_id_test_service_five",
"id":"0x2222"
},
{
- "name":"client_id_test_service_five",
+ "name":"client_id_test_service_six",
"id":"0x3333"
}
],
"services":
[
{
- "service":"0x3000",
+ "service":"0x4000",
"instance":"0x0001",
- "unreliable":"30003",
+ "unreliable":"30004",
"reliable":
{
- "port":"40003",
+ "port":"40004",
"enable-magic-cookies":"false"
}
},
{
- "service":"0x4000",
+ "service":"0x5000",
"instance":"0x0001",
- "unreliable":"30004",
+ "unreliable":"30005",
"reliable":
{
- "port":"40004",
+ "port":"40005",
"enable-magic-cookies":"false"
}
},
{
- "service":"0x5000",
+ "service":"0x6000",
"instance":"0x0001",
- "unreliable":"30005",
+ "unreliable":"30006",
"reliable":
{
- "port":"40005",
+ "port":"40006",
"enable-magic-cookies":"false"
}
}
],
- "routing":"client_id_test_service_three",
+ "routing":"client_id_test_service_four",
"service-discovery":
{
"enable":"true",
diff --git a/test/client_id_tests/conf/client_id_test_same_client_ids_same_ports_master.json.in b/test/client_id_tests/conf/client_id_test_same_client_ids_same_ports_master.json.in
index b0c833b..9f7062f 100644
--- a/test/client_id_tests/conf/client_id_test_same_client_ids_same_ports_master.json.in
+++ b/test/client_id_tests/conf/client_id_test_same_client_ids_same_ports_master.json.in
@@ -20,6 +20,10 @@
{
"name":"client_id_test_service_two",
"id":"0x2222"
+ },
+ {
+ "name":"client_id_test_service_three",
+ "id":"0x3333"
}
],
"services":
@@ -43,6 +47,16 @@
"port":"40000",
"enable-magic-cookies":"false"
}
+ },
+ {
+ "service":"0x3000",
+ "instance":"0x0001",
+ "unreliable":"30000",
+ "reliable":
+ {
+ "port":"40000",
+ "enable-magic-cookies":"false"
+ }
}
],
"routing":"client_id_test_service_one",
diff --git a/test/client_id_tests/conf/client_id_test_same_client_ids_same_ports_slave.json.in b/test/client_id_tests/conf/client_id_test_same_client_ids_same_ports_slave.json.in
index 0b6e1e2..ae534b1 100644
--- a/test/client_id_tests/conf/client_id_test_same_client_ids_same_ports_slave.json.in
+++ b/test/client_id_tests/conf/client_id_test_same_client_ids_same_ports_slave.json.in
@@ -14,22 +14,22 @@
"applications":
[
{
- "name":"client_id_test_service_three",
+ "name":"client_id_test_service_four",
"id":"0x1111"
},
{
- "name":"client_id_test_service_four",
+ "name":"client_id_test_service_five",
"id":"0x2222"
},
{
- "name":"client_id_test_service_five",
+ "name":"client_id_test_service_six",
"id":"0x3333"
}
],
"services":
[
{
- "service":"0x3000",
+ "service":"0x4000",
"instance":"0x0001",
"unreliable":"30000",
"reliable":
@@ -39,7 +39,7 @@
}
},
{
- "service":"0x4000",
+ "service":"0x5000",
"instance":"0x0001",
"unreliable":"30000",
"reliable":
@@ -49,7 +49,7 @@
}
},
{
- "service":"0x5000",
+ "service":"0x6000",
"instance":"0x0001",
"unreliable":"30000",
"reliable":
@@ -59,7 +59,7 @@
}
}
],
- "routing":"client_id_test_service_three",
+ "routing":"client_id_test_service_four",
"service-discovery":
{
"enable":"true",
diff --git a/test/configuration_tests/configuration-test.cpp b/test/configuration_tests/configuration-test.cpp
index b4538d0..01a0e3e 100644
--- a/test/configuration_tests/configuration-test.cpp
+++ b/test/configuration_tests/configuration-test.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/cpu_load_tests/conf/cpu_load_test_client_master.json.in b/test/cpu_load_tests/conf/cpu_load_test_client_master.json.in
new file mode 100644
index 0000000..d623758
--- /dev/null
+++ b/test/cpu_load_tests/conf/cpu_load_test_client_master.json.in
@@ -0,0 +1,32 @@
+{
+ "unicast" : "@TEST_IP_MASTER@",
+ "netmask" : "255.255.255.0",
+ "logging" :
+ {
+ "level" : "debug",
+ "console" : "true",
+ "file" :
+ {
+ "enable" : "false",
+ "path" : "/var/log/vsomeip.log"
+ },
+
+ "dlt" : "false"
+ },
+
+ "applications" :
+ [
+ {
+ "name" : "cpu_load_test_client",
+ "id" : "0x2222"
+ }
+ ],
+ "routing" : "cpu_load_test_client",
+ "service-discovery" :
+ {
+ "enable" : "true",
+ "multicast" : "224.0.0.1",
+ "port" : "30490",
+ "protocol" : "udp"
+ }
+}
diff --git a/test/cpu_load_tests/conf/cpu_load_test_client_slave.json.in b/test/cpu_load_tests/conf/cpu_load_test_client_slave.json.in
new file mode 100644
index 0000000..36de379
--- /dev/null
+++ b/test/cpu_load_tests/conf/cpu_load_test_client_slave.json.in
@@ -0,0 +1,32 @@
+{
+ "unicast" : "@TEST_IP_SLAVE@",
+ "netmask" : "255.255.255.0",
+ "logging" :
+ {
+ "level" : "debug",
+ "console" : "true",
+ "file" :
+ {
+ "enable" : "false",
+ "path" : "/var/log/vsomeip.log"
+ },
+
+ "dlt" : "false"
+ },
+
+ "applications" :
+ [
+ {
+ "name" : "cpu_load_test_client",
+ "id" : "0x2222"
+ }
+ ],
+ "routing" : "cpu_load_test_client",
+ "service-discovery" :
+ {
+ "enable" : "true",
+ "multicast" : "224.0.0.1",
+ "port" : "30490",
+ "protocol" : "udp"
+ }
+}
diff --git a/test/cpu_load_tests/conf/cpu_load_test_service_master.json.in b/test/cpu_load_tests/conf/cpu_load_test_service_master.json.in
new file mode 100644
index 0000000..d836650
--- /dev/null
+++ b/test/cpu_load_tests/conf/cpu_load_test_service_master.json.in
@@ -0,0 +1,46 @@
+{
+ "unicast" : "@TEST_IP_MASTER@",
+ "logging" :
+ {
+ "level" : "debug",
+ "console" : "true",
+ "file" :
+ {
+ "enable" : "false",
+ "path" : "/tmp/vsomeip.log"
+ },
+
+ "dlt" : "false"
+ },
+
+ "applications" :
+ [
+ {
+ "name" : "cpu_load_test_service",
+ "id" : "0x1111"
+ }
+ ],
+
+ "services" :
+ [
+ {
+ "service" : "0x1111",
+ "instance" : "0x1",
+ "unreliable" : "30510",
+ "reliable" :
+ {
+ "port" : "30510",
+ "enable-magic-cookies" : "false"
+ }
+ }
+ ],
+
+ "routing" : "cpu_load_test_service",
+ "service-discovery" :
+ {
+ "enable" : "true",
+ "multicast" : "224.0.0.1",
+ "port" : "30490",
+ "protocol" : "udp"
+ }
+}
diff --git a/test/cpu_load_tests/conf/cpu_load_test_service_slave.json.in b/test/cpu_load_tests/conf/cpu_load_test_service_slave.json.in
new file mode 100644
index 0000000..78e1909
--- /dev/null
+++ b/test/cpu_load_tests/conf/cpu_load_test_service_slave.json.in
@@ -0,0 +1,46 @@
+{
+ "unicast" : "@TEST_IP_SLAVE@",
+ "logging" :
+ {
+ "level" : "debug",
+ "console" : "true",
+ "file" :
+ {
+ "enable" : "false",
+ "path" : "/tmp/vsomeip.log"
+ },
+
+ "dlt" : "false"
+ },
+
+ "applications" :
+ [
+ {
+ "name" : "cpu_load_test_service",
+ "id" : "0x1111"
+ }
+ ],
+
+ "services" :
+ [
+ {
+ "service" : "0x1111",
+ "instance" : "0x1",
+ "unreliable" : "30510",
+ "reliable" :
+ {
+ "port" : "30510",
+ "enable-magic-cookies" : "false"
+ }
+ }
+ ],
+
+ "routing" : "cpu_load_test_service",
+ "service-discovery" :
+ {
+ "enable" : "true",
+ "multicast" : "224.0.0.1",
+ "port" : "30490",
+ "protocol" : "udp"
+ }
+}
diff --git a/test/cpu_load_tests/cpu_load_measurer.cpp b/test/cpu_load_tests/cpu_load_measurer.cpp
new file mode 100644
index 0000000..5d1fa0a
--- /dev/null
+++ b/test/cpu_load_tests/cpu_load_measurer.cpp
@@ -0,0 +1,158 @@
+// 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 "cpu_load_measurer.hpp"
+
+#include <fstream>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <stdexcept>
+#include <cstdio>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+cpu_load_measurer::~cpu_load_measurer() {
+}
+
+cpu_load_measurer::cpu_load_measurer(std::uint32_t _pid) :
+ pid_(_pid),
+ jiffies_complete_start_(0),
+ jiffies_idle_start_(0),
+ jiffies_complete_stop_(0),
+ jiffies_idle_stop_(0),
+ clock_ticks_(0),
+ jiffies_passed_pid_start_(0),
+ jiffies_passed_pid_stop_(0),
+ cpu_load_pid_(0.0),
+ cpu_load_overall_(0.0),
+ cpu_load_pid_wo_idle_(0.0) {
+}
+
+void cpu_load_measurer::start() {
+ // reset everything
+ jiffies_complete_start_ = 0;
+ jiffies_idle_start_ = 0;
+ jiffies_complete_stop_ = 0;
+ jiffies_idle_stop_ = 0;
+ clock_ticks_ = 0;
+ jiffies_passed_pid_start_ = 0;
+ jiffies_passed_pid_stop_ = 0;
+ cpu_load_pid_= 0.0;
+ cpu_load_overall_ = 0.0;
+ cpu_load_pid_wo_idle_ = 0.0;
+ //start
+ jiffies_complete_start_ = read_proc_stat(&jiffies_idle_start_);
+ jiffies_passed_pid_start_ = read_proc_pid_stat();
+}
+
+void cpu_load_measurer::stop() {
+ jiffies_complete_stop_ = read_proc_stat(&jiffies_idle_stop_);
+ jiffies_passed_pid_stop_ = read_proc_pid_stat();
+ if(jiffies_complete_stop_ < jiffies_complete_start_ || jiffies_passed_pid_stop_ < jiffies_passed_pid_start_) {
+ std::cerr << "Overflow of values in procfs occured, can't calculate load" << std::endl;
+ exit(0);
+ }
+ cpu_load_pid_ = 100.0
+ * static_cast<double>(jiffies_passed_pid_stop_
+ - jiffies_passed_pid_start_)
+ / static_cast<double>(jiffies_complete_stop_
+ - jiffies_complete_start_);
+ cpu_load_overall_ = 100.0
+ * static_cast<double>((jiffies_complete_stop_ - jiffies_idle_stop_)
+ - (jiffies_complete_start_ - jiffies_idle_start_))
+ / static_cast<double>(jiffies_complete_stop_
+ - jiffies_complete_start_);
+ cpu_load_pid_wo_idle_ = 100.0
+ * static_cast<double>(jiffies_passed_pid_stop_
+ - jiffies_passed_pid_start_)
+ / static_cast<double>((jiffies_complete_stop_ - jiffies_idle_stop_)
+ - (jiffies_complete_start_ - jiffies_idle_start_));
+
+}
+
+void cpu_load_measurer::print_cpu_load() const {
+ std::cout << "Used Jiffies complete: "
+ << jiffies_complete_stop_ - jiffies_complete_start_ << " (worked: "
+ << (jiffies_complete_stop_ - jiffies_idle_stop_)
+ - (jiffies_complete_start_ - jiffies_idle_start_)
+ << " idled: " << jiffies_idle_stop_ - jiffies_idle_start_
+ << ")" << std::endl;
+ std::cout << "Used Jiffies of pid " << pid_ << ": " << jiffies_passed_pid_stop_ - jiffies_passed_pid_start_ << std::endl;
+ std::cout << "Cpu load pid " << pid_ << " [%]: " << cpu_load_pid_ << std::endl;
+ std::cout << "Overall cpu load[%]: " << cpu_load_overall_ << std::endl;
+ std::cout << "Load caused by pid " << pid_ << " of overall cpu load [%]:" << cpu_load_pid_wo_idle_ << std::endl;
+}
+
+double cpu_load_measurer::get_cpu_load() const {
+ return cpu_load_pid_;
+}
+
+std::uint64_t cpu_load_measurer::read_proc_pid_stat() {
+ std::string path("/proc/" + std::to_string(pid_) + "/stat");
+ FILE* f = std::fopen(path.c_str(), "r");
+ if(!f) {
+ std::perror(std::string("Failed to open " + path).c_str());
+ exit(1);
+ }
+ // see Table 1-4 Contents of the stat files (as of 2.6.30-rc7)
+ // at https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/filesystems/proc.txt?id=refs/tags/v3.10.98
+ // and man proc (for conversion specifier)
+ std::uint64_t utime(0);
+ std::uint64_t stime(0);
+ std::int64_t cutime(0);
+ std::int64_t cstime(0);
+ if (std::fscanf(f, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u "
+ "%lu %lu %ld %ld", // utime, stime, cutime, cstime
+ &utime, &stime, &cutime, &cstime) == EOF) {
+ std::cerr << "Failed to read " + path << std::endl;
+ exit(1);
+ }
+ std::fclose(f);
+ return utime + stime + cutime + cstime;
+}
+
+std::uint64_t cpu_load_measurer::read_proc_stat(std::uint64_t* _idle) {
+ FILE* f = std::fopen("/proc/stat", "r");
+ if(!f) {
+ std::perror("Failed to open /proc/stat");
+ exit(1);
+ }
+
+ // see 1.8 Miscellaneous kernel statistics in /proc/stat
+ // at https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/filesystems/proc.txt?id=refs/tags/v3.10.98
+ std::uint64_t user(0);
+ std::uint64_t nice(0);
+ std::uint64_t system(0);
+ std::uint64_t idle(0);
+ std::uint64_t iowait(0);
+ std::uint64_t irq(0);
+ std::uint64_t softirq(0);
+ std::uint64_t steal(0);
+ std::uint64_t guest(0);
+ std::uint64_t guest_nice(0);
+ if (std::fscanf(f, "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", &user,
+ &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest,
+ &guest_nice) == EOF) {
+ std::cerr << "Failed to read /proc/stat" << std::endl;
+ exit(1);
+ }
+ std::fclose(f);
+ *_idle = idle;
+ return user + nice + system + idle + iowait + irq + softirq + steal + guest
+ + guest_nice;
+}
+
+bool cpu_load_measurer::read_clock_ticks() {
+ long val(::sysconf(_SC_CLK_TCK));
+ if(val < 0 && errno == EINVAL) {
+ std::perror(__func__);
+ return false;
+ }
+ clock_ticks_ = static_cast<std::uint64_t>(val);
+ return true;
+}
diff --git a/test/cpu_load_tests/cpu_load_measurer.hpp b/test/cpu_load_tests/cpu_load_measurer.hpp
new file mode 100644
index 0000000..ce72d0c
--- /dev/null
+++ b/test/cpu_load_tests/cpu_load_measurer.hpp
@@ -0,0 +1,35 @@
+// 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/.
+
+#pragma once
+
+#include <cstdint>
+
+class cpu_load_measurer {
+public:
+ cpu_load_measurer(std::uint32_t _pid);
+ virtual ~cpu_load_measurer();
+ void start();
+ void stop();
+ void print_cpu_load() const;
+ double get_cpu_load() const;
+
+private:
+ std::uint64_t read_proc_stat(std::uint64_t* _idle);
+ std::uint64_t read_proc_pid_stat();
+ bool read_clock_ticks();
+private:
+ std::uint32_t pid_;
+ std::uint64_t jiffies_complete_start_;
+ std::uint64_t jiffies_idle_start_;
+ std::uint64_t jiffies_complete_stop_;
+ std::uint64_t jiffies_idle_stop_;
+ std::uint64_t clock_ticks_;
+ std::uint64_t jiffies_passed_pid_start_;
+ std::uint64_t jiffies_passed_pid_stop_;
+ double cpu_load_pid_;
+ double cpu_load_overall_;
+ double cpu_load_pid_wo_idle_;
+};
diff --git a/test/cpu_load_tests/cpu_load_test_client.cpp b/test/cpu_load_tests/cpu_load_test_client.cpp
new file mode 100644
index 0000000..6546013
--- /dev/null
+++ b/test/cpu_load_tests/cpu_load_test_client.cpp
@@ -0,0 +1,376 @@
+// 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 <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <functional>
+#include <iomanip>
+#include <numeric>
+#include <cmath> // for isfinite
+
+#include "cpu_load_test_globals.hpp"
+#include "../../implementation/logging/include/logger.hpp"
+#include "cpu_load_measurer.hpp"
+
+// for getpid
+#include <sys/types.h>
+#include <unistd.h>
+
+
+enum protocol_e {
+ PR_UNKNOWN,
+ PR_TCP,
+ PR_UDP
+};
+
+class cpu_load_test_client
+{
+public:
+ cpu_load_test_client(protocol_e _protocol, std::uint32_t _number_of_calls,
+ std::uint32_t _payload_size, bool _call_service_sync,
+ bool _shutdown_service) :
+ protocol_(_protocol),
+ app_(vsomeip::runtime::get()->create_application("cpu_load_test_client")),
+ request_(vsomeip::runtime::get()->create_request(protocol_ == protocol_e::PR_TCP)),
+ call_service_sync_(_call_service_sync),
+ shutdown_service_at_end_(_shutdown_service),
+ sliding_window_size_(_number_of_calls),
+ wait_for_availability_(true),
+ is_available_(false),
+ number_of_calls_(_number_of_calls),
+ number_of_calls_current_(0),
+ number_of_sent_messages_(0),
+ number_of_sent_messages_total_(0),
+ number_of_acknowledged_messages_(0),
+ payload_size_(_payload_size),
+ wait_for_all_msg_acknowledged_(true),
+ sender_(std::bind(&cpu_load_test_client::run, this)) {
+ app_->init();
+
+ app_->register_state_handler(
+ std::bind(&cpu_load_test_client::on_state, this,
+ std::placeholders::_1));
+
+ app_->register_message_handler(vsomeip::ANY_SERVICE,
+ vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD,
+ std::bind(&cpu_load_test_client::on_message, this,
+ std::placeholders::_1));
+
+ app_->register_availability_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id,
+ std::bind(&cpu_load_test_client::on_availability, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+ VSOMEIP_INFO << "Starting...";
+ app_->start();
+ }
+
+ ~cpu_load_test_client() {
+ sender_.join();
+ }
+
+private:
+ void stop() {
+ VSOMEIP_INFO << "Stopping...";
+ // shutdown the service
+ if(shutdown_service_at_end_)
+ {
+ shutdown_service();
+ }
+ app_->unregister_availability_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id);
+ app_->unregister_state_handler();
+ app_->unregister_message_handler(vsomeip::ANY_SERVICE,
+ vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD);
+ }
+
+ void on_state(vsomeip::state_type_e _state) {
+ if(_state == vsomeip::state_type_e::ST_REGISTERED)
+ {
+ app_->request_service(cpu_load_test::service_id,
+ cpu_load_test::instance_id);
+ }
+ }
+
+ 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.");
+
+ if (cpu_load_test::service_id == _service
+ && cpu_load_test::instance_id == _instance) {
+ if (is_available_ && !_is_available) {
+ is_available_ = false;
+ } else if (_is_available && !is_available_) {
+ is_available_ = true;
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_for_availability_ = false;
+ condition_.notify_one();
+ }
+ }
+ }
+ void on_message(const std::shared_ptr<vsomeip::message> &_response) {
+
+ number_of_acknowledged_messages_++;
+ ASSERT_EQ(_response->get_service(), cpu_load_test::service_id);
+ ASSERT_EQ(_response->get_method(), cpu_load_test::method_id);
+ if(call_service_sync_)
+ {
+ // We notify the sender thread every time a message was acknowledged
+ std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_);
+ wait_for_all_msg_acknowledged_ = false;
+ all_msg_acknowledged_cv_.notify_one();
+ }
+ else
+ {
+ // We notify the sender thread only if all sent messages have been acknowledged
+ if(number_of_acknowledged_messages_ == number_of_calls_current_)
+ {
+ std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_);
+ number_of_acknowledged_messages_ = 0;
+ wait_for_all_msg_acknowledged_ = false;
+ all_msg_acknowledged_cv_.notify_one();
+ }
+ else if(number_of_acknowledged_messages_ % sliding_window_size_ == 0)
+ {
+ std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_);
+ wait_for_all_msg_acknowledged_ = false;
+ all_msg_acknowledged_cv_.notify_one();
+ }
+ }
+ }
+
+ void run() {
+ std::unique_lock<std::mutex> its_lock(mutex_);
+ while (wait_for_availability_) {
+ condition_.wait(its_lock);
+ }
+
+ request_->set_service(cpu_load_test::service_id);
+ request_->set_instance(cpu_load_test::instance_id);
+ request_->set_method(cpu_load_test::method_id);
+ std::shared_ptr<vsomeip::payload> payload = vsomeip::runtime::get()->create_payload();
+ std::vector<vsomeip::byte_t> payload_data;
+ payload_data.assign(payload_size_, cpu_load_test::load_test_data);
+ payload->set_data(payload_data);
+ request_->set_payload(payload);
+
+ // lock the mutex
+ for(std::uint32_t i=0; i <= number_of_calls_; i++) {
+ number_of_calls_current_ = i;
+ sliding_window_size_ = i;
+ std::unique_lock<std::mutex> lk(all_msg_acknowledged_mutex_);
+ call_service_sync_ ? send_messages_sync(lk, i) : send_messages_async(lk, i);
+ }
+ const double average_load(std::accumulate(results_.begin(), results_.end(), 0.0) / static_cast<double>(results_.size()));
+ VSOMEIP_INFO << "Sent: " << number_of_sent_messages_total_
+ << " messages in total (excluding control messages). This caused: "
+ << std::fixed << std::setprecision(2)
+ << average_load << "% load in average (average of "
+ << results_.size() << " measurements).";
+
+ std::vector<double> results_no_zero;
+ for(const auto &v : results_) {
+ if(v > 0.0) {
+ results_no_zero.push_back(v);
+ }
+ }
+ const double average_load_no_zero(std::accumulate(results_no_zero.begin(), results_no_zero.end(), 0.0) / static_cast<double>(results_no_zero.size()));
+ VSOMEIP_INFO << "Sent: " << number_of_sent_messages_total_
+ << " messages in total (excluding control messages). This caused: "
+ << std::fixed << std::setprecision(2)
+ << average_load_no_zero << "% load in average, if measured "
+ << "cpu load was greater zero (average of "
+ << results_no_zero.size() << " measurements).";
+
+ wait_for_availability_ = true;
+
+ stop();
+ app_->stop();
+ }
+
+
+ void send_messages_sync(std::unique_lock<std::mutex>& lk, std::uint32_t _messages_to_send) {
+ cpu_load_measurer c(::getpid());
+ send_service_start_measuring(true);
+ c.start();
+ for (number_of_sent_messages_ = 0;
+ number_of_sent_messages_ < _messages_to_send;
+ number_of_sent_messages_++, number_of_sent_messages_total_++)
+ {
+ app_->send(request_, true);
+ // wait until the send messages has been acknowledged
+ while(wait_for_all_msg_acknowledged_) {
+ all_msg_acknowledged_cv_.wait(lk);
+ }
+ wait_for_all_msg_acknowledged_ = true;
+ }
+ c.stop();
+ send_service_start_measuring(false);
+ VSOMEIP_DEBUG << "Synchronously sent " << std::setw(4) << std::setfill('0')
+ << number_of_sent_messages_ << " messages. CPU load [%]: "
+ << std::fixed << std::setprecision(2)
+ << (std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0);
+ results_.push_back(std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0);
+
+ }
+
+ void send_messages_async(std::unique_lock<std::mutex>& lk, std::uint32_t _messages_to_send) {
+ cpu_load_measurer c(::getpid());
+ send_service_start_measuring(true);
+ c.start();
+ for (number_of_sent_messages_ = 0;
+ number_of_sent_messages_ < _messages_to_send;
+ number_of_sent_messages_++, number_of_sent_messages_total_++)
+ {
+ app_->send(request_, true);
+ if((number_of_sent_messages_+1) % sliding_window_size_ == 0)
+ {
+ // wait until all send messages have been acknowledged
+ while(wait_for_all_msg_acknowledged_) {
+ all_msg_acknowledged_cv_.wait(lk);
+ }
+ wait_for_all_msg_acknowledged_ = true;
+ }
+ }
+ c.stop();
+ send_service_start_measuring(false);
+ VSOMEIP_DEBUG << "Asynchronously sent " << std::setw(4) << std::setfill('0')
+ << number_of_sent_messages_ << " messages. CPU load [%]: "
+ << std::fixed << std::setprecision(2)
+ << (std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0);
+ results_.push_back(std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0);
+ }
+
+ void send_service_start_measuring(bool _start_measuring) {
+ std::shared_ptr<vsomeip::message> m = vsomeip::runtime::get()->create_request(protocol_ == protocol_e::PR_TCP);
+ m->set_service(cpu_load_test::service_id);
+ m->set_instance(cpu_load_test::instance_id);
+ _start_measuring ? m->set_method(cpu_load_test::method_id_cpu_measure_start) : m->set_method(cpu_load_test::method_id_cpu_measure_stop);
+ app_->send(m);
+ }
+
+ void shutdown_service() {
+ request_->set_service(cpu_load_test::service_id);
+ request_->set_instance(cpu_load_test::instance_id);
+ request_->set_method(cpu_load_test::method_id_shutdown);
+ app_->send(request_);
+ }
+
+private:
+ protocol_e protocol_;
+ std::shared_ptr<vsomeip::application> app_;
+ std::shared_ptr<vsomeip::message> request_;
+ bool call_service_sync_;
+ bool shutdown_service_at_end_;
+ std::uint32_t sliding_window_size_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ bool wait_for_availability_;
+ bool is_available_;
+ const std::uint32_t number_of_calls_;
+ std::uint32_t number_of_calls_current_;
+ std::uint32_t number_of_sent_messages_;
+ std::uint32_t number_of_sent_messages_total_;
+ std::uint32_t number_of_acknowledged_messages_;
+
+ std::uint32_t payload_size_;
+
+ bool wait_for_all_msg_acknowledged_;
+ std::mutex all_msg_acknowledged_mutex_;
+ std::condition_variable all_msg_acknowledged_cv_;
+ std::vector<double> results_;
+ std::thread sender_;
+};
+
+
+// this variables are changed via cmdline parameters
+static protocol_e protocol(protocol_e::PR_UNKNOWN);
+static std::uint32_t number_of_calls(0);
+static std::uint32_t payload_size(40);
+static bool call_service_sync(true);
+static bool shutdown_service(true);
+
+
+TEST(someip_load_test, send_messages_and_measure_cpu_load)
+{
+ cpu_load_test_client test_client_(protocol, number_of_calls, payload_size, call_service_sync, shutdown_service);
+}
+
+#ifndef WIN32
+int main(int argc, char** argv)
+{
+ int i = 0;
+ while (i < argc) {
+ if(std::string("--protocol") == std::string(argv[i])
+ || std::string("-p") == std::string(argv[i])) {
+ if(std::string("udp") == std::string(argv[i+1]) ||
+ std::string("UDP") == std::string(argv[i+1])) {
+ protocol = protocol_e::PR_UDP;
+ i++;
+ } else if(std::string("tcp") == std::string(argv[i+1]) ||
+ std::string("TCP") == std::string(argv[i+1])) {
+ protocol = protocol_e::PR_TCP;
+ i++;
+ }
+ } else if(std::string("--calls") == std::string(argv[i])
+ || std::string("-c") == std::string(argv[i])) {
+ try {
+ number_of_calls = static_cast<std::uint32_t>(std::stoul(std::string(argv[i+1]), nullptr, 10));
+ } catch (const std::exception &e) {
+ std::cerr << "Please specify a valid value for number of calls" << std::endl;
+ return(EXIT_FAILURE);
+ }
+ i++;
+ } else if(std::string("--mode") == std::string(argv[i])
+ || std::string("-m") == std::string(argv[i])) {
+ if(std::string("sync") == std::string(argv[i+1]) ||
+ std::string("SYNC") == std::string(argv[i+1])) {
+ call_service_sync = true;
+ i++;
+ } else if(std::string("async") == std::string(argv[i+1]) ||
+ std::string("ASYNC") == std::string(argv[i+1])) {
+ call_service_sync = false;
+ i++;
+ }
+ } else if(std::string("--payload-size") == std::string(argv[i])
+ || std::string("-pl") == std::string(argv[i])) {
+ try {
+ payload_size = static_cast<std::uint32_t>(std::stoul(std::string(argv[i+1]), nullptr, 10));
+ } catch (const std::exception &e) {
+ std::cerr << "Please specify a valid values for payload size" << std::endl;
+ return(EXIT_FAILURE);
+ }
+ i++;
+ } else if(std::string("--help") == std::string(argv[i])
+ || std::string("-h") == std::string(argv[i])) {
+ std::cout << "Available options:" << std::endl;
+ std::cout << "--protocol|-p: valid values TCP or UDP" << std::endl;
+ std::cout << "--calls|-c: number of message calls to do" << std::endl;
+ std::cout << "--mode|-m: mode sync or async" << std::endl;
+ std::cout << "--payload-size|-pl: payload size in Bytes default: 40" << std::endl;
+ }
+ i++;
+ }
+
+ if(protocol == protocol_e::PR_UNKNOWN) {
+ std::cerr << "Please specify valid protocol mode, see --help" << std::endl;
+ return(EXIT_FAILURE);
+ }
+ if(!number_of_calls) {
+ std::cerr << "Please specify valid number of calls, see --help" << std::endl;
+ return(EXIT_FAILURE);
+ }
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/cpu_load_tests/cpu_load_test_globals.hpp b/test/cpu_load_tests/cpu_load_test_globals.hpp
new file mode 100644
index 0000000..e5e8466
--- /dev/null
+++ b/test/cpu_load_tests/cpu_load_test_globals.hpp
@@ -0,0 +1,18 @@
+// 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/.
+
+#pragma once
+
+namespace cpu_load_test {
+
+static constexpr vsomeip::service_t service_id(0x1111);
+static constexpr vsomeip::instance_t instance_id(0x1);
+static constexpr vsomeip::method_t method_id(0x1111);
+static constexpr vsomeip::byte_t load_test_data(0xDD);
+static constexpr vsomeip::length_t default_payload_length(40);
+static constexpr vsomeip::method_t method_id_shutdown(0x7777);
+static constexpr vsomeip::method_t method_id_cpu_measure_start(0x8888);
+static constexpr vsomeip::method_t method_id_cpu_measure_stop(0x9999);
+}
diff --git a/test/cpu_load_tests/cpu_load_test_master_starter.sh b/test/cpu_load_tests/cpu_load_test_master_starter.sh
new file mode 100755
index 0000000..bc135fc
--- /dev/null
+++ b/test/cpu_load_tests/cpu_load_test_master_starter.sh
@@ -0,0 +1,70 @@
+#!/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
+
+export VSOMEIP_CONFIGURATION=cpu_load_test_client_master.json
+./cpu_load_test_client --protocol UDP --calls 1000 &
+
+sleep 1
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Please now run:
+** cpu_load_test_slave_starter.sh
+** from an external host to successfully complete this test.
+**
+** You probably will need to adapt the 'unicast' settings in
+** cpu_load_test_client_master.json,
+** cpu_load_test_service_master.json,
+** cpu_load_test_client_client.json and
+** cpu_load_test_service_client.json to your personal setup.
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+for job in $(jobs -p)
+do
+ # Fail gets incremented if either client or service exit
+ # with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+sleep 4
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Now switching roles and running service on this host
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+export VSOMEIP_CONFIGURATION=cpu_load_test_service_master.json
+./cpu_load_test_service &
+sleep 1
+
+for job in $(jobs -p)
+do
+ # Fail gets incremented if either client or service exit
+ # with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/cpu_load_tests/cpu_load_test_service.cpp b/test/cpu_load_tests/cpu_load_test_service.cpp
new file mode 100644
index 0000000..6eb0c81
--- /dev/null
+++ b/test/cpu_load_tests/cpu_load_test_service.cpp
@@ -0,0 +1,204 @@
+// 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 <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <functional>
+#include <numeric>
+#include <cmath> // for isfinite
+
+#include "cpu_load_test_globals.hpp"
+#include "../../implementation/logging/include/logger.hpp"
+#include "cpu_load_measurer.hpp"
+
+// for getpid
+#include <sys/types.h>
+#include <unistd.h>
+
+class cpu_load_test_service
+{
+public:
+ cpu_load_test_service() :
+ app_(vsomeip::runtime::get()->create_application("cpu_load_test_service")),
+ is_registered_(false),
+ blocked_(false),
+ number_of_received_messages_(0),
+ number_of_received_messages_total_(0),
+ load_measurer_(::getpid()),
+ offer_thread_(std::bind(&cpu_load_test_service::run, this))
+ {
+ }
+
+ void init()
+ {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+
+ app_->init();
+ app_->register_message_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id, cpu_load_test::method_id,
+ std::bind(&cpu_load_test_service::on_message, this,
+ std::placeholders::_1));
+
+ app_->register_message_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id, cpu_load_test::method_id_shutdown,
+ std::bind(&cpu_load_test_service::on_message_shutdown, this,
+ std::placeholders::_1));
+ app_->register_message_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id, cpu_load_test::method_id_cpu_measure_start,
+ std::bind(&cpu_load_test_service::on_message_start_measuring, this,
+ std::placeholders::_1));
+ app_->register_message_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id, cpu_load_test::method_id_cpu_measure_stop,
+ std::bind(&cpu_load_test_service::on_message_stop_measuring, this,
+ std::placeholders::_1));
+ app_->register_state_handler(
+ std::bind(&cpu_load_test_service::on_state, this,
+ std::placeholders::_1));
+ }
+
+ void start()
+ {
+ VSOMEIP_INFO << "Starting...";
+ app_->start();
+ }
+
+ void stop()
+ {
+ VSOMEIP_INFO << "Stopping...";
+ app_->stop_offer_service(cpu_load_test::service_id, cpu_load_test::instance_id);
+ app_->unregister_message_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id, cpu_load_test::method_id);
+ app_->unregister_message_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id, cpu_load_test::method_id_shutdown);
+ app_->unregister_state_handler();
+ app_->stop();
+ }
+
+ void join_offer_thread()
+ {
+ offer_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)
+ {
+ if(!is_registered_)
+ {
+ is_registered_ = true;
+ blocked_ = true;
+ // "start" the run method thread
+ condition_.notify_one();
+ }
+ }
+ else
+ {
+ is_registered_ = false;
+ }
+ }
+
+ void on_message(const std::shared_ptr<vsomeip::message>& _request)
+ {
+ number_of_received_messages_++;
+ number_of_received_messages_total_++;
+ // send response
+ app_->send(vsomeip::runtime::get()->create_response(_request), true);
+ }
+
+ void on_message_start_measuring(const std::shared_ptr<vsomeip::message>& _request)
+ {
+ (void)_request;
+ load_measurer_.start();
+ }
+
+ void on_message_stop_measuring(const std::shared_ptr<vsomeip::message>& _request)
+ {
+ (void)_request;
+ load_measurer_.stop();
+ VSOMEIP_DEBUG << "Received " << std::setw(4) << std::setfill('0')
+ << number_of_received_messages_ << " messages. CPU load [%]: "
+ << std::fixed << std::setprecision(2)
+ << (std::isfinite(load_measurer_.get_cpu_load()) ? load_measurer_.get_cpu_load() : 0.0);
+ results_.push_back(std::isfinite(load_measurer_.get_cpu_load()) ? load_measurer_.get_cpu_load() : 0.0);
+ number_of_received_messages_ = 0;
+ }
+
+ void on_message_shutdown(
+ const std::shared_ptr<vsomeip::message>& _request)
+ {
+ (void)_request;
+ VSOMEIP_INFO << "Shutdown method was called, going down now.";
+ const double average_load(std::accumulate(results_.begin(), results_.end(), 0.0) / static_cast<double>(results_.size()));
+ VSOMEIP_INFO << "Received: " << number_of_received_messages_total_
+ << " in total (excluding control messages). This caused: "
+ << std::fixed << std::setprecision(2)
+ << average_load << "% load in average (average of "
+ << results_.size() << " measurements).";
+
+ std::vector<double> results_no_zero;
+ for(const auto &v : results_) {
+ if(v > 0.0) {
+ results_no_zero.push_back(v);
+ }
+ }
+ const double average_load_no_zero(std::accumulate(results_no_zero.begin(), results_no_zero.end(), 0.0) / static_cast<double>(results_no_zero.size()));
+ VSOMEIP_INFO << "Sent: " << number_of_received_messages_total_
+ << " messages in total (excluding control messages). This caused: "
+ << std::fixed << std::setprecision(2)
+ << average_load_no_zero << "% load in average, if measured cpu load "
+ << "was greater zero (average of "
+ << results_no_zero.size() << " measurements).";
+ stop();
+ }
+
+ void run()
+ {
+ std::unique_lock<std::mutex> its_lock(mutex_);
+ while (!blocked_) {
+ condition_.wait(its_lock);
+ }
+
+ app_->offer_service(cpu_load_test::service_id, cpu_load_test::instance_id);
+ }
+
+private:
+ std::shared_ptr<vsomeip::application> app_;
+ bool is_registered_;
+
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ bool blocked_;
+ std::uint32_t number_of_received_messages_;
+ std::uint32_t number_of_received_messages_total_;
+ cpu_load_measurer load_measurer_;
+ std::vector<double> results_;
+ std::thread offer_thread_;
+};
+
+
+TEST(someip_payload_test, send_response_for_every_request)
+{
+ cpu_load_test_service test_service;
+ test_service.init();
+ test_service.start();
+ test_service.join_offer_thread();
+}
+
+#ifndef WIN32
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/cpu_load_tests/cpu_load_test_slave_starter.sh b/test/cpu_load_tests/cpu_load_test_slave_starter.sh
new file mode 100755
index 0000000..e6731b7
--- /dev/null
+++ b/test/cpu_load_tests/cpu_load_test_slave_starter.sh
@@ -0,0 +1,52 @@
+#!/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
+
+export VSOMEIP_CONFIGURATION=cpu_load_test_service_slave.json
+./cpu_load_test_service &
+
+# Wait until all applications are finished
+for job in $(jobs -p)
+do
+ # Fail gets incremented if one of the binaries exits
+ # with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Now switching roles and running client on this host
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+sleep 4
+export VSOMEIP_CONFIGURATION=cpu_load_test_client_slave.json
+./cpu_load_test_client --protocol UDP --calls 1000 &
+
+for job in $(jobs -p)
+do
+ # Fail gets incremented if one of the binaries exits
+ # with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/header_factory_tests/header_factory_test.cpp b/test/header_factory_tests/header_factory_test.cpp
index c3b8c32..c02fd74 100644
--- a/test/header_factory_tests/header_factory_test.cpp
+++ b/test/header_factory_tests/header_factory_test.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/header_factory_tests/header_factory_test_client.cpp b/test/header_factory_tests/header_factory_test_client.cpp
index 3f9eb4f..dc4a041 100644
--- a/test/header_factory_tests/header_factory_test_client.cpp
+++ b/test/header_factory_tests/header_factory_test_client.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/header_factory_tests/header_factory_test_client.hpp b/test/header_factory_tests/header_factory_test_client.hpp
index a68627e..1b96edd 100644
--- a/test/header_factory_tests/header_factory_test_client.hpp
+++ b/test/header_factory_tests/header_factory_test_client.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/header_factory_tests/header_factory_test_service.cpp b/test/header_factory_tests/header_factory_test_service.cpp
index 9879b48..4d45d9f 100644
--- a/test/header_factory_tests/header_factory_test_service.cpp
+++ b/test/header_factory_tests/header_factory_test_service.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/header_factory_tests/header_factory_test_service.hpp b/test/header_factory_tests/header_factory_test_service.hpp
index 99f5b09..b58a29b 100644
--- a/test/header_factory_tests/header_factory_test_service.hpp
+++ b/test/header_factory_tests/header_factory_test_service.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/magic_cookies_tests/magic_cookies_test_client.cpp b/test/magic_cookies_tests/magic_cookies_test_client.cpp
index e2f1396..1b61e60 100644
--- a/test/magic_cookies_tests/magic_cookies_test_client.cpp
+++ b/test/magic_cookies_tests/magic_cookies_test_client.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
@@ -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);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
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);
+ its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true, true, false);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
stop();
diff --git a/test/magic_cookies_tests/magic_cookies_test_client_start.sh b/test/magic_cookies_tests/magic_cookies_test_client_start.sh
index ba4f662..2ebe8c1 100755
--- a/test/magic_cookies_tests/magic_cookies_test_client_start.sh
+++ b/test/magic_cookies_tests/magic_cookies_test_client_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/magic_cookies_tests/magic_cookies_test_service.cpp b/test/magic_cookies_tests/magic_cookies_test_service.cpp
index 35e1d77..daa0fce 100644
--- a/test/magic_cookies_tests/magic_cookies_test_service.cpp
+++ b/test/magic_cookies_tests/magic_cookies_test_service.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/magic_cookies_tests/magic_cookies_test_service_start.sh b/test/magic_cookies_tests/magic_cookies_test_service_start.sh
index 4261ed5..00c6546 100755
--- a/test/magic_cookies_tests/magic_cookies_test_service_start.sh
+++ b/test/magic_cookies_tests/magic_cookies_test_service_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/magic_cookies_tests/magic_cookies_test_starter.sh b/test/magic_cookies_tests/magic_cookies_test_starter.sh
index e4308cd..57efc67 100755
--- a/test/magic_cookies_tests/magic_cookies_test_starter.sh
+++ b/test/magic_cookies_tests/magic_cookies_test_starter.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/payload_tests/external_local_payload_test_client_external_start.sh b/test/payload_tests/external_local_payload_test_client_external_start.sh
index 2ca6816..06babd4 100755
--- a/test/payload_tests/external_local_payload_test_client_external_start.sh
+++ b/test/payload_tests/external_local_payload_test_client_external_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/payload_tests/external_local_payload_test_client_external_starter.sh b/test/payload_tests/external_local_payload_test_client_external_starter.sh
index 225adba..87a70a6 100755
--- a/test/payload_tests/external_local_payload_test_client_external_starter.sh
+++ b/test/payload_tests/external_local_payload_test_client_external_starter.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/payload_tests/external_local_payload_test_client_local_and_external_starter.sh b/test/payload_tests/external_local_payload_test_client_local_and_external_starter.sh
index ba0bf15..1464bf9 100755
--- a/test/payload_tests/external_local_payload_test_client_local_and_external_starter.sh
+++ b/test/payload_tests/external_local_payload_test_client_local_and_external_starter.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/payload_tests/external_local_payload_test_client_local_start.sh b/test/payload_tests/external_local_payload_test_client_local_start.sh
index 87b9296..d3a1f04 100755
--- a/test/payload_tests/external_local_payload_test_client_local_start.sh
+++ b/test/payload_tests/external_local_payload_test_client_local_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/payload_tests/external_local_payload_test_client_local_starter.sh b/test/payload_tests/external_local_payload_test_client_local_starter.sh
index 6fda55a..fcc8a20 100755
--- a/test/payload_tests/external_local_payload_test_client_local_starter.sh
+++ b/test/payload_tests/external_local_payload_test_client_local_starter.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/payload_tests/external_local_payload_test_service_client_external_start.sh b/test/payload_tests/external_local_payload_test_service_client_external_start.sh
index a41fd9d..e668cbc 100755
--- a/test/payload_tests/external_local_payload_test_service_client_external_start.sh
+++ b/test/payload_tests/external_local_payload_test_service_client_external_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/payload_tests/external_local_payload_test_service_start.sh b/test/payload_tests/external_local_payload_test_service_start.sh
index 45fbcc2..e5bfe2b 100755
--- a/test/payload_tests/external_local_payload_test_service_start.sh
+++ b/test/payload_tests/external_local_payload_test_service_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/payload_tests/local_payload_test_client_start.sh b/test/payload_tests/local_payload_test_client_start.sh
index ac157bc..87ec43d 100755
--- a/test/payload_tests/local_payload_test_client_start.sh
+++ b/test/payload_tests/local_payload_test_client_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/payload_tests/local_payload_test_service_start.sh b/test/payload_tests/local_payload_test_service_start.sh
index 8173a94..34fbc80 100755
--- a/test/payload_tests/local_payload_test_service_start.sh
+++ b/test/payload_tests/local_payload_test_service_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/payload_tests/local_payload_test_starter.sh b/test/payload_tests/local_payload_test_starter.sh
index a2bc3d4..489f42f 100755
--- a/test/payload_tests/local_payload_test_starter.sh
+++ b/test/payload_tests/local_payload_test_starter.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/payload_tests/payload_test_client.cpp b/test/payload_tests/payload_test_client.cpp
index 41bd577..bea774e 100644
--- a/test/payload_tests/payload_test_client.cpp
+++ b/test/payload_tests/payload_test_client.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/payload_tests/payload_test_client.hpp b/test/payload_tests/payload_test_client.hpp
index ca1b58c..7f9f9e5 100644
--- a/test/payload_tests/payload_test_client.hpp
+++ b/test/payload_tests/payload_test_client.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/payload_tests/payload_test_service.cpp b/test/payload_tests/payload_test_service.cpp
index 2a92064..90fd476 100644
--- a/test/payload_tests/payload_test_service.cpp
+++ b/test/payload_tests/payload_test_service.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/payload_tests/payload_test_service.hpp b/test/payload_tests/payload_test_service.hpp
index b272e66..098543a 100644
--- a/test/payload_tests/payload_test_service.hpp
+++ b/test/payload_tests/payload_test_service.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/payload_tests/stopwatch.cpp b/test/payload_tests/stopwatch.cpp
index 4911f1c..2eb59f3 100644
--- a/test/payload_tests/stopwatch.cpp
+++ b/test/payload_tests/stopwatch.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/payload_tests/stopwatch.hpp b/test/payload_tests/stopwatch.hpp
index 0cdc078..9723c22 100644
--- a/test/payload_tests/stopwatch.hpp
+++ b/test/payload_tests/stopwatch.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/readme.txt b/test/readme.txt
index ab643e5..2e8c240 100644
--- a/test/readme.txt
+++ b/test/readme.txt
@@ -315,8 +315,8 @@ This tests tests communication over two nodes with multiple services on both
nodes.
The test setup is as followed:
-* There are five services with one method each.
-* Two of the services run on node 1.
+* There are six services with one method each.
+* Three of the services run on node 1.
* Three of the services run on node 2.
* Each of the services sends ten requests to the other services and waits
until it received a response for every request.
@@ -339,3 +339,54 @@ ctest -V -R client_id_test_diff_client_ids_same_ports
Manual start from sub folder test of build directory:
./client_id_test_master_starter.sh client_id_test_diff_client_ids_same_ports_master.json
+
+
+Subscribe notify tests
+----------------------
+This tests tests subscribe notify 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.
+* Each of the services waits until all other services are available.
+* Each of the services subscribes to the offered event of all the other services.
+* Each of the services then waits until the other services have subscribed to
+ its event.
+* Each of the services then starts to sent out ten notifications for its event.
+* Each service waits until it received the correct amount of notifications from
+ all other services.
+* If all notifications have been received, the service shuts down.
+
+Automatic start from the build directory (example):
+
+ctest -V -R subscribe_notify_test_diff_client_ids_diff_ports_udp
+
+Manual start from sub folder test of build directory:
+
+./subscribe_notify_test_master_starter.sh UDP subscribe_notify_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.
+
+
+CPU load test
+-------------
+This test does a increasing number of synchronous function calls to the same
+method of the service and measures CPU load for each batch of function calls.
+All method calls transport a payload of 40 Bytes. The responses don't transport
+any payload.
+
+The CPU load is measured thorugh the proc fs.
+If the test prints a message like:
+
+ Synchronously sent 0890 messages. CPU load [%]: 12.68
+
+This means that the test process consumed 12% of the jiffies consumed by
+complete system while doing 890 methodcalls.
+
+Automatic start from the build directory (example):
+
+ctest -V -R cpu_load_test
diff --git a/test/routing_tests/external_local_routing_test_client_external_start.sh b/test/routing_tests/external_local_routing_test_client_external_start.sh
index a40dece..05bb510 100755
--- a/test/routing_tests/external_local_routing_test_client_external_start.sh
+++ b/test/routing_tests/external_local_routing_test_client_external_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/routing_tests/external_local_routing_test_service.cpp b/test/routing_tests/external_local_routing_test_service.cpp
index 72899fd..745435f 100644
--- a/test/routing_tests/external_local_routing_test_service.cpp
+++ b/test/routing_tests/external_local_routing_test_service.cpp
@@ -1,5 +1,4 @@
-// Copyright (C) 2014 BMW Group
-// Author: Lutz Bichler (lutz.bichler@bmw.de)
+// 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/.
@@ -134,7 +133,9 @@ void external_local_routing_test_service::on_message(
if(number_received_messages_local_ >= vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND
&& number_received_messages_external_ >= vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND)
{
- app_->stop();
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ blocked_ = true;
+ condition_.notify_one();
}
ASSERT_LT(number_received_messages_local_,
vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND + 1);
@@ -148,10 +149,19 @@ void external_local_routing_test_service::run()
while (!blocked_)
condition_.wait(its_lock);
+ blocked_ = false;
if(use_static_routing_)
{
offer();
}
+
+ while (!blocked_) {
+ condition_.wait(its_lock);
+ }
+
+ std::thread t2([](){ usleep(1000000 * 2);});
+ t2.join();
+ app_->stop();
}
TEST(someip_external_local_routing_test, receive_ten_messages_over_local_and_external_socket)
diff --git a/test/routing_tests/external_local_routing_test_service.hpp b/test/routing_tests/external_local_routing_test_service.hpp
index 82f6220..f1e73b9 100644
--- a/test/routing_tests/external_local_routing_test_service.hpp
+++ b/test/routing_tests/external_local_routing_test_service.hpp
@@ -1,5 +1,4 @@
-// Copyright (C) 2014 BMW Group
-// Author: Lutz Bichler (lutz.bichler@bmw.de)
+// 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/.
diff --git a/test/routing_tests/external_local_routing_test_service_start.sh b/test/routing_tests/external_local_routing_test_service_start.sh
index e6ac677..c79428d 100755
--- a/test/routing_tests/external_local_routing_test_service_start.sh
+++ b/test/routing_tests/external_local_routing_test_service_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/routing_tests/external_local_routing_test_starter.sh b/test/routing_tests/external_local_routing_test_starter.sh
index abee34d..36a85e6 100755
--- a/test/routing_tests/external_local_routing_test_starter.sh
+++ b/test/routing_tests/external_local_routing_test_starter.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/routing_tests/local_routing_test_client.cpp b/test/routing_tests/local_routing_test_client.cpp
index 0659e48..a97c63c 100644
--- a/test/routing_tests/local_routing_test_client.cpp
+++ b/test/routing_tests/local_routing_test_client.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/routing_tests/local_routing_test_client.hpp b/test/routing_tests/local_routing_test_client.hpp
index 311b6eb..cb30667 100644
--- a/test/routing_tests/local_routing_test_client.hpp
+++ b/test/routing_tests/local_routing_test_client.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/routing_tests/local_routing_test_client_start.sh b/test/routing_tests/local_routing_test_client_start.sh
index 1c9cad9..cd36c77 100755
--- a/test/routing_tests/local_routing_test_client_start.sh
+++ b/test/routing_tests/local_routing_test_client_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/routing_tests/local_routing_test_service.cpp b/test/routing_tests/local_routing_test_service.cpp
index 7e04f01..90e7eed 100644
--- a/test/routing_tests/local_routing_test_service.cpp
+++ b/test/routing_tests/local_routing_test_service.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/routing_tests/local_routing_test_service.hpp b/test/routing_tests/local_routing_test_service.hpp
index 8cd4fb9..f78d5b0 100644
--- a/test/routing_tests/local_routing_test_service.hpp
+++ b/test/routing_tests/local_routing_test_service.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/routing_tests/local_routing_test_service_start.sh b/test/routing_tests/local_routing_test_service_start.sh
index acafd51..3536212 100755
--- a/test/routing_tests/local_routing_test_service_start.sh
+++ b/test/routing_tests/local_routing_test_service_start.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/routing_tests/local_routing_test_starter.sh b/test/routing_tests/local_routing_test_starter.sh
index 97bd67d..fd82594 100755
--- a/test/routing_tests/local_routing_test_starter.sh
+++ b/test/routing_tests/local_routing_test_starter.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# 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/.
diff --git a/test/someip_test_globals.hpp b/test/someip_test_globals.hpp
index d95e7de..fcde342 100644
--- a/test/someip_test_globals.hpp
+++ b/test/someip_test_globals.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// 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/.
diff --git a/test/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master.json.in b/test/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master.json.in
new file mode 100644
index 0000000..27cc8c4
--- /dev/null
+++ b/test/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master.json.in
@@ -0,0 +1,74 @@
+{
+ "unicast":"@TEST_IP_MASTER@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"subscribe_notify_one_test_service_one",
+ "id":"0x1111"
+ },
+ {
+ "name":"subscribe_notify_one_test_service_two",
+ "id":"0x2222"
+ },
+ {
+ "name":"subscribe_notify_one_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"
+ }
+ }
+ ],
+ "routing":"subscribe_notify_one_test_service_one",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ },
+ "supports_selective_broadcasts" :
+ {
+ "address" : "@TEST_IP_SLAVE@"
+ }
+} \ No newline at end of file
diff --git a/test/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json.in b/test/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json.in
new file mode 100644
index 0000000..1541410
--- /dev/null
+++ b/test/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json.in
@@ -0,0 +1,74 @@
+{
+ "unicast":"@TEST_IP_SLAVE@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true",
+ "file":
+ {
+ "enable":"false",
+ "path":"/tmp/vsomeip.log"
+ },
+ "dlt":"false"
+ },
+ "applications":
+ [
+ {
+ "name":"subscribe_notify_one_test_service_four",
+ "id":"0x4444"
+ },
+ {
+ "name":"subscribe_notify_one_test_service_five",
+ "id":"0x5555"
+ },
+ {
+ "name":"subscribe_notify_one_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"
+ }
+ }
+ ],
+ "routing":"subscribe_notify_one_test_service_four",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.0.1",
+ "port":"30490",
+ "protocol":"udp"
+ },
+ "supports_selective_broadcasts" :
+ {
+ "address" : "@TEST_IP_MASTER@"
+ }
+} \ No newline at end of file
diff --git a/test/subscribe_notify_one_tests/subscribe_notify_one_test_globals.hpp b/test/subscribe_notify_one_tests/subscribe_notify_one_test_globals.hpp
new file mode 100644
index 0000000..8f4205f
--- /dev/null
+++ b/test/subscribe_notify_one_tests/subscribe_notify_one_test_globals.hpp
@@ -0,0 +1,35 @@
+// 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 subscribe_notify_one_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 int notifications_to_send = 10;
+}
+
+#endif /* SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ */
diff --git a/test/subscribe_notify_one_tests/subscribe_notify_one_test_master_starter.sh b/test/subscribe_notify_one_tests/subscribe_notify_one_test_master_starter.sh
new file mode 100755
index 0000000..f85aa6c
--- /dev/null
+++ b/test/subscribe_notify_one_tests/subscribe_notify_one_test_master_starter.sh
@@ -0,0 +1,93 @@
+#!/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 subscribe_notify_one_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 subscribe_notify_one_test_diff_client_ids_diff_ports_master.json"
+ exit 1
+fi
+
+# 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 == $1 ]
+ 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=$2
+CLIENT_JSON_FILE=${MASTER_JSON_FILE/master/slave}
+
+FAIL=0
+
+# Start the services
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_one
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_one_test_service 1 $1 &
+
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_two
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_one_test_service 2 $1 &
+
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_three
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_one_test_service 3 $1 &
+
+sleep 1
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Please now run:
+** subscribe_notify_one_test_slave_starter.sh $1 $CLIENT_JSON_FILE
+** from an external host to successfully complete this test.
+**
+** You probably will need to adapt the 'unicast' settings in
+** subscribe_notify_one_test_diff_client_ids_diff_ports_master.json and
+** subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json to your personal setup.
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+# Wait until client and service are finished
+for job in $(jobs -p)
+do
+ # Fail gets incremented if either client or service exit
+ # with a non-zero exit code
+ wait $job || ((FAIL+=1))
+done
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
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
new file mode 100644
index 0000000..744a322
--- /dev/null
+++ b/test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp
@@ -0,0 +1,442 @@
+// 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 <unordered_set>
+
+#include <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+#include "../../implementation/logging/include/logger.hpp"
+
+#include "subscribe_notify_one_test_globals.hpp"
+
+
+class subscribe_notify_one_test_service {
+public:
+ subscribe_notify_one_test_service(struct subscribe_notify_one_test::service_info _service_info,
+ vsomeip::subscription_type_e _subscription_type) :
+ service_info_(_service_info),
+ subscription_type_(_subscription_type),
+ app_(vsomeip::runtime::get()->create_application()),
+ wait_until_registered_(true),
+ wait_until_other_services_available_(true),
+ wait_until_notified_from_other_services_(true),
+ 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();
+ app_->register_state_handler(
+ std::bind(&subscribe_notify_one_test_service::on_state, this,
+ std::placeholders::_1));
+
+ // offer event
+ 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);
+
+ app_->register_message_handler(service_info_.service_id,
+ service_info_.instance_id, service_info_.method_id,
+ std::bind(&subscribe_notify_one_test_service::on_request, this,
+ std::placeholders::_1));
+
+ // register subscription handler to detect whether or not all other
+ // other services have subscribed
+ app_->register_subscription_handler(service_info_.service_id,
+ service_info_.instance_id, service_info_.eventgroup_id,
+ std::bind(&subscribe_notify_one_test_service::on_subscription, this,
+ std::placeholders::_1, std::placeholders::_2));
+
+ // register availability for all other services and request their event.
+ for(const auto& i : subscribe_notify_one_test::service_infos) {
+ if ((i.service_id == service_info_.service_id
+ && i.instance_id == service_info_.instance_id)
+ || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) {
+ continue;
+ }
+ app_->register_message_handler(i.service_id,
+ i.instance_id, vsomeip::ANY_METHOD,
+ std::bind(&subscribe_notify_one_test_service::on_message, this,
+ std::placeholders::_1));
+ app_->register_availability_handler(i.service_id, i.instance_id,
+ std::bind(&subscribe_notify_one_test_service::on_availability, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+
+ std::set<vsomeip::eventgroup_t> its_eventgroups;
+ its_eventgroups.insert(i.eventgroup_id);
+ app_->request_event(i.service_id, i.instance_id, i.event_id, its_eventgroups, false);
+
+ 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_->start();
+ }
+
+ ~subscribe_notify_one_test_service() {
+ offer_thread_.join();
+ stop_thread_.join();
+ notify_thread_.join();
+ }
+
+ void offer() {
+ app_->offer_service(service_info_.service_id, service_info_.instance_id);
+ }
+
+ void stop_offer() {
+ app_->stop_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 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_INFO << "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(mutex_);
+ wait_until_other_services_available_ = false;
+ condition_.notify_one();
+ }
+ }
+ }
+
+ 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
+
+ if (subscribers_.size() == subscribe_notify_one_test::service_infos.size() - 2) {
+ return true;
+ }
+
+ 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 << 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
+ std::lock_guard<std::mutex> its_lock(notify_mutex_);
+ wait_for_notify_ = false;
+ notify_condition_.notify_one();
+ }
+ return true;
+ }
+
+ void on_request(const std::shared_ptr<vsomeip::message> &_message) {
+ if(_message->get_message_type() == vsomeip::message_type_e::MT_REQUEST) {
+ 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() << "]";
+ std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get()
+ ->create_response(_message);
+ app_->send(its_response);
+ }
+ }
+
+ 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
+ << service_info_.service_id << "] "
+ << "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())] << ")";
+
+
+ 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 == subscribe_notify_one_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 == subscribe_notify_one_test::notifications_to_send * 2) {
+ received_twice++;
+ } else if(v.second == subscribe_notify_one_test::notifications_to_send) {
+ received_normal++;
+ }
+ }
+
+ if( received_twice == (subscribe_notify_one_test::service_infos.size() - 1) / 2
+ && received_normal == (subscribe_notify_one_test::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
+ << service_info_.service_id << "] "
+ << "Received notifications:"
+ << " Normal: " << received_normal
+ << " Twice: " << received_twice;
+ return true;
+ }
+ return false;
+ }
+
+ 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_other_services_available_) {
+ condition_.wait(its_lock);
+ }
+
+ 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_one_test::service_info& i: subscribe_notify_one_test::service_infos) {
+ if ((i.service_id == service_info_.service_id
+ && i.instance_id == service_info_.instance_id)
+ || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) {
+ continue;
+ }
+
+ app_->request_service(i.service_id, i.instance_id, vsomeip::DEFAULT_MAJOR, vsomeip::DEFAULT_MINOR, true);
+
+ app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id,
+ vsomeip::DEFAULT_MAJOR, subscription_type_);
+
+ VSOMEIP_DEBUG << "[" << std::hex << service_info_.service_id
+ << "] subscribing to Service/Instance/Eventgroup ["
+ << std::setw(4) << std::setfill('0') << std::hex << i.service_id << "/"
+ << std::setw(4) << std::setfill('0') << std::hex << i.instance_id
+ << "/" << std::setw(4) << std::setfill('0') << std::hex << i.eventgroup_id <<"]";
+
+ }
+
+ while (wait_until_notified_from_other_services_) {
+ condition_.wait(its_lock);
+ }
+ }
+
+ void notify_one() {
+ std::unique_lock<std::mutex> its_lock(notify_mutex_);
+ while(wait_for_notify_) {
+ notify_condition_.wait(its_lock);
+ }
+
+ // sleep a while before starting to notify this is necessary as it's not
+ // possible to detect if _all_ clients on the remote side have
+ // 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));
+
+ VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id << "] Starting to notify";
+
+ for(uint32_t i = 0; i < subscribe_notify_one_test::notifications_to_send; i++) {
+ std::shared_ptr<vsomeip::payload> its_payload =
+ vsomeip::runtime::get()->create_payload();
+
+ vsomeip::byte_t its_data[10] = {0};
+ for (uint32_t j = 0; j < i+1; ++j) {
+ its_data[j] = static_cast<uint8_t>(j);
+ }
+ its_payload->set_data(its_data, i+1);
+
+ for (vsomeip::client_t client : subscribers_) {
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id << "] Notifying client: "
+ << client << " : " << i+1;
+ app_->notify_one(service_info_.service_id, service_info_.instance_id,
+ service_info_.event_id, its_payload, client);
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+ }
+ }
+
+ 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
+ << "] Received notifications from all other services, going down";
+
+ // let offer thread exit
+ {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_until_notified_from_other_services_ = false;
+ condition_.notify_one();
+ }
+
+ std::this_thread::sleep_for(std::chrono::seconds(6));
+ app_->stop();
+ }
+
+private:
+ subscribe_notify_one_test::service_info service_info_;
+ 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_;
+ bool wait_until_notified_from_other_services_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::thread offer_thread_;
+
+ bool wait_for_stop_;
+ std::mutex stop_mutex_;
+ 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_;
+ std::thread notify_thread_;
+
+ std::unordered_set<vsomeip::client_t> subscribers_;
+};
+
+static int service_number;
+static vsomeip::subscription_type_e subscription_type;
+
+TEST(someip_subscribe_notify_one_test, send_ten_notifications_to_service)
+{
+ subscribe_notify_one_test_service its_sample(
+ subscribe_notify_one_test::service_infos[service_number], subscription_type);
+}
+
+#ifndef WIN32
+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 << "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;
+ return 1;
+ }
+
+ service_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;
+ }
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/subscribe_notify_one_tests/subscribe_notify_one_test_slave_starter.sh b/test/subscribe_notify_one_tests/subscribe_notify_one_test_slave_starter.sh
new file mode 100755
index 0000000..2bcde81
--- /dev/null
+++ b/test/subscribe_notify_one_tests/subscribe_notify_one_test_slave_starter.sh
@@ -0,0 +1,72 @@
+#!/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 subscribe_notify_one_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 subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json"
+ exit 1
+fi
+
+# 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 == $1 ]
+ 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
+# Start the services
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_four
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_one_test_service 4 $1 &
+
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_five
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_one_test_service 5 $1 &
+
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_six
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_one_test_service 6 $1 &
+
+# Wait until all applications are finished
+for job in $(jobs -p)
+do
+ # Fail gets incremented if one of the binaries exits
+ # with a non-zero exit code
+ wait $job || ((FAIL+=1))
+done
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master.json.in
new file mode 100644
index 0000000..a363388
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_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":"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"
+ }
+ }
+ ],
+ "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_slave.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave.json.in
new file mode 100644
index 0000000..7307fb2
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_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":"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"
+ }
+ }
+ ],
+ "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/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_master.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_master.json.in
new file mode 100644
index 0000000..8d8cfb0
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_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":"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"
+ }
+ }
+ ],
+ "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_partial_same_ports_slave.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_slave.json.in
new file mode 100644
index 0000000..b429266
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_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":"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"
+ }
+ }
+ ],
+ "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/conf/subscribe_notify_test_diff_client_ids_same_ports_master.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master.json.in
new file mode 100644
index 0000000..09788c9
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_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":"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"
+ }
+ }
+ ],
+ "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_same_ports_slave.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave.json.in
new file mode 100644
index 0000000..9c4d63c
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_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":"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"
+ }
+ }
+ ],
+ "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/conf/subscribe_notify_test_same_client_ids_diff_ports_master.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_master.json.in
new file mode 100644
index 0000000..a363388
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_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":"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"
+ }
+ }
+ ],
+ "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_same_client_ids_diff_ports_slave.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_slave.json.in
new file mode 100644
index 0000000..bc38eaf
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_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":"0x1111"
+ },
+ {
+ "name":"subscribe_notify_test_service_five",
+ "id":"0x2222"
+ },
+ {
+ "name":"subscribe_notify_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"
+ }
+ }
+ ],
+ "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/conf/subscribe_notify_test_same_client_ids_same_ports_master.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_master.json.in
new file mode 100644
index 0000000..09788c9
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_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":"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"
+ }
+ }
+ ],
+ "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_same_client_ids_same_ports_slave.json.in b/test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_slave.json.in
new file mode 100644
index 0000000..caed298
--- /dev/null
+++ b/test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_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":"0x1111"
+ },
+ {
+ "name":"subscribe_notify_test_service_five",
+ "id":"0x2222"
+ },
+ {
+ "name":"subscribe_notify_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"
+ }
+ }
+ ],
+ "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
new file mode 100644
index 0000000..0bf42d5
--- /dev/null
+++ b/test/subscribe_notify_tests/subscribe_notify_test_globals.hpp
@@ -0,0 +1,35 @@
+// 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 subscribe_notify_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 int notifications_to_send = 10;
+}
+
+#endif /* SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ */
diff --git a/test/subscribe_notify_tests/subscribe_notify_test_master_starter.sh b/test/subscribe_notify_tests/subscribe_notify_test_master_starter.sh
new file mode 100755
index 0000000..0d0f920
--- /dev/null
+++ b/test/subscribe_notify_tests/subscribe_notify_test_master_starter.sh
@@ -0,0 +1,93 @@
+#!/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 subscribe_notify_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 subscribe_notify_test_diff_client_ids_diff_ports_master.json"
+ exit 1
+fi
+
+# 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 == $1 ]
+ 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=$2
+CLIENT_JSON_FILE=${MASTER_JSON_FILE/master/slave}
+
+FAIL=0
+
+# Start the services
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_one
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_test_service 1 $1 &
+
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_two
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_test_service 2 $1 &
+
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_three
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_test_service 3 $1 &
+
+sleep 1
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Please now run:
+** subscribe_notify_test_slave_starter.sh $1 $CLIENT_JSON_FILE
+** from an external host to successfully complete this test.
+**
+** You probably will need to adapt the 'unicast' settings in
+** subscribe_notify_test_diff_client_ids_diff_ports_master.json and
+** subscribe_notify_test_diff_client_ids_diff_ports_slave.json to your personal setup.
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+# Wait until client and service are finished
+for job in $(jobs -p)
+do
+ # Fail gets incremented if either client or service exit
+ # with a non-zero exit code
+ wait $job || ((FAIL+=1))
+done
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/subscribe_notify_tests/subscribe_notify_test_service.cpp b/test/subscribe_notify_tests/subscribe_notify_test_service.cpp
new file mode 100644
index 0000000..9c967ef
--- /dev/null
+++ b/test/subscribe_notify_tests/subscribe_notify_test_service.cpp
@@ -0,0 +1,416 @@
+// 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 "subscribe_notify_test_globals.hpp"
+
+
+class subscribe_notify_test_service {
+public:
+ subscribe_notify_test_service(struct subscribe_notify_test::service_info _service_info,
+ vsomeip::subscription_type_e _subscription_type) :
+ service_info_(_service_info),
+ subscription_type_(_subscription_type),
+ app_(vsomeip::runtime::get()->create_application()),
+ wait_until_registered_(true),
+ wait_until_other_services_available_(true),
+ wait_until_notified_from_other_services_(true),
+ 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();
+ app_->register_state_handler(
+ std::bind(&subscribe_notify_test_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(&subscribe_notify_test_service::on_request, this,
+ std::placeholders::_1));
+ app_->register_message_handler(vsomeip::ANY_SERVICE,
+ service_info_.instance_id, vsomeip::ANY_METHOD,
+ std::bind(&subscribe_notify_test_service::on_message, this,
+ std::placeholders::_1));
+
+ // offer event
+ 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);
+
+
+ // register availability for all other services and request their event.
+ for(const auto& i : subscribe_notify_test::service_infos) {
+ if ((i.service_id == service_info_.service_id
+ && i.instance_id == service_info_.instance_id)
+ || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) {
+ continue;
+ }
+ app_->register_availability_handler(i.service_id, i.instance_id,
+ std::bind(&subscribe_notify_test_service::on_availability, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+
+ 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;
+ }
+
+ // register subscription handler to detect whether or not all other
+ // other services have subscribed
+ app_->register_subscription_handler(service_info_.service_id,
+ service_info_.instance_id, service_info_.eventgroup_id,
+ std::bind(&subscribe_notify_test_service::on_subscription, this,
+ std::placeholders::_1, std::placeholders::_2));
+
+ app_->start();
+ }
+
+ ~subscribe_notify_test_service() {
+ offer_thread_.join();
+ stop_thread_.join();
+ notify_thread_.join();
+ }
+
+ void offer() {
+ app_->offer_service(service_info_.service_id, service_info_.instance_id);
+ }
+
+ void stop_offer() {
+ app_->stop_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 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_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(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(mutex_);
+ wait_until_other_services_available_ = false;
+ condition_.notify_one();
+ }
+ }
+ }
+
+ bool on_subscription(vsomeip::client_t _client, bool _subscribed) {
+ (void)(_client);
+ _subscribed ? number_of_subscribers_++ : number_of_subscribers_--;
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id << "] " << "Client: " << _client
+ << " subscribed, now have " << std::dec << number_of_subscribers_
+ << " 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 )
+ {
+ // 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();
+ }
+ return true;
+ }
+
+ void on_request(const std::shared_ptr<vsomeip::message> &_message) {
+ if(_message->get_message_type() == vsomeip::message_type_e::MT_REQUEST) {
+ 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() << "]";
+ std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get()
+ ->create_response(_message);
+ app_->send(its_response);
+ }
+ }
+
+ 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
+ << service_info_.service_id << "] "
+ << "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())] << ")";
+
+ 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 == subscribe_notify_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 == subscribe_notify_test::notifications_to_send * 2) {
+ received_twice++;
+ } else if(v.second == subscribe_notify_test::notifications_to_send) {
+ received_normal++;
+ }
+ }
+
+ if( received_twice == (subscribe_notify_test::service_infos.size() - 1) / 2
+ && received_normal == (subscribe_notify_test::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
+ << service_info_.service_id << "] "
+ << "Received notifications:"
+ << " Normal: " << received_normal
+ << " Twice: " << received_twice;
+ return true;
+ }
+ return false;
+ }
+
+ 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_other_services_available_) {
+ condition_.wait(its_lock);
+ }
+
+ 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) {
+ 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_->subscribe(i.service_id, i.instance_id, i.eventgroup_id,
+ vsomeip::DEFAULT_MAJOR, subscription_type_);
+ VSOMEIP_DEBUG << "[" << std::hex << service_info_.service_id
+ << "] subscribing to Service/Instance/Eventgroup ["
+ << std::setw(4) << std::setfill('0') << std::hex << i.service_id << "/"
+ << std::setw(4) << std::setfill('0') << std::hex << i.instance_id
+ << "/" << std::setw(4) << std::setfill('0') << std::hex << i.eventgroup_id <<"]";
+ }
+
+ while (wait_until_notified_from_other_services_) {
+ condition_.wait(its_lock);
+ }
+ }
+
+ void notify() {
+ std::unique_lock<std::mutex> its_lock(notify_mutex_);
+ while(wait_for_notify_) {
+ notify_condition_.wait(its_lock);
+ }
+
+ // sleep a while before starting to notify this is necessary as it's not
+ // possible to detect if _all_ clients on the remote side have
+ // 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));
+
+ VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id << "] Starting to notify";
+
+ for(uint32_t i = 0; i < subscribe_notify_test::notifications_to_send; i++) {
+ std::shared_ptr<vsomeip::payload> its_payload =
+ vsomeip::runtime::get()->create_payload();
+
+ vsomeip::byte_t its_data[10] = {0};
+ for (uint32_t j = 0; j < i+1; ++j) {
+ its_data[j] = static_cast<uint8_t>(j);
+ }
+ its_payload->set_data(its_data, i+1);
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << 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));
+ }
+ }
+
+ 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
+ << "] Received notifications from all other services, going down";
+
+ // let offer thread exit
+ {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_until_notified_from_other_services_ = false;
+ condition_.notify_one();
+ }
+
+ std::this_thread::sleep_for(std::chrono::seconds(6));
+ app_->stop();
+ }
+
+private:
+ subscribe_notify_test::service_info service_info_;
+ 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_;
+ bool wait_until_notified_from_other_services_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::thread offer_thread_;
+
+ bool wait_for_stop_;
+ std::mutex stop_mutex_;
+ 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_;
+ std::thread notify_thread_;
+};
+
+static int service_number;
+static vsomeip::subscription_type_e subscription_type;
+
+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);
+}
+
+#ifndef WIN32
+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 << "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;
+ return 1;
+ }
+
+ service_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;
+ }
+ 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
new file mode 100755
index 0000000..887e2e4
--- /dev/null
+++ b/test/subscribe_notify_tests/subscribe_notify_test_slave_starter.sh
@@ -0,0 +1,72 @@
+#!/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 subscribe_notify_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 subscribe_notify_test_diff_client_ids_diff_ports_slave.json"
+ exit 1
+fi
+
+# 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 == $1 ]
+ 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
+# Start the services
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_four
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_test_service 4 $1 &
+
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_five
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_test_service 5 $1 &
+
+export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_six
+export VSOMEIP_CONFIGURATION=$2
+./subscribe_notify_test_service 6 $1 &
+
+# Wait until all applications are finished
+for job in $(jobs -p)
+do
+ # Fail gets incremented if one of the binaries exits
+ # with a non-zero exit code
+ wait $job || ((FAIL+=1))
+done
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644
index 0000000..7a56439
--- /dev/null
+++ b/tools/CMakeLists.txt
@@ -0,0 +1,18 @@
+# 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/.
+
+cmake_minimum_required (VERSION 2.8)
+
+# vsomeip_ctrl
+add_executable(vsomeip_ctrl EXCLUDE_FROM_ALL vsomeip_ctrl.cpp)
+target_link_libraries(vsomeip_ctrl
+ vsomeip
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+)
+
+###################################################################################################
+
diff --git a/tools/vsomeip_ctrl.cpp b/tools/vsomeip_ctrl.cpp
new file mode 100644
index 0000000..84faf00
--- /dev/null
+++ b/tools/vsomeip_ctrl.cpp
@@ -0,0 +1,429 @@
+// 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/.
+
+#include <vsomeip/vsomeip.hpp>
+#include "../implementation/configuration/include/internal.hpp"
+#include "../../implementation/logging/include/logger.hpp"
+#include "../implementation/service_discovery/include/constants.hpp"
+#include "../implementation/utility/include/byteorder.hpp"
+
+#include <cstdint>
+#include <thread>
+#include <cstring>
+#include <condition_variable>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+namespace vsomeip_ctrl {
+
+class vsomeip_sender {
+public:
+ vsomeip_sender(bool _use_tcp,
+ std::vector<vsomeip::byte_t> _user_message,
+ vsomeip::instance_t _instance) :
+ use_tcp_(_use_tcp),
+ user_message_(_user_message),
+ instance_(_instance),
+ app_(vsomeip::runtime::get()->create_application("vsomeip_ctrl")),
+ wait_registered_(true),
+ wait_service_available_(true),
+ send_thread_(std::bind(&vsomeip_sender::send, this)),
+ service_id_(0x0),
+ method_id_(0x0),
+ length_(0),
+ client_id_(0x0),
+ interface_version_(0x0),
+ message_type_(vsomeip::message_type_e::MT_UNKNOWN),
+ return_code_(vsomeip::return_code_e::E_UNKNOWN),
+ wait_for_answer_(true)
+ {
+ if (user_message_.size() < VSOMEIP_PAYLOAD_POS) {
+ VSOMEIP_ERROR << "Provided message is to short, min. length "
+ "is 16 Bytes, exiting.";
+ exit(EXIT_FAILURE);
+ }
+ service_id_ = VSOMEIP_BYTES_TO_WORD(user_message_[VSOMEIP_SERVICE_POS_MIN],
+ user_message_[VSOMEIP_SERVICE_POS_MAX]);
+ method_id_ = VSOMEIP_BYTES_TO_WORD(user_message_[VSOMEIP_METHOD_POS_MIN],
+ user_message_[VSOMEIP_METHOD_POS_MAX]);
+ length_ = VSOMEIP_BYTES_TO_LONG(user_message_[VSOMEIP_LENGTH_POS_MIN],
+ user_message_[VSOMEIP_LENGTH_POS_MIN+1],
+ user_message_[VSOMEIP_LENGTH_POS_MIN+2],
+ user_message_[VSOMEIP_LENGTH_POS_MAX]);
+ client_id_ = VSOMEIP_BYTES_TO_WORD(user_message_[VSOMEIP_CLIENT_POS_MIN],
+ user_message_[VSOMEIP_CLIENT_POS_MAX]);
+ interface_version_ = user_message_[VSOMEIP_INTERFACE_VERSION_POS];
+ message_type_ = static_cast<vsomeip::message_type_e>(user_message_[VSOMEIP_MESSAGE_TYPE_POS]);
+ return_code_ = static_cast<vsomeip::return_code_e>(user_message_[VSOMEIP_RETURN_CODE_POS]);
+
+ validate_message();
+
+ app_->init();
+ app_->register_state_handler(
+ std::bind(&vsomeip_sender::on_state, this,
+ std::placeholders::_1));
+ app_->register_message_handler(vsomeip::ANY_SERVICE,
+ vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD,
+ std::bind(&vsomeip_sender::on_message, this,
+ std::placeholders::_1));
+ app_->register_availability_handler(service_id_, instance_,
+ std::bind(&vsomeip_sender::on_availability, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+ app_->start();
+ };
+
+ void stop(int _exit_code) {
+ app_->stop();
+ exit(_exit_code);
+ }
+
+ ~vsomeip_sender() {
+ send_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) {
+ app_->request_service(service_id_, vsomeip::ANY_INSTANCE);
+ }
+ }
+
+ void on_availability(vsomeip::service_t _service,
+ vsomeip::instance_t _instance, bool _is_available) {
+ if(_is_available) {
+ VSOMEIP_INFO << "Service [" << std::setw(4) << std::setfill('0')
+ << std::hex << _service << "." << _instance << "] is available.";
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_service_available_ = false;
+ condition_.notify_one();
+ }
+ }
+
+ void on_message(const std::shared_ptr<vsomeip::message> &_response) {
+ VSOMEIP_INFO << "Received a response from Service [" << std::setw(4)
+ << std::setfill('0') << std::hex << _response->get_service()
+ << "." << 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()
+ << " # service id / instance id";
+ VSOMEIP_INFO << std::setw(8) << std::setfill('0') << std::hex
+ << _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()
+ << " # client id / session id";
+ VSOMEIP_INFO << std::setw(2) << std::setfill('0') << std::hex
+ << static_cast<std::uint16_t>(_response->get_protocol_version())
+ << std::setw(2) << std::setfill('0') << std::hex
+ << static_cast<std::uint16_t>(_response->get_interface_version())
+ << std::setw(2) << std::setfill('0') << std::hex
+ << static_cast<std::uint16_t>(_response->get_message_type())
+ << std::setw(2) << std::setfill('0') << std::hex
+ << static_cast<std::uint16_t>(_response->get_return_code())
+ << " # protocol version / interface version / "
+ << "message type / return code";
+
+
+ std::stringstream stream;
+ std::string str;
+ for(unsigned int i = 0; i < _response->get_payload()->get_length(); i++) {
+ stream << std::hex << std::setw(2) << std::setfill('0')
+ << static_cast<std::uint32_t>((_response->get_payload()->get_data())[i]);
+ str.append(stream.str());
+ stream.str("");
+ stream.clear();
+ }
+ std::string str2;
+ int k=1;
+ for(unsigned int j = 0; j < str.length(); j+=2, k++) {
+ str2.append(str.substr(j,2));
+ if(k%4 == 0) {
+ if(k == 4) {
+ VSOMEIP_INFO << str2 << " # payload from here on";
+ } else {
+ VSOMEIP_INFO << str2;
+ }
+ str2.clear();
+ }
+ }
+ VSOMEIP_INFO << "########## end message";
+ VSOMEIP_INFO << "Payload as byte stream: " << str;
+ str.clear();
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_for_answer_ = false;
+ condition_.notify_one();
+ }
+
+ void send() {
+ std::unique_lock<std::mutex> its_lock(mutex_);
+ while (wait_service_available_) {
+ if(std::cv_status::timeout == condition_.wait_for(its_lock, std::chrono::seconds(6))) {
+ VSOMEIP_INFO << "Service [" << std::setw(4) << std::setfill('0')
+ << std::hex << service_id_ << "." << instance_ << "] isn't available. Exiting";
+ stop(EXIT_FAILURE);
+ }
+ }
+
+ std::shared_ptr<vsomeip::message> its_message =
+ vsomeip::runtime::get()->create_message(use_tcp_);
+ its_message->set_method(method_id_);
+ its_message->set_service(service_id_);
+ its_message->set_interface_version(interface_version_);
+ its_message->set_message_type(message_type_);
+ its_message->set_return_code(return_code_);
+ its_message->set_client(app_->get_client());
+ its_message->set_instance(instance_);
+
+ std::shared_ptr< vsomeip::payload > its_payload =
+ vsomeip::runtime::get()->create_payload();
+ its_payload->set_data(&user_message_[VSOMEIP_PAYLOAD_POS],
+ static_cast<vsomeip::length_t>(user_message_.size() - VSOMEIP_PAYLOAD_POS));
+ its_message->set_payload(its_payload);
+ VSOMEIP_INFO << "Sending";
+ app_->send(its_message);
+
+ while(wait_for_answer_) {
+ if(std::cv_status::timeout == condition_.wait_for(its_lock, std::chrono::seconds(5))) {
+ VSOMEIP_INFO << "Didn't receive answer within 5sec. Shutting down.";
+ stop(EXIT_SUCCESS);
+ break;
+ }
+ }
+
+ stop(EXIT_SUCCESS);
+ }
+
+private:
+ bool validate_message() {
+ if (!check_message_type()) {
+ VSOMEIP_ERROR << "Invalid message type 0x" << std::setw(2)
+ << std::setfill('0') << std::hex
+ << static_cast<std::uint8_t>(message_type_) << ", exiting.";
+ stop(EXIT_FAILURE);
+ }
+
+ if(!check_return_code()) {
+ VSOMEIP_ERROR << "Invalid return code 0x" << std::setw(2)
+ << std::setfill('0') << std::hex
+ << static_cast<std::uint8_t>(return_code_) << ", exiting.";
+ stop(EXIT_FAILURE);
+ }
+
+ if (service_id_ == vsomeip::sd::service &&
+ method_id_ == vsomeip::sd::method) {
+ VSOMEIP_ERROR << "Usage of reserved service id and method id "
+ "of service discovery, exiting.";
+ stop(EXIT_FAILURE);
+ }
+
+ if (user_message_.size() != length_ + 8) {
+ VSOMEIP_ERROR << "Provided length 0x" << std::setw(8)
+ << std::setfill('0') << std::hex << length_
+ << " doesn't match message size.";
+ VSOMEIP_ERROR << "Assuming the same payload the length field should"
+ " be set to 0x" << std::setw(8) << std::setfill('0')
+ << std::hex << user_message_.size() - 8 << " , exiting.";
+ stop(EXIT_FAILURE);
+ }
+
+ if (use_tcp_ && user_message_.size() > VSOMEIP_MAX_TCP_MESSAGE_SIZE) {
+ VSOMEIP_WARNING << "Max allowed message size for TCP is "
+ << std::dec << VSOMEIP_MAX_TCP_MESSAGE_SIZE
+ << ". Provided message size is: " << user_message_.size();
+ }
+ if (!use_tcp_ && user_message_.size() > VSOMEIP_MAX_UDP_MESSAGE_SIZE) {
+ VSOMEIP_WARNING << "Max allowed message size for UDP is "
+ << std::dec << VSOMEIP_MAX_UDP_MESSAGE_SIZE
+ << ". Provided message size is: " << user_message_.size();
+ }
+ return true;
+ }
+
+ bool check_message_type() {
+ switch (message_type_) {
+ case vsomeip::message_type_e::MT_REQUEST:
+ case vsomeip::message_type_e::MT_REQUEST_NO_RETURN:
+ case vsomeip::message_type_e::MT_NOTIFICATION:
+ case vsomeip::message_type_e::MT_RESPONSE:
+ case vsomeip::message_type_e::MT_ERROR:
+ return true;
+ break;
+ case vsomeip::message_type_e::MT_UNKNOWN:
+ case vsomeip::message_type_e::MT_ERROR_ACK:
+ case vsomeip::message_type_e::MT_RESPONSE_ACK:
+ case vsomeip::message_type_e::MT_NOTIFICATION_ACK:
+ case vsomeip::message_type_e::MT_REQUEST_NO_RETURN_ACK:
+ case vsomeip::message_type_e::MT_REQUEST_ACK:
+ default:
+ return false;
+ break;
+ }
+ }
+
+ bool check_return_code() {
+ if (static_cast<std::uint8_t>(return_code_) > 0x3F) {
+ VSOMEIP_ERROR << "Provided return code 0x" << std::setw(2)
+ << std::setfill('0') << std::hex
+ << static_cast<std::uint8_t>(return_code_) << " is out of range.";
+ return false;
+ }
+ if (static_cast<std::uint8_t>(return_code_) >
+ static_cast<std::uint8_t>(vsomeip::return_code_e::E_WRONG_MESSAGE_TYPE) &&
+ static_cast<std::uint8_t>(return_code_) <= 0x3f) {
+ VSOMEIP_ERROR << "Provided return code 0x" << std::setw(2)
+ << std::setfill('0') << std::hex <<
+ static_cast<std::uint8_t>(return_code_) << "is reserved.";
+ return false;
+ }
+ switch (message_type_) {
+ case vsomeip::message_type_e::MT_REQUEST:
+ case vsomeip::message_type_e::MT_REQUEST_NO_RETURN:
+ case vsomeip::message_type_e::MT_NOTIFICATION:
+ if(return_code_ != vsomeip::return_code_e::E_OK) {
+ VSOMEIP_ERROR << "Provided return code 0x" << std::setw(2)
+ << std::setfill('0') << std::hex
+ << static_cast<std::uint8_t>(return_code_)
+ << "is invalid in combination with message type 0x"
+ << std::setw(2) << std::setfill('0') << std::hex
+ << static_cast<std::uint8_t>(message_type_)
+ << " use 0x00 (E_OK).";
+ return false;
+ }
+ return true;
+ break;
+ default:
+ return true;
+ break;
+ }
+ }
+
+private:
+ bool use_tcp_;
+ std::vector<vsomeip::byte_t> user_message_;
+ vsomeip::instance_t instance_;
+ std::shared_ptr<vsomeip::application> app_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ bool wait_registered_;
+ bool wait_service_available_;
+ std::thread send_thread_;
+ vsomeip::service_t service_id_;
+ vsomeip::method_t method_id_;
+ std::uint32_t length_;
+ vsomeip::client_t client_id_;
+ vsomeip::interface_version_t interface_version_;
+ vsomeip::message_type_e message_type_;
+ vsomeip::return_code_e return_code_;
+ bool wait_for_answer_;
+};
+} // namespace vsomeip_ctrl
+
+static void print_help(char* binary_name) {
+ std::cout << "Usage example:" << std::endl;
+ std::cout << binary_name << " --instance 5678 "
+ << "--message 123480e800000015134300030100000000000009efbbbf576f726c6400\n"
+ << "This will send a message to service with service id 1234 and instance 5678."
+ << std::endl << std::endl;
+ std::cout <<
+ "Available options:\n"
+ "--help | -h : print this help\n"
+ "--instance | -i : instance id of target service in hex (required)\n"
+ "--tcp | -t : flag to enable sending over TCP, default off (= UDP)\n"
+ "--message | -m : vSomeIP message to send in hex (required)\n\n"
+ "Please note: the fields client id and session id in the provided message\n"
+ "will be overwritten by the stack with the required values\n"
+ "Please further make sure to use the same configuration file\n"
+ "as the target service, if the system is not using vsomeipd" << std::endl;
+}
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ std::cerr << "To few arguments, please see the help with : "
+ << argv[0] << " --help" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ std::vector<vsomeip::byte_t> user_message;
+ vsomeip::instance_t instance(vsomeip::ANY_INSTANCE);
+ bool use_tcp(false);
+
+ for (int i = 1; i < argc; i++) {
+ std::string arg(argv[i]);
+ if (arg == "--help" || arg == "-h") {
+ print_help(argv[0]);
+ exit(EXIT_SUCCESS);
+ break;
+ } else if (arg == "--message" || arg == "-m") {
+ std::string message(argv[i + 1]);
+ for (unsigned int i = 0; i < message.length(); i += 2) {
+ vsomeip::byte_t its_byte;
+ try {
+ its_byte = static_cast<vsomeip::byte_t>(std::stoul(
+ message.substr(i, 2), 0, 16));
+ } catch (std::invalid_argument &e) {
+ std::cerr << e.what() << ": Couldn't convert '"
+ << message.substr(i, 2) << "' to hex, exiting: "
+ << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ user_message.push_back(its_byte);
+ }
+ } if (arg == "--tcp" || arg == "-t") {
+ use_tcp = true;
+ } else if (arg == "--instance" || arg == "-i") {
+ std::string instance_str(argv[i + 1]);
+ if(instance_str.length() > 4) {
+ std::cerr << "provided instance is to long, exiting." << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ if(instance_str.length() < 4) {
+ while(instance_str.size() != 4) {
+ instance_str = "0" + instance_str;
+ }
+ }
+ vsomeip::byte_t high(0x0);
+ vsomeip::byte_t low(0x0);
+ std::cout << "Instance: " << instance_str << std::endl;
+ for (unsigned int i = 0; i < instance_str.length(); i += 2) {
+ vsomeip::byte_t its_byte;
+ try {
+ its_byte = static_cast<vsomeip::byte_t>(std::stoul(
+ instance_str.substr(i, 2), 0, 16));
+ } catch (std::invalid_argument &e) {
+ std::cerr << e.what() << ": Couldn't convert '"
+ << instance_str.substr(i, 2) << "' to hex, exiting: "
+ << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ if(i == 0) {
+ high = its_byte;
+ } else {
+ low = its_byte;
+ }
+ }
+ instance = VSOMEIP_BYTES_TO_WORD(high, low);
+ }
+ }
+
+ if(instance == vsomeip::ANY_INSTANCE) {
+ std::cerr << "Please provide a target instance (see --help)" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ if(user_message.empty()) {
+ std::cerr << "Please provide a message to send (see --help)" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ vsomeip_ctrl::vsomeip_sender sender(use_tcp, user_message, instance);
+}