From 273814c76be4a8f906dc053492529b8d53b9e807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gehring?= Date: Tue, 20 Sep 2016 03:59:53 -0700 Subject: [PATCH] vSomeIP 2.2.4 --- .gitignore | 48 +- CHANGES | 126 ++ CMakeLists.txt | 36 +- LICENSE_boost | 25 + README | 392 +++- README.md | 0 config/vsomeip-local-tracing.json | 86 + config/vsomeip-tcp-client.json | 46 +- config/vsomeip-udp-client.json | 8 + config/vsomeip-udp-service.json | 12 +- daemon/CMakeLists.txt | 4 +- daemon/vsomeipd.cpp | 21 +- documentation/todo.txt | 16 - examples/CMakeLists.txt | 2 +- examples/hello_world/CMakeLists.txt | 2 +- examples/hello_world/hello_world_client.cpp | 2 +- examples/hello_world/hello_world_service.cpp | 2 +- examples/hello_world/helloworld-local.json | 69 +- examples/hello_world/readme | 2 +- examples/notify-sample.cpp | 2 +- examples/readme.txt | 10 +- examples/request-sample.cpp | 2 +- examples/response-sample.cpp | 2 +- examples/sample-ids.hpp | 2 +- examples/subscribe-sample.cpp | 12 +- exportmap.gcc | 1 + .../configuration/include/client.hpp | 28 + .../configuration/include/configuration.hpp | 39 +- .../include/configuration_impl.hpp | 137 +- .../configuration/include/event.hpp | 2 +- .../configuration/include/eventgroup.hpp | 4 +- .../configuration/include/internal.hpp.in | 61 +- .../configuration/include/service.hpp | 3 +- .../configuration/include/trace.hpp | 62 + .../configuration/include/watchdog.hpp | 21 + .../configuration/src/configuration.cpp | 2 +- .../configuration/src/configuration_impl.cpp | 907 ++++++-- implementation/endpoints/include/buffer.hpp | 2 +- .../include/client_endpoint_impl.hpp | 27 +- implementation/endpoints/include/endpoint.hpp | 6 +- .../endpoints/include/endpoint_definition.hpp | 2 +- .../endpoints/include/endpoint_host.hpp | 8 +- .../endpoints/include/endpoint_impl.hpp | 18 +- .../include/local_client_endpoint_impl.hpp | 25 +- .../include/local_server_endpoint_impl.hpp | 22 +- .../include/server_endpoint_impl.hpp | 21 +- .../include/tcp_client_endpoint_impl.hpp | 8 +- .../include/tcp_server_endpoint_impl.hpp | 13 +- .../include/udp_client_endpoint_impl.hpp | 9 +- .../include/udp_server_endpoint_impl.hpp | 30 +- .../include/virtual_server_endpoint_impl.hpp | 6 +- .../endpoints/src/client_endpoint_impl.cpp | 159 +- .../endpoints/src/endpoint_definition.cpp | 2 +- .../endpoints/src/endpoint_impl.cpp | 93 +- .../src/local_client_endpoint_impl.cpp | 150 +- .../src/local_server_endpoint_impl.cpp | 62 +- .../endpoints/src/server_endpoint_impl.cpp | 97 +- .../src/tcp_client_endpoint_impl.cpp | 93 +- .../src/tcp_server_endpoint_impl.cpp | 124 +- .../src/udp_client_endpoint_impl.cpp | 58 +- .../src/udp_server_endpoint_impl.cpp | 218 +- .../src/virtual_server_endpoint_impl.cpp | 12 +- .../boost/asio/basic_datagram_socket_ext.hpp | 954 +++++++++ .../asio/datagram_socket_service_ext.hpp | 437 ++++ .../detail/handler_type_requirements_ext.hpp | 516 +++++ .../impl/reactive_socket_service_base_ext.ipp | 270 +++ .../boost/asio/detail/impl/socket_ops_ext.ipp | 210 ++ .../detail/reactive_socket_recv_op_ext.hpp | 126 ++ .../reactive_socket_recvfrom_op_ext.hpp | 136 ++ .../detail/reactive_socket_recvmsg_op_ext.hpp | 128 ++ .../reactive_socket_service_base_ext.hpp | 455 ++++ .../detail/reactive_socket_service_ext.hpp | 462 +++++ .../boost/asio/detail/reactor_op_ext.hpp | 42 + .../boost/asio/detail/socket_ops_ext.hpp | 62 + .../helper/boost/asio/ip/udp_ext.hpp | 115 ++ implementation/logging/include/defines.hpp | 15 + .../logging/include/dlt_sink_backend.hpp | 6 +- implementation/logging/include/logger.hpp | 2 +- .../logging/include/logger_impl.hpp | 5 +- .../logging/src/dlt_sink_backend.cpp | 15 +- implementation/logging/src/logger.cpp | 2 +- implementation/logging/src/logger_impl.cpp | 23 +- .../message/include/deserializer.hpp | 2 +- .../message/include/message_base_impl.hpp | 6 +- .../message/include/message_header_impl.hpp | 2 +- .../message/include/message_impl.hpp | 12 +- .../message/include/payload_impl.hpp | 2 +- implementation/message/include/serializer.hpp | 2 +- implementation/message/src/deserializer.cpp | 6 +- .../message/src/message_base_impl.cpp | 10 +- implementation/routing/include/event.hpp | 29 +- .../routing/include/eventgroupinfo.hpp | 35 +- .../routing/include/routing_manager.hpp | 21 +- .../include/routing_manager_adapter.hpp | 2 +- .../routing/include/routing_manager_base.hpp | 193 ++ .../routing/include/routing_manager_host.hpp | 6 +- .../routing/include/routing_manager_impl.hpp | 160 +- .../routing/include/routing_manager_proxy.hpp | 83 +- .../routing/include/routing_manager_stub.hpp | 47 +- .../include/routing_manager_stub_host.hpp | 29 +- .../routing/include/serviceinfo.hpp | 22 +- implementation/routing/include/types.hpp | 2 +- implementation/routing/src/event.cpp | 123 +- implementation/routing/src/eventgroupinfo.cpp | 86 +- .../routing/src/routing_manager_base.cpp | 782 +++++++ .../routing/src/routing_manager_impl.cpp | 1840 +++++++++-------- .../routing/src/routing_manager_proxy.cpp | 809 +++++--- .../routing/src/routing_manager_stub.cpp | 586 +++++- implementation/routing/src/serviceinfo.cpp | 50 +- .../runtime/include/application_impl.hpp | 125 +- .../runtime/include/runtime_impl.hpp | 7 +- .../runtime/src/application_impl.cpp | 963 +++++++-- implementation/runtime/src/error.cpp | 2 +- implementation/runtime/src/runtime.cpp | 10 +- implementation/runtime/src/runtime_impl.cpp | 14 +- .../include/configuration_option_impl.hpp | 2 +- .../service_discovery/include/constants.hpp | 2 +- .../service_discovery/include/defines.hpp | 16 +- .../include/deserializer.hpp | 2 +- .../service_discovery/include/entry_impl.hpp | 5 +- .../include/enumeration_types.hpp | 2 +- .../include/eventgroupentry_impl.hpp | 13 +- .../service_discovery/include/fsm_base.hpp | 12 +- .../service_discovery/include/fsm_events.hpp | 21 +- .../include/ip_option_impl.hpp | 2 +- .../include/ipv4_option_impl.hpp | 2 +- .../include/ipv6_option_impl.hpp | 2 +- .../include/load_balancing_option_impl.hpp | 2 +- .../include/message_element_impl.hpp | 2 +- .../include/message_impl.hpp | 12 +- .../service_discovery/include/option_impl.hpp | 2 +- .../include/primitive_types.hpp | 2 +- .../include/protection_option_impl.hpp | 2 +- .../service_discovery/include/request.hpp | 7 +- .../service_discovery/include/runtime.hpp | 2 +- .../include/runtime_impl.hpp | 2 +- .../include/service_discovery.hpp | 24 +- .../include/service_discovery_fsm.hpp | 74 +- .../include/service_discovery_host.hpp | 30 +- .../include/service_discovery_impl.hpp | 157 +- .../include/serviceentry_impl.hpp | 2 +- .../include/subscription.hpp | 20 +- .../src/configuration_option_impl.cpp | 50 +- .../service_discovery/src/deserializer.cpp | 2 +- .../service_discovery/src/entry_impl.cpp | 31 +- .../src/eventgroupentry_impl.cpp | 53 +- .../service_discovery/src/fsm_base.cpp | 40 +- .../service_discovery/src/ip_option_impl.cpp | 2 +- .../src/ipv4_option_impl.cpp | 6 +- .../src/ipv6_option_impl.cpp | 6 +- .../src/load_balancing_option_impl.cpp | 2 +- .../src/message_element_impl.cpp | 2 +- .../service_discovery/src/message_impl.cpp | 9 +- .../service_discovery/src/option_impl.cpp | 2 +- .../src/protection_option_impl.cpp | 2 +- .../service_discovery/src/request.cpp | 13 +- .../service_discovery/src/runtime.cpp | 2 +- .../service_discovery/src/runtime_impl.cpp | 2 +- .../src/service_discovery_fsm.cpp | 205 +- .../src/service_discovery_impl.cpp | 1536 ++++++++++---- .../src/serviceentry_impl.cpp | 2 +- .../service_discovery/src/subscription.cpp | 30 +- implementation/tracing/include/defines.hpp | 12 + .../tracing/include/enumeration_types.hpp | 21 + .../tracing/include/trace_connector.hpp | 100 + .../tracing/include/trace_header.hpp | 38 + .../tracing/src/trace_connector.cpp | 361 ++++ implementation/tracing/src/trace_header.cpp | 58 + implementation/utility/include/byteorder.hpp | 2 +- implementation/utility/include/utility.hpp | 10 +- implementation/utility/src/utility.cpp | 273 ++- initial.txt | 1 - interface/vsomeip/application.hpp | 31 +- interface/vsomeip/constants.hpp | 12 +- interface/vsomeip/defines.hpp | 4 +- interface/vsomeip/enumeration_types.hpp | 2 +- interface/vsomeip/error.hpp | 2 +- interface/vsomeip/export.hpp | 2 +- interface/vsomeip/handler.hpp | 3 +- interface/vsomeip/internal/deserializable.hpp | 2 +- interface/vsomeip/internal/serializable.hpp | 2 +- interface/vsomeip/message.hpp | 2 +- interface/vsomeip/message_base.hpp | 4 +- interface/vsomeip/payload.hpp | 2 +- interface/vsomeip/primitive_types.hpp | 4 +- interface/vsomeip/runtime.hpp | 6 +- interface/vsomeip/vsomeip.hpp | 2 +- test/CMakeLists.txt | 415 +++- test/application_tests/application_test.cpp | 61 +- test/application_tests/application_test.json | 9 +- .../application_test_daemon.json | 38 + ...ation_test_no_dispatch_threads_daemon.json | 37 + .../application_test_starter.sh | 31 +- .../big_payload_test_client.cpp | 2 +- .../big_payload_test_client.hpp | 2 +- .../big_payload_test_globals.hpp | 2 +- .../big_payload_test_service.cpp | 2 +- .../big_payload_test_service.hpp | 2 +- .../client_id_test_globals.hpp | 9 +- .../client_id_test_master_starter.sh | 8 +- .../client_id_test_service.cpp | 4 +- .../client_id_test_slave_starter.sh | 12 +- ..._diff_client_ids_diff_ports_master.json.in | 14 + ...t_diff_client_ids_diff_ports_slave.json.in | 28 +- ...ient_ids_partial_same_ports_master.json.in | 70 + ...lient_ids_partial_same_ports_slave.json.in | 70 + ..._diff_client_ids_same_ports_master.json.in | 14 + ...t_diff_client_ids_same_ports_slave.json.in | 16 +- ..._same_client_ids_diff_ports_master.json.in | 14 + ...t_same_client_ids_diff_ports_slave.json.in | 26 +- ..._same_client_ids_same_ports_master.json.in | 14 + ...t_same_client_ids_same_ports_slave.json.in | 14 +- .../configuration-test.cpp | 2 +- .../conf/cpu_load_test_client_master.json.in | 32 + .../conf/cpu_load_test_client_slave.json.in | 32 + .../conf/cpu_load_test_service_master.json.in | 46 + .../conf/cpu_load_test_service_slave.json.in | 46 + test/cpu_load_tests/cpu_load_measurer.cpp | 158 ++ test/cpu_load_tests/cpu_load_measurer.hpp | 35 + test/cpu_load_tests/cpu_load_test_client.cpp | 376 ++++ test/cpu_load_tests/cpu_load_test_globals.hpp | 18 + .../cpu_load_test_master_starter.sh | 70 + test/cpu_load_tests/cpu_load_test_service.cpp | 204 ++ .../cpu_load_test_slave_starter.sh | 52 + .../header_factory_test.cpp | 2 +- .../header_factory_test_client.cpp | 2 +- .../header_factory_test_client.hpp | 2 +- .../header_factory_test_service.cpp | 2 +- .../header_factory_test_service.hpp | 2 +- .../magic_cookies_test_client.cpp | 32 +- .../magic_cookies_test_client_start.sh | 2 +- .../magic_cookies_test_service.cpp | 2 +- .../magic_cookies_test_service_start.sh | 2 +- .../magic_cookies_test_starter.sh | 2 +- ...ocal_payload_test_client_external_start.sh | 2 +- ...al_payload_test_client_external_starter.sh | 2 +- ..._test_client_local_and_external_starter.sh | 2 +- ...l_local_payload_test_client_local_start.sh | 2 +- ...local_payload_test_client_local_starter.sh | 2 +- ...load_test_service_client_external_start.sh | 2 +- ...ternal_local_payload_test_service_start.sh | 2 +- .../local_payload_test_client_start.sh | 2 +- .../local_payload_test_service_start.sh | 2 +- .../local_payload_test_starter.sh | 2 +- test/payload_tests/payload_test_client.cpp | 2 +- test/payload_tests/payload_test_client.hpp | 2 +- test/payload_tests/payload_test_service.cpp | 2 +- test/payload_tests/payload_test_service.hpp | 2 +- test/payload_tests/stopwatch.cpp | 2 +- test/payload_tests/stopwatch.hpp | 2 +- test/readme.txt | 55 +- ...ocal_routing_test_client_external_start.sh | 2 +- .../external_local_routing_test_service.cpp | 16 +- .../external_local_routing_test_service.hpp | 3 +- ...ternal_local_routing_test_service_start.sh | 2 +- .../external_local_routing_test_starter.sh | 2 +- .../local_routing_test_client.cpp | 2 +- .../local_routing_test_client.hpp | 2 +- .../local_routing_test_client_start.sh | 2 +- .../local_routing_test_service.cpp | 2 +- .../local_routing_test_service.hpp | 2 +- .../local_routing_test_service_start.sh | 2 +- .../local_routing_test_starter.sh | 2 +- test/someip_test_globals.hpp | 2 +- ..._diff_client_ids_diff_ports_master.json.in | 74 + ...t_diff_client_ids_diff_ports_slave.json.in | 74 + .../subscribe_notify_one_test_globals.hpp | 35 + ...ubscribe_notify_one_test_master_starter.sh | 93 + .../subscribe_notify_one_test_service.cpp | 442 ++++ ...subscribe_notify_one_test_slave_starter.sh | 72 + ..._diff_client_ids_diff_ports_master.json.in | 70 + ...t_diff_client_ids_diff_ports_slave.json.in | 70 + ...ient_ids_partial_same_ports_master.json.in | 70 + ...lient_ids_partial_same_ports_slave.json.in | 70 + ..._diff_client_ids_same_ports_master.json.in | 70 + ...t_diff_client_ids_same_ports_slave.json.in | 70 + ..._same_client_ids_diff_ports_master.json.in | 70 + ...t_same_client_ids_diff_ports_slave.json.in | 70 + ..._same_client_ids_same_ports_master.json.in | 70 + ...t_same_client_ids_same_ports_slave.json.in | 70 + .../subscribe_notify_test_globals.hpp | 35 + .../subscribe_notify_test_master_starter.sh | 93 + .../subscribe_notify_test_service.cpp | 416 ++++ .../subscribe_notify_test_slave_starter.sh | 72 + tools/CMakeLists.txt | 18 + tools/vsomeip_ctrl.cpp | 429 ++++ 286 files changed, 18188 insertions(+), 3412 deletions(-) create mode 100644 CHANGES create mode 100644 LICENSE_boost mode change 100644 => 100755 README.md create mode 100644 config/vsomeip-local-tracing.json create mode 100644 implementation/configuration/include/client.hpp create mode 100644 implementation/configuration/include/trace.hpp create mode 100644 implementation/configuration/include/watchdog.hpp create mode 100644 implementation/helper/boost/asio/basic_datagram_socket_ext.hpp create mode 100644 implementation/helper/boost/asio/datagram_socket_service_ext.hpp create mode 100644 implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp create mode 100644 implementation/helper/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp create mode 100644 implementation/helper/boost/asio/detail/impl/socket_ops_ext.ipp create mode 100644 implementation/helper/boost/asio/detail/reactive_socket_recv_op_ext.hpp create mode 100644 implementation/helper/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp create mode 100644 implementation/helper/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp create mode 100644 implementation/helper/boost/asio/detail/reactive_socket_service_base_ext.hpp create mode 100644 implementation/helper/boost/asio/detail/reactive_socket_service_ext.hpp create mode 100644 implementation/helper/boost/asio/detail/reactor_op_ext.hpp create mode 100644 implementation/helper/boost/asio/detail/socket_ops_ext.hpp create mode 100644 implementation/helper/boost/asio/ip/udp_ext.hpp create mode 100644 implementation/logging/include/defines.hpp create mode 100644 implementation/routing/include/routing_manager_base.hpp create mode 100644 implementation/routing/src/routing_manager_base.cpp create mode 100644 implementation/tracing/include/defines.hpp create mode 100644 implementation/tracing/include/enumeration_types.hpp create mode 100644 implementation/tracing/include/trace_connector.hpp create mode 100644 implementation/tracing/include/trace_header.hpp create mode 100644 implementation/tracing/src/trace_connector.cpp create mode 100644 implementation/tracing/src/trace_header.cpp delete mode 100644 initial.txt create mode 100644 test/application_tests/application_test_daemon.json create mode 100644 test/application_tests/application_test_no_dispatch_threads_daemon.json create mode 100644 test/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_master.json.in create mode 100644 test/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_slave.json.in create mode 100644 test/cpu_load_tests/conf/cpu_load_test_client_master.json.in create mode 100644 test/cpu_load_tests/conf/cpu_load_test_client_slave.json.in create mode 100644 test/cpu_load_tests/conf/cpu_load_test_service_master.json.in create mode 100644 test/cpu_load_tests/conf/cpu_load_test_service_slave.json.in create mode 100644 test/cpu_load_tests/cpu_load_measurer.cpp create mode 100644 test/cpu_load_tests/cpu_load_measurer.hpp create mode 100644 test/cpu_load_tests/cpu_load_test_client.cpp create mode 100644 test/cpu_load_tests/cpu_load_test_globals.hpp create mode 100755 test/cpu_load_tests/cpu_load_test_master_starter.sh create mode 100644 test/cpu_load_tests/cpu_load_test_service.cpp create mode 100755 test/cpu_load_tests/cpu_load_test_slave_starter.sh create mode 100644 test/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master.json.in create mode 100644 test/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json.in create mode 100644 test/subscribe_notify_one_tests/subscribe_notify_one_test_globals.hpp create mode 100755 test/subscribe_notify_one_tests/subscribe_notify_one_test_master_starter.sh create mode 100644 test/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp create mode 100755 test/subscribe_notify_one_tests/subscribe_notify_one_test_slave_starter.sh create mode 100644 test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master.json.in create mode 100644 test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave.json.in create mode 100644 test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_master.json.in create mode 100644 test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_slave.json.in create mode 100644 test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master.json.in create mode 100644 test/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave.json.in create mode 100644 test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_master.json.in create mode 100644 test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_slave.json.in create mode 100644 test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_master.json.in create mode 100644 test/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_slave.json.in create mode 100644 test/subscribe_notify_tests/subscribe_notify_test_globals.hpp create mode 100755 test/subscribe_notify_tests/subscribe_notify_test_master_starter.sh create mode 100644 test/subscribe_notify_tests/subscribe_notify_test_service.cpp create mode 100755 test/subscribe_notify_tests/subscribe_notify_test_slave_starter.sh create mode 100644 tools/CMakeLists.txt create mode 100644 tools/vsomeip_ctrl.cpp diff --git a/.gitignore b/.gitignore index 1b7d204bf..3aa1ebf78 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 000000000..362beb528 --- /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 bf03c161f..5f85a14b8 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 000000000..eff5f980f --- /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 893d00400..79b7efff6 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= .. +---- + +To predefine the diagnosis address, call cmake like: +[source,bash] +---- +cmake -DDIAGNOSIS_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 <> utility call: +[source, bash] +---- +mkdir build +cd build +cmake .. +make vsomeip_ctrl +---- + Generating the documentation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To generate the documentation call cmake as described in <> 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 <> ++ +** '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 +<>. + + +[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 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 old mode 100644 new mode 100755 diff --git a/config/vsomeip-local-tracing.json b/config/vsomeip-local-tracing.json new file mode 100644 index 000000000..ba3a6bf98 --- /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 52e349a72..b3d58cf36 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 9c8a846b1..909eab561 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 b04aa4e1e..6850a7f3d 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 bdc0f3c3d..09d8b0358 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 db60e235b..54c6b9b21 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 #include "../implementation/configuration/include/internal.hpp" +#include "../implementation/logging/include/logger.hpp" + +#ifdef USE_DLT +#include +#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 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 f93e5413a..1933fd858 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 e41958953..aca749c4a 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 48d14a4b3..cb3266574 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 2099eeedd..8007c32a6 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 78b895f9b..b99a401b1 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 c2b4203c4..5aeebb70d 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 9b19424bb..01c2ec955 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 442f74bd1..12c9a4ceb 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 745c5f26f..038544ecf 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 ccdcffef4..86834d064 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 31adacece..c3ef1775a 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 2d59164a2..b1a503d0f 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 9a037223b..915ea11dd 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 @@ class client_sample { << "]" << 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 @@ class client_sample { 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 546738df8..a768523b5 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 000000000..fcb4395b7 --- /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 +#include +#include + +#include + +namespace vsomeip { +namespace cfg { + +struct client { + service_t service_; + instance_t instance_; + + std::map > 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 2f106eeef..8dab1b463 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 #include "internal.hpp" +#include "trace.hpp" namespace vsomeip { @@ -32,6 +33,7 @@ class VSOMEIP_EXPORT configuration { 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 @@ class VSOMEIP_EXPORT configuration { 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 > &_used, uint16_t &_port) const = 0; + virtual std::set > 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 @@ class VSOMEIP_EXPORT configuration { 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 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 a6ca21cb5..87a1d159b 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 #include #include +#include #include +#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 @@ class configuration_impl: public configuration { 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 &_trees); + VSOMEIP_EXPORT void load(const element &_element); + VSOMEIP_EXPORT void load_log(const std::vector &_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 @@ class configuration_impl: public configuration { 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 @@ class configuration_impl: public configuration { 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 > &_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 > 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 @@ class configuration_impl: public configuration { 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 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 &_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 get_client_port_configuration( + const boost::property_tree::ptree &_tree); void get_event_configuration(std::shared_ptr &_service, const boost::property_tree::ptree &_tree); void get_eventgroup_configuration(std::shared_ptr &_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 &_filter_rule); + void get_permission_configuration(const element &_element); + + servicegroup *find_servicegroup(const std::string &_name) const; + std::shared_ptr find_client(service_t _service, instance_t _instance) const; + std::shared_ptr find_service(service_t _service, instance_t _instance) const; + std::shared_ptr find_eventgroup(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const; private: static std::shared_ptr the_configuration; @@ -118,6 +173,7 @@ class configuration_impl: public configuration { protected: // Configuration data boost::asio::ip::address unicast_; + unsigned short diagnosis_; bool has_console_log_; bool has_file_log_; @@ -125,12 +181,17 @@ class configuration_impl: public configuration { std::string logfile_; boost::log::trivial::severity_level loglevel_; - std::map> applications_; + std::map> applications_; + std::set client_identifiers_; std::map > > services_; + std::map > > clients_; + std::string routing_host_; bool is_sd_enabled_; @@ -150,6 +211,42 @@ class configuration_impl: public configuration { std::map> message_sizes_; std::uint32_t max_configured_message_size_; + + std::shared_ptr trace_; + + std::unordered_set supported_selective_addresses; + + std::shared_ptr 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 e93228979..d488ec431 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 27bf72231..93a91a32e 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 > 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 64b71055b..d7770c9bb 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 +#ifndef WIN32 +#include +#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 bbe235eaf..8e72a0288 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 000000000..cba4da86e --- /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 + +#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 services_; + std::vector methods_; + std::vector clients_; +}; + +struct trace { + + trace() : + channels_(), + filter_rules_(), + is_enabled_(false) { + channels_.push_back(std::make_shared()); + } + + std::vector> channels_; + std::vector> 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 000000000..1d5696d1b --- /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 9bc90d4f7..0994dcd4d 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 66a121938..3c78de094 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 #include #include @@ -20,6 +16,7 @@ #include +#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_impl::get( std::shared_ptr its_configuration; std::lock_guard its_lock(mutex_); + std::set failed_files; + static bool has_reading_failed(false); + if (!the_configuration) { the_configuration = std::make_shared(); - std::vector its_tree_set; + std::vector its_configuration_elements; // Load logger configuration first for (auto i : _input) { @@ -51,9 +51,13 @@ std::shared_ptr 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_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_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()), + watchdog_(std::make_shared()), + 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(*_other.trace_.get()); + watchdog_ = std::make_shared(*_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 &_trees) { +void configuration_impl::load_log(const std::vector &_elements) { + std::set 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 &_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("unicast"); + unicast_ = unicast_.from_string(its_value); + is_configured_[ET_UNICAST] = true; + } + } catch (...) { + } try { - std::string its_value = _tree.get("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("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 its_client(std::make_shared()); + + 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 configuration_impl::get_client_port_configuration( + const boost::property_tree::ptree &_tree) { + std::set 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, 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 its_event = std::make_shared( 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, const boost::property_tree::ptree &_tree) { - bool is_multicast; for (auto i = _tree.begin(); i != _tree.end(); ++i) { - is_multicast = false; std::shared_ptr its_eventgroup = std::make_shared(); 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 its_channel = std::make_shared(); + 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 its_filter_rule = std::make_shared(); + 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 &_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 > &_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 > @@ -796,26 +1311,73 @@ configuration_impl::get_remote_services() const { std::set > 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 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 configuration_impl::find_client(service_t _service, + instance_t _instance) const { + std::shared_ptr 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 configuration_impl::find_service(service_t _service, instance_t _instance) const { - service *its_service(0); + std::shared_ptr 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 configuration_impl::find_eventgroup( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const { + std::shared_ptr 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 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 5641117ce..1dac89ae9 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 29f42a35d..f80e38568 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 #include +#include + #include "buffer.hpp" #include "endpoint_impl.hpp" @@ -24,22 +26,23 @@ namespace vsomeip { class endpoint; class endpoint_host; -template -class client_endpoint_impl: public endpoint_impl, - public std::enable_shared_from_this< - client_endpoint_impl > { +template +class client_endpoint_impl: public endpoint_impl, + public std::enable_shared_from_this > { 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 _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 _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 _target, + const byte_t *_data, uint32_t _size, bool _flush = true); + bool flush(); void stop(); void restart(); @@ -64,6 +67,8 @@ class client_endpoint_impl: public endpoint_impl, 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 @@ class client_endpoint_impl: public endpoint_impl, std::deque 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 6acf1646a..c063f2a92 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 @@ class endpoint { 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 d7fb3a23e..e4a32907f 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 d526ab48f..1c78f39c6 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 +#include + #include namespace vsomeip { @@ -21,9 +23,11 @@ class endpoint_host { virtual void on_connect(std::shared_ptr _endpoint) = 0; virtual void on_disconnect(std::shared_ptr _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 5d8350adb..bd056982c 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 +template class endpoint_impl: public endpoint { public: + typedef typename Protocol::endpoint endpoint_type; + endpoint_impl(std::shared_ptr _adapter, + endpoint_type _local, boost::asio::io_service &_io, std::uint32_t _max_message_size); virtual ~endpoint_impl(); @@ -33,11 +36,10 @@ class endpoint_impl: public endpoint { // 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 @@ class endpoint_impl: public endpoint { 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 97f01ceee..a6d777eb5 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 local_client_endpoint_base_impl; +typedef client_endpoint_impl< + boost::asio::ip::tcp + > local_client_endpoint_base_impl; #else -typedef client_endpoint_impl 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 _host, - endpoint_type _local, + endpoint_type _remote, boost::asio::io_service &_io, std::uint32_t _max_message_size); @@ -43,21 +45,10 @@ class local_client_endpoint_impl: public local_client_endpoint_base_impl { 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 626b30e49..d8f5288e1 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 local_server_endpoint_base_impl; +typedef server_endpoint_impl< + boost::asio::ip::tcp + > local_server_endpoint_base_impl; #else -typedef server_endpoint_impl 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 @@ class local_server_endpoint_impl: public local_server_endpoint_base_impl { 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 { @@ -69,6 +73,8 @@ class local_server_endpoint_impl: public local_server_endpoint_base_impl { 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 @@ class local_server_endpoint_impl: public local_server_endpoint_base_impl { receive_buffer_t recv_buffer_; size_t recv_buffer_size_; + static std::vector queued_data_; + private: void receive_cbk(boost::system::error_code const &_error, std::size_t _bytes); @@ -94,7 +102,7 @@ class local_server_endpoint_impl: public local_server_endpoint_base_impl { #endif std::map 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 c51cb49b3..15d001b46 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 -class server_endpoint_impl: public endpoint_impl, - public std::enable_shared_from_this< - server_endpoint_impl > { +template +class server_endpoint_impl: public endpoint_impl, + public std::enable_shared_from_this > { public: typedef typename Protocol::socket socket_type; typedef typename Protocol::endpoint endpoint_type; - typedef boost::array buffer_type; typedef typename std::map > queue_type; typedef typename queue_type::iterator queue_iterator_type; server_endpoint_impl(std::shared_ptr _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 @@ class server_endpoint_impl: public endpoint_impl, 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 packetizer_; queue_type queues_; + std::mutex clients_mutex_; std::map > 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 e5bf98771..e6aaa33c3 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 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 _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 729586839..16197ccc3 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 #include +#include #include "server_endpoint_impl.hpp" namespace vsomeip { -typedef server_endpoint_impl 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 @@ class tcp_server_endpoint_impl: public tcp_server_endpoint_base_impl { 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); + 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 4a51db683..07d217959 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 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 _host, + endpoint_type _local, endpoint_type _remote, boost::asio::io_service &_io); virtual ~udp_client_endpoint_impl(); @@ -46,7 +48,6 @@ class udp_client_endpoint_impl: virtual public udp_client_endpoint_base_impl { 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 c03a7b425..907e02238 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 -#include +#include #include + #include "server_endpoint_impl.hpp" namespace vsomeip { -typedef server_endpoint_impl 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 @@ class udp_server_endpoint_impl: public udp_server_endpoint_base_impl { 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 @@ class udp_server_endpoint_impl: public udp_server_endpoint_base_impl { 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 > multicasts_; + + std::map default_targets_; + std::set 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 12484f545..2fd70056a 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 @@ class virtual_server_endpoint_impl : public endpoint { 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 6ed812a21..f68bad70f 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 -client_endpoint_impl::client_endpoint_impl( - std::shared_ptr _host, endpoint_type _remote, - boost::asio::io_service &_io, std::uint32_t _max_message_size) - : endpoint_impl(_host, _io, _max_message_size), +template +client_endpoint_impl::client_endpoint_impl( + std::shared_ptr _host, + endpoint_type _local, + endpoint_type _remote, + boost::asio::io_service &_io, + std::uint32_t _max_message_size) + : endpoint_impl(_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()) { + packetizer_(std::make_shared()), + was_not_connected_(false) { } -template -client_endpoint_impl::~client_endpoint_impl() { +template +client_endpoint_impl::~client_endpoint_impl() { } -template -bool client_endpoint_impl::is_client() const { +template +bool client_endpoint_impl::is_client() const { return true; } -template -bool client_endpoint_impl::is_connected() const { +template +bool client_endpoint_impl::is_connected() const { return is_connected_; } -template -void client_endpoint_impl::stop() { +template +void client_endpoint_impl::stop() { if (socket_.is_open()) { - socket_.close(); + connect_timer_.cancel(); + connect_timeout_ = VSOMEIP_DEFAULT_CONNECT_TIMEOUT; + endpoint_impl::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 -void client_endpoint_impl::restart() { - receive(); +template +void client_endpoint_impl::restart() { + is_connected_ = false; + connect_timer_.expires_from_now( + std::chrono::milliseconds(connect_timeout_)); + connect_timer_.async_wait( + std::bind(&client_endpoint_impl::wait_connect_cbk, + this->shared_from_this(), std::placeholders::_1)); } -template -bool client_endpoint_impl::send_to( +template +bool client_endpoint_impl::send_to( const std::shared_ptr _target, const byte_t *_data, uint32_t _size, bool _flush) { (void)_target; @@ -70,16 +98,18 @@ bool client_endpoint_impl::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 -bool client_endpoint_impl::send(const uint8_t *_data, +template +bool client_endpoint_impl::send(const uint8_t *_data, uint32_t _size, bool _flush) { std::lock_guard its_lock(mutex_); - bool is_flushing(false); + if (endpoint_impl::sending_blocked_) { + return false; + } #if 0 std::stringstream msg; msg << "cei::send: "; @@ -89,9 +119,10 @@ bool client_endpoint_impl::send(const uint8_t *_data, VSOMEIP_DEBUG << msg.str(); #endif - if (packetizer_->size() + _size > endpoint_impl::max_message_size_) { + const bool queue_size_zero_on_entry(queue_.empty()); + if (packetizer_->size() + _size > endpoint_impl::max_message_size_ + && !packetizer_->empty()) { queue_.push_back(packetizer_); - is_flushing = true; packetizer_ = std::make_shared(); } @@ -100,28 +131,26 @@ bool client_endpoint_impl::send(const uint8_t *_data, if (_flush) { flush_timer_.cancel(); queue_.push_back(packetizer_); - is_flushing = true; packetizer_ = std::make_shared(); } 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::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 -bool client_endpoint_impl::flush() { +template +bool client_endpoint_impl::flush() { bool is_successful(true); if (!packetizer_->empty()) { @@ -138,23 +167,26 @@ bool client_endpoint_impl::flush() { return is_successful; } -template -void client_endpoint_impl::connect_cbk( +template +void client_endpoint_impl::connect_cbk( boost::system::error_code const &_error) { std::shared_ptr 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::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::connect_cbk( } receive(); + + std::lock_guard its_lock(mutex_); + if (queue_.size() > 0 && was_not_connected_) { + was_not_connected_ = false; + send_queued(); + } } } } -template -void client_endpoint_impl::wait_connect_cbk( +template +void client_endpoint_impl::wait_connect_cbk( boost::system::error_code const &_error) { if (!_error) { connect(); } } -template -void client_endpoint_impl::send_cbk( +template +void client_endpoint_impl::send_cbk( boost::system::error_code const &_error, std::size_t _bytes) { (void)_bytes; if (!_error) { std::lock_guard 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::sending_blocked_) { + std::lock_guard 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 -void client_endpoint_impl::flush_cbk( +template +void client_endpoint_impl::flush_cbk( boost::system::error_code const &_error) { if (!_error) { (void) flush(); @@ -209,13 +258,9 @@ void client_endpoint_impl::flush_cbk( // Instantiate template #ifndef WIN32 -template class client_endpoint_impl ; +template class client_endpoint_impl; #endif -template class client_endpoint_impl ; -template class client_endpoint_impl ; - +template class client_endpoint_impl; +template class client_endpoint_impl; } // namespace vsomeip diff --git a/implementation/endpoints/src/endpoint_definition.cpp b/implementation/endpoints/src/endpoint_definition.cpp index d748aa3ac..fe7e7d647 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 5b0e088fa..109cff8ff 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 +#include +#include +#include + #include #include @@ -12,33 +17,38 @@ namespace vsomeip { -template -endpoint_impl::endpoint_impl( - std::shared_ptr _host, boost::asio::io_service &_io, - std::uint32_t _max_message_size) +template +endpoint_impl::endpoint_impl( + std::shared_ptr _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 -endpoint_impl::~endpoint_impl() { +template +endpoint_impl::~endpoint_impl() { } -template -void endpoint_impl::enable_magic_cookies() { +template +void endpoint_impl::enable_magic_cookies() { has_enabled_magic_cookies_ = is_supporting_magic_cookies_; } -template -bool endpoint_impl::is_magic_cookie() const { +template +bool endpoint_impl::is_magic_cookie() const { return false; } -template -uint32_t endpoint_impl::find_magic_cookie( +template +uint32_t endpoint_impl::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::find_magic_cookie( return (is_found ? its_offset : 0xFFFFFFFF); } -template -void endpoint_impl::join(const std::string &) { +template +void endpoint_impl::join(const std::string &) { } -template -void endpoint_impl::leave(const std::string &) { +template +void endpoint_impl::leave(const std::string &) { } -template -void endpoint_impl::add_multicast( - service_t, event_t, const std::string &, uint16_t) { +template +void endpoint_impl::add_default_target( + service_t, const std::string &, uint16_t) { } -template -void endpoint_impl::remove_multicast(service_t, event_t) { +template +void endpoint_impl::remove_default_target(service_t) { } -template -bool endpoint_impl::get_remote_address( +template +bool endpoint_impl::get_remote_address( boost::asio::ip::address &_address) const { (void)_address; return false; } -template -unsigned short endpoint_impl::get_local_port() const { +template +unsigned short endpoint_impl::get_local_port() const { return 0; } -template -unsigned short endpoint_impl::get_remote_port() const { +template +unsigned short endpoint_impl::get_remote_port() const { return 0; } -template -bool endpoint_impl::is_reliable() const { +template +bool endpoint_impl::is_reliable() const { return false; } -template -void endpoint_impl::increment_use_count() { +template +void endpoint_impl::increment_use_count() { use_count_++; } -template -void endpoint_impl::decrement_use_count() { +template +void endpoint_impl::decrement_use_count() { if (use_count_ > 0) use_count_--; } -template -uint32_t endpoint_impl::get_use_count() { +template +uint32_t endpoint_impl::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; +#endif +template class endpoint_impl; +template class endpoint_impl; +template class endpoint_impl; } // namespace vsomeip diff --git a/implementation/endpoints/src/local_client_endpoint_impl.cpp b/implementation/endpoints/src/local_client_endpoint_impl.cpp index 116287fbb..62dba827c 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 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 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 b392cec93..e67a646e5 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 #include -#include #include #include @@ -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 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(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 b67ececd4..c8e513bf6 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 #include -#include +#include #include #include @@ -21,26 +21,34 @@ namespace vsomeip { -template -server_endpoint_impl::server_endpoint_impl( +template +server_endpoint_impl::server_endpoint_impl( std::shared_ptr _host, endpoint_type _local, boost::asio::io_service &_io, std::uint32_t _max_message_size) - : endpoint_impl(_host, _io, _max_message_size), - flush_timer_(_io), local_(_local) { + : endpoint_impl(_host, _local, _io, _max_message_size), + flush_timer_(_io) { } -template -bool server_endpoint_impl::is_client() const { +template +server_endpoint_impl::~server_endpoint_impl() { +} + +template +void server_endpoint_impl::stop() { +} + +template +bool server_endpoint_impl::is_client() const { return false; } -template -bool server_endpoint_impl::is_connected() const { +template +bool server_endpoint_impl::is_connected() const { return true; } -template -bool server_endpoint_impl::send(const uint8_t *_data, +template +bool server_endpoint_impl::send(const uint8_t *_data, uint32_t _size, bool _flush) { #if 0 std::stringstream msg; @@ -52,6 +60,10 @@ bool server_endpoint_impl::send(const uint8_t *_data, endpoint_type its_target; bool is_valid_target(false); + if(endpoint_impl::sending_blocked_) { + return false; + } + if (VSOMEIP_SESSION_POS_MAX < _size) { std::lock_guard its_lock(mutex_); @@ -66,6 +78,7 @@ bool server_endpoint_impl::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::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::send(const uint8_t *_data, return is_valid_target; } -template -bool server_endpoint_impl::send_intern( +template +bool server_endpoint_impl::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::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::send_intern( } // TODO compare against value from configuration here - if (target_packetizer->size() + _size > endpoint_impl::max_message_size_) { + const bool queue_size_zero_on_entry(target_queue_iterator->second.empty()); + if (target_packetizer->size() + _size + > endpoint_impl::max_message_size_ + && !target_packetizer->empty()) { target_queue_iterator->second.push_back(target_packetizer); - is_flushing = true; - packetizer_[_target] = std::make_shared(); + target_packetizer = std::make_shared(); + packetizer_[_target] = target_packetizer; } target_packetizer->insert(target_packetizer->end(), _data, _data + _size); @@ -126,29 +142,26 @@ bool server_endpoint_impl::send_intern( if (_flush) { flush_timer_.cancel(); target_queue_iterator->second.push_back(target_packetizer); - is_flushing = true; packetizer_[_target] = std::make_shared(); } 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::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 -bool server_endpoint_impl::flush( +template +bool server_endpoint_impl::flush( endpoint_type _target) { bool is_flushed = false; std::lock_guard its_lock(mutex_); @@ -161,14 +174,14 @@ bool server_endpoint_impl::flush( return is_flushed; } -template -void server_endpoint_impl::connect_cbk( +template +void server_endpoint_impl::connect_cbk( boost::system::error_code const &_error) { (void)_error; } -template -void server_endpoint_impl::send_cbk( +template +void server_endpoint_impl::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::send_cbk( } } -template -void server_endpoint_impl::flush_cbk( +template +void server_endpoint_impl::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::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; #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; +template class server_endpoint_impl; } // namespace vsomeip diff --git a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp index 26c7424ed..d31a38b20 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 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 0084d8e2e..fc3185007 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 _target, const byte_t *_data, uint32_t _size, bool _flush) { + std::lock_guard 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(_queue_iterator->first.port()) + << " dropping message."; + _queue_iterator->second.pop_front(); + } +} + +bool tcp_server_endpoint_impl::is_established(std::shared_ptr _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(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(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 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 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 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 a5a90ccc3..a6029db6b 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 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 4593c1f53..8b3fd3022 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 + #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( + _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 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 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 _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 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 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) { endpoint_type endpoint(_endpoint->get_address(), _endpoint->get_port()); + std::lock_guard 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 7700874d0..516619fc5 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 000000000..c9a912374 --- /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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 > +class basic_datagram_socket_ext + : public basic_socket +{ +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(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(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(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( + 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( + 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::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 + basic_datagram_socket_ext( + basic_datagram_socket_ext&& other, + typename enable_if::value>::type* = 0) + : basic_socket( + 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 enable_if::value, + basic_datagram_socket_ext>::type& operator=( + basic_datagram_socket_ext&& other) + { + basic_socket::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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + +#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 000000000..3ce03d864 --- /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 + +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +#elif defined(BOOST_ASIO_HAS_IOCP) +# include "detail/win_iocp_socket_service_ext.hpp" +#else +# include "detail/reactive_socket_service_ext.hpp" +#endif + +#include + +namespace boost { +namespace asio { + +/// Default service implementation for a datagram socket. +template +class datagram_socket_service_ext +#if defined(GENERATING_DOCUMENTATION) + : public boost::asio::io_service::service +#else + : public boost::asio::detail::service_base > +#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 service_impl_type; +#elif defined(BOOST_ASIO_HAS_IOCP) + typedef detail::win_iocp_socket_service_ext service_impl_type; +#else + typedef detail::reactive_socket_service_ext 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 >(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 + void converting_move_construct(implementation_type& impl, + typename datagram_socket_service_ext< + Protocol1>::implementation_type& other_impl, + typename enable_if::value>::type* = 0) + { + service_impl_.template converting_move_construct( + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + +#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 000000000..d81fb42f4 --- /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 + +// 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 +#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 +auto zero_arg_handler_test(Handler h, void*) + -> decltype( + sizeof(Handler(static_cast(h))), + ((h)()), + char(0)); + +template +char (&zero_arg_handler_test(Handler, ...))[2]; + +template +auto one_arg_handler_test(Handler h, Arg1* a1) + -> decltype( + sizeof(Handler(static_cast(h))), + ((h)(*a1)), + char(0)); + +template +char (&one_arg_handler_test(Handler h, ...))[2]; + +template +auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2) + -> decltype( + sizeof(Handler(static_cast(h))), + ((h)(*a1, *a2)), + char(0)); + +template +char (&two_arg_handler_test(Handler, ...))[2]; + +template +auto three_arg_handler_test(Handler h, Arg1* a1, Arg2* a2, Arg3* a3) + -> decltype( + sizeof(Handler(static_cast(h))), + ((h)(*a1, *a2, *a3)), + char(0)); + +template +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 T& lvref(); +template T& lvref(T); +template const T& clvref(); +template const T& clvref(T); +template char argbyv(T); + +#if 0 +template +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(0), \ + static_cast(0), \ + static_cast(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(), \ + boost::asio::detail::lvref(), \ + boost::asio::detail::lvref()), \ + 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(0), \ + static_cast(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(), \ + boost::asio::detail::lvref()), \ + 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(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()), \ + 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(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()), \ + 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(0), \ + static_cast(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(), \ + boost::asio::detail::lvref()), \ + 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(0), \ + static_cast(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(), \ + boost::asio::detail::lvref()), \ + 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(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()), \ + 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(0), \ + static_cast(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(), \ + boost::asio::detail::lvref()), \ + 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(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()), \ + 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(0), \ + static_cast(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(), \ + boost::asio::detail::lvref()), \ + 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(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()), \ + 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 000000000..fe50185ce --- /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 + +#if !defined(BOOST_ASIO_HAS_IOCP) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include + +#include + +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(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 + +#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 000000000..cf8067038 --- /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 + +#include + +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(*addrlen); + msg.msg_iov = bufs; + msg.msg_iovlen = static_cast(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 + +#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 000000000..c4f45472b --- /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 +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +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(base)); + + buffer_sequence_adapter 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 +class reactive_socket_recv_op_ext : + public reactive_socket_recv_op_base_ext +{ +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(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(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(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 + +#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 000000000..afa6a661b --- /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 +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +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(base)); + + buffer_sequence_adapter 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 +class reactive_socket_recvfrom_op_ext : + public reactive_socket_recvfrom_op_base_ext +{ +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( + 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(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(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 + +#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 000000000..ba0a71484 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +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(base)); + + buffer_sequence_adapter 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 +class reactive_socket_recvmsg_op_ext : + public reactive_socket_recvmsg_op_base_ext +{ +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(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(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(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 + +#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 000000000..cd0b19fe8 --- /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 + +#include + +#if !defined(BOOST_ASIO_HAS_IOCP) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 + 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(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 + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter 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 + 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 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::all_empty(buffers))); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + 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 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 + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter 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 + 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 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::all_empty(buffers))); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + 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 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 + 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 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 + 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 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 + 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 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 + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#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 000000000..a13e5c87c --- /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 + +#include + +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +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 + 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 + 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 + 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 + 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 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 + 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 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 + 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 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 + 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 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 + 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 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 + 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 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 + 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 + 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 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 + 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 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 + +#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 000000000..575fba2ee --- /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 + +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 000000000..9280830a2 --- /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 + +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 +#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 000000000..d5f054e67 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include + +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 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 socket; + + /// The UDP resolver type. + typedef basic_resolver 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 + +#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 000000000..bef1a7233 --- /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 1b7fd0921..20311585b 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 555f15e29..7bbc00a36 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 ddc4eb277..391687407 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 @@ class logger_impl: public logger { 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 b4d286411..9da5ae977 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 +#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 03f05aa90..54b5d7591 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 6bf4e08d4..3934c1eb3 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 #endif +#include + #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) { 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 backend = boost::make_shared(); + boost::shared_ptr backend = boost::make_shared(_app_id, + _context_id); dlt_sink_ = boost::make_shared(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 941358be0..0588aa73a 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 58562f199..40486a291 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 @@ class message_base_impl 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 b233d75d7..18f734dc9 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 7c8902ca7..102833ae1 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 #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 2530ac83f..66b3afa6b 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 427ee2038..7928a526f 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 6017d5a6f..fb6f67081 100644 --- a/implementation/message/src/deserializer.cpp +++ b/implementation/message/src/deserializer.cpp @@ -8,12 +8,11 @@ #ifdef VSOMEIP_DEBUGGING #include #include - -#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 616ed638a..c9597fc6c 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 203663636..9033160da 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 { 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 @@ class event: public std::enable_shared_from_this { void set_payload(std::shared_ptr _payload, const std::shared_ptr _target); + void set_payload_dont_notify(std::shared_ptr _payload); + void set_payload(std::shared_ptr _payload); - void unset_payload(); + void unset_payload(bool _force = false); bool is_field() const; void set_field(bool _is_field); @@ -57,6 +59,8 @@ class event: public std::enable_shared_from_this { 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 @@ class event: public std::enable_shared_from_this { void set_eventgroups(const std::set &_eventgroups); void notify_one(const std::shared_ptr &_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 @@ class event: public std::enable_shared_from_this { bool is_set_; bool is_provided_; - uint32_t ref_; + std::map> 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 08536e0b3..7e832a1a5 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 +#include #include #include @@ -21,6 +23,15 @@ class event; class eventgroupinfo { public: + struct target_t { + std::shared_ptr 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 @@ class eventgroupinfo { VSOMEIP_EXPORT void add_event(std::shared_ptr _event); VSOMEIP_EXPORT void remove_event(std::shared_ptr _event); - VSOMEIP_EXPORT const std::set< - std::shared_ptr > get_targets() const; - VSOMEIP_EXPORT bool add_target(std::shared_ptr _target); - VSOMEIP_EXPORT bool remove_target(std::shared_ptr _target); + VSOMEIP_EXPORT const std::list 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 &_target, + const std::chrono::high_resolution_clock::time_point &_expiration); + VSOMEIP_EXPORT bool remove_target( + const std::shared_ptr &_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 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 > events_; - std::set > targets_; + std::list targets_; + std::list multicast_targets_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager.hpp b/implementation/routing/include/routing_manager.hpp index 26426772d..ee189576c 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 #include +#include namespace vsomeip { @@ -39,7 +40,7 @@ class routing_manager { 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 @@ class routing_manager { 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 @@ class routing_manager { 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 &_target, std::shared_ptr) = 0; @@ -69,17 +71,26 @@ class routing_manager { virtual void register_event(client_t _client, service_t _service, instance_t _instance, event_t _event, const std::set &_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 get_event(service_t _service, + instance_t _instance, event_t _event) const = 0; + + virtual std::set> 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) = 0; virtual void notify_one(service_t _service, instance_t _instance, event_t _event, std::shared_ptr _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 fc0e55d0d..0dfe70322 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 000000000..1d69f6f2d --- /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 +#include + +#include +#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{ + +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 &_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 get_event(service_t _service, + instance_t _instance, event_t _event) const; + + virtual std::set> 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); + + virtual void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr _payload, client_t _client); + + virtual bool send(client_t _client, std::shared_ptr _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) = 0; + virtual void on_disconnect(std::shared_ptr _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 find_service(service_t _service, instance_t _instance) const; + std::shared_ptr 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 create_local(client_t _client); + std::shared_ptr find_or_create_local(client_t _client); + void remove_local(client_t _client); + std::shared_ptr find_local(client_t _client); + std::shared_ptr find_local(service_t _service, + instance_t _instance); + + std::unordered_set get_connected_clients(); + + std::shared_ptr find_event(service_t _service, instance_t _instance, + event_t _event) const; + std::shared_ptr find_eventgroup(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const; + + std::set 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 &_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_; + std::shared_ptr serializer_; + std::shared_ptr deserializer_; + + std::mutex serialize_mutex_; + + std::mutex local_services_mutex_; + std::map > > local_services_; + + // Eventgroups + mutable std::mutex eventgroups_mutex_; + std::map > > > eventgroups_; + mutable std::mutex events_mutex_; + std::map > > > events_; + std::mutex eventgroup_clients_mutex_; + std::map > > > eventgroup_clients_; + +#ifdef USE_DLT + std::shared_ptr tc_; +#endif + +private: + services_t services_; + mutable std::mutex services_mutex_; + + std::map > 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 7b96be03c..3a60d8cd8 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 @@ class routing_manager_host { 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) = 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 9741f3e0d..13936a46d 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 #include #include +#include #include #include #include #include +#include -#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 { + public sd::service_discovery_host { public: routing_manager_impl(routing_manager_host *_host); ~routing_manager_impl(); @@ -66,7 +63,7 @@ class routing_manager_impl: public routing_manager, 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 @@ class routing_manager_impl: public routing_manager, bool send(client_t _client, std::shared_ptr _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 &_target, std::shared_ptr _message); @@ -93,12 +90,15 @@ class routing_manager_impl: public routing_manager, bool send_to(const std::shared_ptr &_target, const byte_t *_data, uint32_t _size); - void register_event(client_t _client, service_t _service, + bool send_to(const std::shared_ptr &_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 &_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 @@ class routing_manager_impl: public routing_manager, void notify_one(service_t _service, instance_t _instance, event_t _event, std::shared_ptr _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 create_local(client_t _client); std::shared_ptr find_local(client_t _client); std::shared_ptr find_or_create_local(client_t _client); void remove_local(client_t _client); - std::shared_ptr 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 find_or_create_remote_client(service_t _service, @@ -124,11 +133,14 @@ class routing_manager_impl: public routing_manager, void on_connect(std::shared_ptr _endpoint); void on_disconnect(std::shared_ptr _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 > servicegroups_t; @@ -147,12 +159,17 @@ class routing_manager_impl: public routing_manager, 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 _subscriber, - std::shared_ptr _target); + std::shared_ptr _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 _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 _target); @@ -162,45 +179,34 @@ class routing_manager_impl: public routing_manager, 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 &_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 find_local_clients(service_t _service, - instance_t _instance, eventgroup_t _eventgroup); + instance_t find_instance(service_t _service, endpoint *_endpoint); - std::shared_ptr find_service(service_t _service, - instance_t _instance) const; - std::shared_ptr 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 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 create_server_endpoint(uint16_t _port, bool _reliable, bool _start); std::shared_ptr find_server_endpoint(uint16_t _port, - bool _reliable); + bool _reliable) const; std::shared_ptr find_or_create_server_endpoint(uint16_t _port, bool _reliable, bool _start); - std::set > find_events(service_t _service, - instance_t _instance, eventgroup_t _eventgroup); - std::shared_ptr 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 @@ class routing_manager_impl: public routing_manager, void clear_client_endpoints(service_t _service, instance_t _instance, bool _reliable); void stop_and_delete_client_endpoint(std::shared_ptr _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 @@ class routing_manager_impl: public routing_manager, 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_; - std::shared_ptr serializer_; + bool supports_selective(service_t _service, instance_t _instance); - std::shared_ptr configuration_; + client_t find_client(service_t _service, instance_t _instance, + const std::shared_ptr &_eventgroup, + const std::shared_ptr &_target) const; + + void clear_remote_subscriber(service_t _service, instance_t _instance, + client_t _client, + const std::shared_ptr &_target); std::shared_ptr stub_; std::shared_ptr discovery_; - // Routing info - - // Local - std::map > local_clients_; - std::map > local_services_; - // Server endpoints for local services std::map > > server_endpoints_; std::map > service_instances_; @@ -268,29 +262,27 @@ class routing_manager_impl: public routing_manager, std::map > > > >remote_services_; std::map > > > client_endpoints_by_ip_; - - // Services - services_t services_; - - // Eventgroups - std::map > > > eventgroups_; - std::map > > > events_; - std::map > > > eventgroup_clients_; + std::map>>>> 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>>>> remote_subscribers_; + + std::mutex specific_endpoint_clients_mutex_; + std::map>>specific_endpoint_clients_; + std::map > > >identified_clients_; - std::map> remote_subscriber_map_; + std::shared_ptr sd_info_; - std::unordered_set specific_endpoint_clients; + std::map> used_client_ports_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_proxy.hpp index 05775978b..d2f61d7b6 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 -#include "routing_manager.hpp" -#include "../../endpoints/include/endpoint_host.hpp" +#include "routing_manager_base.hpp" #include +#include 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 { +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 @@ class routing_manager_proxy: public routing_manager, 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 @@ class routing_manager_proxy: public routing_manager, void unsubscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup); - bool send(client_t _client, std::shared_ptr _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 &_target, std::shared_ptr _message); @@ -73,7 +64,7 @@ class routing_manager_proxy: public routing_manager, void register_event(client_t _client, service_t _service, instance_t _instance, event_t _event, const std::set &_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 @@ class routing_manager_proxy: public routing_manager, void notify(service_t _service, instance_t _instance, event_t _event, std::shared_ptr _payload); - void notify_one(service_t _service, instance_t _instance, - event_t _event, std::shared_ptr _payload, - client_t _client); - void on_connect(std::shared_ptr _endpoint); void on_disconnect(std::shared_ptr _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 find_local(client_t _client); - std::shared_ptr find_local(service_t _service, - instance_t _instance); - std::shared_ptr 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 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 @@ class routing_manager_proxy: public routing_manager, 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, @@ -120,29 +108,38 @@ class routing_manager_proxy: public routing_manager, 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); + + 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_; - - std::shared_ptr serializer_; - std::shared_ptr deserializer_; std::shared_ptr sender_; // --> stub std::shared_ptr receiver_; // --> from everybody - std::map > local_endpoints_; - std::map > local_services_; - std::map > service_versions_; - std::mutex local_services_mutex_; + std::unordered_set known_clients_; struct service_data_t { service_t service_; @@ -196,6 +193,7 @@ class routing_manager_proxy: public routing_manager, } }; std::set pending_subscriptions_; + std::map> pending_ingoing_subscripitons_; std::map > > > pending_notifications_; std::mutex send_mutex_; - std::mutex serialize_mutex_; std::mutex deserialize_mutex_; std::mutex pending_mutex_; - - std::map > > fields_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_stub.hpp b/implementation/routing/include/routing_manager_stub.hpp index 6a1ec38f5..27b8ec527 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 #include #include #include #include #include +#include #include #include @@ -36,13 +38,32 @@ class routing_manager_stub: public endpoint_host, void on_connect(std::shared_ptr _endpoint); void on_disconnect(std::shared_ptr _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 _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 _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 &_command) const; @@ -50,8 +71,8 @@ class routing_manager_stub: public endpoint_host, 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 @@ class routing_manager_stub: public endpoint_host, void check_watchdog(); void send_application_lost(std::list &_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_; + std::shared_ptr local_receiver_; std::map > > > routing_info_; + std::pair> > > > routing_info_; mutable std::mutex routing_info_mutex_; std::shared_ptr configuration_; + + size_t routingCommandSize_; + + bool client_registration_running_; + std::shared_ptr client_registration_thread_; + std::mutex client_registration_mutex_; + std::condition_variable client_registration_condition_; + std::map> 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 d56f2d39c..e216b5a2e 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 +#include namespace vsomeip { @@ -20,7 +21,7 @@ class routing_manager_stub_host { 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 @@ class routing_manager_stub_host { 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 &_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 @@ class routing_manager_stub_host { 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 find_local(client_t _client) = 0; - virtual std::shared_ptr find_local(service_t _service, - instance_t _instance) = 0; + virtual std::shared_ptr 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 af3a50c58..44050b8e6 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 #include #include +#include #include #include @@ -33,21 +34,16 @@ class serviceinfo { 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 get_endpoint(bool _reliable) const; VSOMEIP_EXPORT void set_endpoint(std::shared_ptr _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 @@ class serviceinfo { major_version_t major_; minor_version_t minor_; - ttl_t ttl_; + std::chrono::milliseconds ttl_; std::shared_ptr reliable_; std::shared_ptr unreliable_; - std::string multicast_address_; - uint16_t multicast_port_; - eventgroup_t multicast_group_; - std::set requesters_; bool is_local_; diff --git a/implementation/routing/include/types.hpp b/implementation/routing/include/types.hpp index 60b97bc1b..c483aee0d 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 b553415dd..d5365973b 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 event::get_payload() const { return (message_->get_payload()); } +void event::set_payload_dont_notify(std::shared_ptr _payload) { + if(is_cache_placeholder_) { + std::shared_ptr 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 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) { if (is_provided_) { if (set_payload_helper(_payload)) { @@ -89,6 +113,9 @@ void event::set_payload(std::shared_ptr _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, 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, 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()); + } else { + if (is_provided_) { + is_set_ = false; + message_->set_payload(std::make_shared()); + } } } @@ -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 &_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) { @@ -210,13 +266,54 @@ bool event::set_payload_helper(std::shared_ptr _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 0d098e436..138096964 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 + #include + #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 > eventgroupinfo::get_events() const { @@ -68,20 +73,77 @@ void eventgroupinfo::remove_event(std::shared_ptr _event) { events_.erase(_event); } -const std::set > eventgroupinfo::get_targets() const { +const std::list eventgroupinfo::get_targets() const { return targets_; } -bool eventgroupinfo::add_target(std::shared_ptr _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::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 &_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 _target) { + const std::shared_ptr &_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 000000000..1a04a2097 --- /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 + +#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()), + deserializer_(std::make_shared()) +#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 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 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 &_eventgroups, + bool _is_field, bool _is_provided, bool _is_shadow, + bool _is_cache_placeholder) { + std::shared_ptr 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 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 its_eventgroups; + its_eventgroups.insert(_event); + its_event->set_eventgroups(its_eventgroups); + } else { + its_event->set_eventgroups(_eventgroups); + } + + } + } else { + its_event = std::make_shared(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 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 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 its_eventgroup_info + = find_eventgroup(_service, _instance, eg); + if (!its_eventgroup_info) { + its_eventgroup_info = std::make_shared(); + std::lock_guard its_lock(eventgroups_mutex_); + eventgroups_[_service][_instance][eg] = its_eventgroup_info; + } + its_eventgroup_info->add_event(its_event); + } + + std::lock_guard 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 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 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 routing_manager_base::get_event( + service_t _service, instance_t _instance, event_t _event) const { + std::shared_ptr its_event; + std::lock_guard 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> routing_manager_base::find_events( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const { + std::lock_guard its_lock(eventgroups_mutex_); + std::set > 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 > 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 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) { + std::shared_ptr 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, client_t _client) { + std::shared_ptr 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, + bool _flush) { + bool is_sent(false); + if (utility::is_request(_message->get_message_type())) { + _message->set_client(its_client); + } + std::lock_guard 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 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 its_lock(services_mutex_); + std::shared_ptr its_info = + std::make_shared(_major, _minor, _ttl, _is_local_service); + services_[_service][_instance] = its_info; + return its_info; +} + +std::shared_ptr routing_manager_base::find_service( + service_t _service, instance_t _instance) const { + std::shared_ptr its_info; + std::lock_guard 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 its_info(find_service(_service, _instance)); + if (!its_info) { + return; + } + // Clear service_info and service_group + std::shared_ptr 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 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 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 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 routing_manager_base::create_local(client_t _client) { + std::lock_guard 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 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 routing_manager_base::find_local(client_t _client) { + std::lock_guard its_lock(local_endpoint_mutex_); + std::shared_ptr 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 routing_manager_base::find_or_create_local(client_t _client) { + std::shared_ptr 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 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 its_lock(local_endpoint_mutex_); + local_endpoints_.erase(_client); + } + { + std::lock_guard its_lock(local_services_mutex_); + // Finally remove all services that are implemented by the client. + std::set> 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 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 routing_manager_base::find_local(service_t _service, + instance_t _instance) { + return find_local(find_local_client(_service, _instance)); +} + +std::unordered_set routing_manager_base::get_connected_clients() { + std::lock_guard its_lock(local_endpoint_mutex_); + std::unordered_set clients; + for (auto its_client : local_endpoints_) { + clients.insert(its_client.first); + } + return clients; +} + +std::shared_ptr routing_manager_base::find_event(service_t _service, + instance_t _instance, event_t _event) const { + std::shared_ptr its_event; + std::lock_guard 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 routing_manager_base::find_eventgroup( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const { + std::lock_guard its_lock(eventgroups_mutex_); + + std::shared_ptr 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 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 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 routing_manager_base::find_local_clients(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) { + std::set its_clients; + std::lock_guard 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 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(_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 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 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& _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 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 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 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 13ec3329d..3c9833489 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 #include #include #include @@ -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()), - serializer_(std::make_shared()), - 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(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 its_info; + std::shared_ptr its_info = find_service(_service, _instance); + { - std::lock_guard its_lock(local_mutex_); - local_services_[_service][_instance] = _client; + std::lock_guard 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 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 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 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 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 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 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 its_eventgroup - = find_eventgroup(_service, _instance, _eventgroup); - if (its_eventgroup) { - std::set > 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 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 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 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, bool _flush) { - bool is_sent(false); - - if (utility::is_request(_message->get_message_type())) { - _message->set_client(its_client); - } - - std::lock_guard 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 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 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 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 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 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 its_unreliable_target = its_info->get_endpoint(false); std::shared_ptr 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& _target, client_t _client, - const byte_t *_data, uint32_t _size, - instance_t _instance, - bool _flush, bool _reliable) const { - - std::lock_guard its_lock(endpoint_mutex_); - - std::vector 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 &_target, std::shared_ptr _message) { @@ -439,95 +496,56 @@ bool routing_manager_impl::send_to( std::shared_ptr 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 &_eventgroups, - bool _is_field, bool _is_provided) { - (void)_client; - - std::shared_ptr 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(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 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 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 &_target, + const byte_t *_data, uint32_t _size, uint16_t _sd_port) { + std::shared_ptr its_endpoint = find_server_endpoint( + _sd_port, _target->is_reliable()); - for (auto eg : _eventgroups) { - std::shared_ptr its_eventgroup_info - = find_eventgroup(_service, _instance, eg); - if (!its_eventgroup_info) { - its_eventgroup_info = std::make_shared(); - 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 &_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 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, client_t _client) { - - std::shared_ptr 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 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(_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(_data)[VSOMEIP_CLIENT_POS_MIN] = 0; - const_cast(_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 its_event - = find_event(_service, _instance, its_method); - if (its_event) { - uint32_t its_length = utility::get_payload_size(_data, _size); - std::shared_ptr 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 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 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) { 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 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 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) { 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 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 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) { } 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 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 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 its_event = find_event(_service, _instance, its_method); if (its_event) { std::vector< byte_t > its_data; - + std::set 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 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 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 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 routing_manager_impl::find_eventgroup( service_t _service, instance_t _instance, eventgroup_t _eventgroup) const { - std::lock_guard its_lock(eventgroups_mutex_); - - std::shared_ptr 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 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 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 routing_manager_impl::get_configuration() const { @@ -1018,16 +1010,11 @@ std::shared_ptr routing_manager_impl::create_service_discovery_endpoin its_service_endpoint = create_server_endpoint(_port, _reliable, true); if (its_service_endpoint) { - std::shared_ptr its_info( - std::make_shared(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(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 routing_manager_impl::create_service_discovery_endpoin } services_t routing_manager_impl::get_offered_services() const { - services_t its_offers; - std::lock_guard 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 routing_manager_impl::find_or_create_remote_client( @@ -1064,26 +1050,12 @@ std::shared_ptr routing_manager_impl::find_or_create_remote_client( /////////////////////////////////////////////////////////////////////////////// // PRIVATE /////////////////////////////////////////////////////////////////////////////// -std::shared_ptr routing_manager_impl::find_service( - service_t _service, instance_t _instance) const { - std::shared_ptr its_info; - std::lock_guard 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 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 its_info; +void routing_manager_impl::init_service_info( + service_t _service, instance_t _instance, bool _is_local_service) { + std::shared_ptr its_info = find_service(_service, _instance); if (configuration_) { - its_info = std::make_shared(_major, _minor, _ttl, _is_local_service); + std::shared_ptr its_reliable_endpoint; + std::shared_ptr its_unreliable_endpoint; uint16_t its_reliable_port = configuration_->get_reliable_port(_service, _instance); @@ -1092,16 +1064,6 @@ std::shared_ptr 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 its_reliable_endpoint; - std::shared_ptr 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 routing_manager_impl::create_service_info( << "]. Service is internal."; } } - - { - std::lock_guard its_lock(services_mutex_); - services_[_service][_instance] = its_info; - } } else { host_->on_error(error_code_e::CONFIGURATION_MISSING); } - - return (its_info); } std::shared_ptr 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 routing_manager_impl::create_client_endpoint( if (_reliable) { its_endpoint = std::make_shared( 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( 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 routing_manager_impl::create_server_endpoint( } std::shared_ptr routing_manager_impl::find_server_endpoint( - uint16_t _port, bool _reliable) { + uint16_t _port, bool _reliable) const { std::shared_ptr its_endpoint; std::lock_guard its_lock(endpoint_mutex_); auto found_port = server_endpoints_.find(_port); @@ -1235,126 +1203,32 @@ std::shared_ptr routing_manager_impl::find_server_endpoint( if (found_endpoint != found_port->second.end()) { its_endpoint = found_endpoint->second; } - } - return (its_endpoint); -} - -std::shared_ptr routing_manager_impl::find_or_create_server_endpoint( - uint16_t _port, bool _reliable, bool _start) { - std::shared_ptr its_endpoint = find_server_endpoint(_port, - _reliable); - if (0 == its_endpoint) { - its_endpoint = create_server_endpoint(_port, _reliable, _start); - } - return (its_endpoint); -} - -std::shared_ptr routing_manager_impl::find_local(client_t _client) { - std::lock_guard its_lock(endpoint_mutex_); - std::shared_ptr 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 routing_manager_impl::create_local(client_t _client) { - std::lock_guard 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 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); } -std::shared_ptr routing_manager_impl::find_or_create_local( - client_t _client) { - std::shared_ptr its_endpoint(find_local(_client)); +std::shared_ptr routing_manager_impl::find_or_create_server_endpoint( + uint16_t _port, bool _reliable, bool _start) { + std::shared_ptr its_endpoint = find_server_endpoint(_port, + _reliable); if (!its_endpoint) { - its_endpoint = create_local(_client); + its_endpoint = create_server_endpoint(_port, _reliable, _start); } return (its_endpoint); } -void routing_manager_impl::remove_local(client_t _client) { - { - std::lock_guard its_lock(endpoint_mutex_); - std::shared_ptr its_endpoint = find_local(_client); - its_endpoint->stop(); - local_clients_.erase(_client); - } - { - std::lock_guard its_lock(local_mutex_); - // Finally remove all services that are implemented by the client. - std::set> 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 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; +std::shared_ptr routing_manager_impl::find_local(client_t _client) { + return routing_manager_base::find_local(_client); } -client_t routing_manager_impl::find_local_client(service_t _service, - instance_t _instance) { - std::lock_guard 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::shared_ptr routing_manager_impl::find_or_create_local( + client_t _client) { + return routing_manager_base::find_or_create_local(_client); } -std::set routing_manager_impl::find_local_clients(service_t _service, - instance_t _instance, eventgroup_t _eventgroup) { - std::set 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); +void routing_manager_impl::remove_local(client_t _client) { + routing_manager_base::remove_local(_client); } instance_t routing_manager_impl::find_instance(service_t _service, @@ -1374,34 +1248,42 @@ std::shared_ptr routing_manager_impl::create_remote_client( service_t _service, instance_t _instance, bool _reliable, client_t _client) { std::shared_ptr its_endpoint; std::shared_ptr 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 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 routing_manager_impl::find_remote_client( return its_endpoint; } -std::shared_ptr routing_manager_impl::find_event(service_t _service, - instance_t _instance, event_t _event) const { - std::shared_ptr 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 > routing_manager_impl::find_events( - service_t _service, instance_t _instance, eventgroup_t _eventgroup) { - std::set > 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 &_eventgroup, + const std::shared_ptr &_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(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(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 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 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 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 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 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 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 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(default_ttl); std::map > > 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 > > 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 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 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> its_invalid_targets; + std::set> 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 _subscriber, - std::shared_ptr _target) { +bool routing_manager_impl::on_subscribe_accepted(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, const std::shared_ptr _target, + const std::chrono::high_resolution_clock::time_point &_expiration) { std::shared_ptr 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(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(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; + } + + 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."; + } - send_subscribe(client, _service, _instance, _eventgroup, its_eventgroup->get_major()); + stub_->send_subscribe(routing_manager_base::find_local(_service, _instance), + client, _service, _instance, _eventgroup, its_eventgroup->get_major(), true); + + remote_subscribers_[_service][_instance][client].insert(_target); + } else { + VSOMEIP_ERROR<< "subscribe: attempt to subscribe to unknown eventgroup!"; + return false; + } + return true; +} - remote_subscriber_map_[client] = _target; +void routing_manager_impl::on_subscribe( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + std::shared_ptr _subscriber, + std::shared_ptr _target, + const std::chrono::high_resolution_clock::time_point &_expiration) { - if (its_eventgroup->add_target(_target)) { // unicast or multicast + std::shared_ptr 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 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(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(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 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 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 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 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 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 its_info(find_service(_service, _instance)); - if (!its_info) { - return; - } - // Clear service_info and service_group - std::shared_ptr 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 (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(_receiver)->get_remote(); + auto endpoint = dynamic_cast(_receiver); + if(!endpoint) { + return; + } + auto remote = endpoint->get_remote(); adr = remote.address(); port = remote.port(); } else { - auto remote = static_cast(_receiver)->get_remote(); + auto endpoint = dynamic_cast(_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(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 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 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 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; +} + +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 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 &_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 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> 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 + +} // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_proxy.cpp b/implementation/routing/src/routing_manager_proxy.cpp index 45346bff5..0a3f7b559 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 #include #include +#include +#include + +#ifndef WIN32 +// for umask +#include +#include +#endif #include #include @@ -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()), - deserializer_(std::make_shared()), 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(configuration_->get_umask()))); #endif receiver_ = std::make_shared(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 its_lock(pending_mutex_); - pending_offers_.insert(offer); } + service_data_t offer = { _service, _instance, _major, _minor, false }; + std::lock_guard 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 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 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 &_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(_is_provided); sender_->send(its_command, sizeof(its_command)); - } else { - std::lock_guard 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 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 its_lock(pending_mutex_); - pending_subscriptions_.insert(subscription); } + eventgroup_data_t subscription = { _service, _instance, _eventgroup, _major, + _subscription_type}; + std::lock_guard 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 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, - bool _flush) { - bool is_sent(false); - - std::lock_guard 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 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 its_target; + bool _reliable, + bool _initial) { + bool is_sent(false); if (_size > VSOMEIP_MESSAGE_TYPE_POS) { + std::shared_ptr 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 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 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 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 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, client_t _client) { - - std::shared_ptr 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) { - 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 > old_local_services; + bool restart_sender(_size == 0); + std::map > > old_local_services; + std::unordered_set clients_to_delete; { std::lock_guard its_lock(local_services_mutex_); old_local_services = local_services_; local_services_.clear(); + std::unordered_set 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 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 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 routing_manager_proxy::find_local(client_t _client) { - std::shared_ptr 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 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 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 routing_manager_proxy::find_or_create_local( - client_t _client) { - std::shared_ptr 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 its_endpoint(find_local(_client)); - if (its_endpoint) - its_endpoint->stop(); - local_endpoints_.erase(_client); -} - -std::shared_ptr routing_manager_proxy::find_local(service_t _service, - instance_t _instance) { - client_t its_client(0); - std::lock_guard 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 &_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 its_server_endpoint + = std::dynamic_pointer_cast(receiver_); + return its_server_endpoint->queue_message(_data, _size); +} + +void routing_manager_proxy::cache_event_payload( + const std::shared_ptr &_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 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 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 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 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 7f8aad825..01ca85ab0 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 #include #include -#include + +#ifndef WIN32 +// for umask +#include +#include +#endif #include @@ -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(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::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) { @@ -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 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 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 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 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 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 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> 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 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 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 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 its_endpoint = host_->find_local(_client); if (its_endpoint) { - uint32_t its_capacity = 4096; // TODO: dynamic resizing - std::vector 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 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(&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(&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(&its_service_entry_size)[i]); + } + // Service + for (uint32_t i = 0; i < sizeof(service_t); ++i) { + its_command.push_back( + reinterpret_cast(&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(&instance)[i]); + } + // Major version + for (uint32_t i = 0; i < sizeof(major_version_t); ++i) { + its_command.push_back( + reinterpret_cast(&instance.second.first)[i]); + } + // Minor version + for (uint32_t i = 0; i < sizeof(minor_version_t); ++i) { + its_command.push_back( + reinterpret_cast(&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 &_command) const { } } +void routing_manager_stub::send_subscribe(std::shared_ptr _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 _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 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 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 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 its_callback = [this](boost::system::error_code const &_error) { @@ -477,42 +856,27 @@ void routing_manager_stub::check_watchdog() { std::lock_guard 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 &_lost) { - uint32_t its_size = uint32_t(_lost.size() * sizeof(client_t)); - std::vector 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 its_server_endpoint + = std::dynamic_pointer_cast(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 75d11dd1c..fcf535ebb 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 (_ttl); + ttl_ = std::chrono::duration_cast(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(std::chrono::duration_cast(ttl_).count()); + return ttl; } void serviceinfo::set_ttl(ttl_t _ttl) { - ttl_ = _ttl; + std::chrono::seconds ttl = static_cast(_ttl); + ttl_ = std::chrono::duration_cast (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 serviceinfo::get_endpoint(bool _reliable) const { @@ -59,30 +71,6 @@ void serviceinfo::set_endpoint(std::shared_ptr _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(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 fea635e56..06f60eb06 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 #include +#include #include #include @@ -47,8 +48,8 @@ class application_impl: public application, 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 @@ class application_impl: public application, 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, bool _flush); @@ -97,15 +99,25 @@ class application_impl: public application, 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 @@ class application_impl: public application, 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); 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 _handler) : + handler_(_handler), + is_dispatching_(false) { } + + std::function handler_; + bool is_dispatching_; + }; + + // + // Methods + // void service(); inline void update_session() { session_++; @@ -132,10 +162,36 @@ class application_impl: public application, } } + bool is_available_unlocked(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const; + + typedef std::map>> 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 &_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 @@ class application_impl: public application, // Proxy to or the Routing Manager itself std::shared_ptr routing_; + // vsomeip state (registered / deregistered) + state_type_e state_; + // vsomeip state handler state_handler_t handler_; @@ -162,31 +221,43 @@ class application_impl: public application, mutable std::mutex members_mutex_; // Availability handlers - std::map > availability_; + std::map>> availability_; mutable std::mutex availability_mutex_; // Availability - mutable std::map> available_; + mutable available_t available_; - // Subscriptopn handlers + // Subscription handlers std::map>> subscription_; mutable std::mutex subscription_mutex_; + std::map > > > 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 dispatchers_; - std::atomic_bool is_dispatching_; - // Handlers - mutable std::deque> handlers_; - - // Condition to wake up - mutable std::mutex dispatch_mutex_; - mutable std::condition_variable dispatch_condition_; + mutable std::deque> handlers_; + mutable std::mutex handlers_mutex_; + + // Dispatching + bool is_dispatching_; + // Dispatcher threads + std::map> dispatchers_; + // Dispatcher threads that elapsed and can be removed + std::set elapsed_dispatchers_; + // Dispatcher threads that blocked + std::set 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_; @@ -195,6 +266,16 @@ class application_impl: public application, 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>> event_subscriptions_; }; } // namespace vsomeip diff --git a/implementation/runtime/include/runtime_impl.hpp b/implementation/runtime/include/runtime_impl.hpp index 123272bfc..a81b00e5a 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 get(); virtual ~runtime_impl(); @@ -37,6 +41,7 @@ class runtime_impl: public runtime { private: static std::shared_ptr the_runtime_; + static std::map properties_; std::map> applications_; }; diff --git a/implementation/runtime/src/application_impl.cpp b/implementation/runtime/src/application_impl.cpp index c9efed447..dc7bda55a 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 #endif -#include #include +#include #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 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(this); } else { routing_ = std::make_shared(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 its_trace_connector = tc::trace_connector::get(); + std::shared_ptr 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 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 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::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 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 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 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& 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 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 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 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, 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 its_lock(availability_mutex_); - availability_[_service][_instance] = _handler; + std::unique_lock 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 handlers_lock(handlers_mutex_); + + std::shared_ptr its_sync_handler + = std::make_shared([_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 its_lock(availability_mutex_); + instance_t _instance, major_version_t _major, minor_version_t _minor) { + std::lock_guard 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 its_lock(subscription_mutex_); + std::lock_guard 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 its_lock(subscription_mutex_); + std::lock_guard its_lock(subscription_mutex_); subscription_[_service][_instance][_eventgroup] = _handler; + + message_handler_t handler([&](const std::shared_ptr& 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 its_lock(subscription_mutex_); + std::lock_guard 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 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 handlers_lock(handlers_mutex_); + std::shared_ptr its_sync_handler + = std::make_shared([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 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 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 its_lock(members_mutex_); + std::lock_guard 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 its_lock(members_mutex_); + std::lock_guard 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 its_lock(dispatch_mutex_); - handlers_.push_back([this, _state]() { - handler_(_state); - }); - dispatch_condition_.notify_one(); - } else { - handler_(_state); + { + std::lock_guard its_lock(handlers_mutex_); + + std::shared_ptr its_sync_handler + = std::make_shared([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::const_iterator found_instance; + std::map::const_iterator found_minor; availability_handler_t its_handler; - std::map::const_iterator found_wildcard_instance; + std::map::const_iterator found_wildcard_minor; availability_handler_t its_wildcard_handler; bool has_handler(false); bool has_wildcard_handler(false); { - std::unique_lock its_lock(availability_mutex_); - - if (_is_available == is_available(_service, _instance)) + std::lock_guard 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 handlers_lock(handlers_mutex_); if (has_handler) { - std::unique_lock 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 its_sync_handler + = std::make_shared( + [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 its_sync_handler + = std::make_shared( + [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 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) { @@ -587,8 +980,36 @@ void application_impl::on_message(std::shared_ptr _message) { message_handler_t its_handler; bool has_handler(false); + if (_message->get_message_type() == message_type_e::MT_NOTIFICATION) { + std::lock_guard 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 its_lock(members_mutex_); + std::lock_guard 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) { } } } - } - if (has_handler) { - if (num_dispatchers_ > 0) { - std::unique_lock 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 its_lock(handlers_mutex_); + std::shared_ptr its_sync_handler + = std::make_shared( + [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 handler; +void application_impl::main_dispatch() { while (is_dispatching_) { - { - std::unique_lock its_lock(dispatch_mutex_); - if (handlers_.empty()) { - dispatch_condition_.wait(its_lock); - continue; - } else { - handler = handlers_.front(); + std::unique_lock 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 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 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 its_lock(handlers_mutex_); + if (handlers_.empty()) { + dispatcher_condition_.wait(its_lock); + if (handlers_.empty()) { // Maybe woken up from main dispatcher + std::lock_guard its_lock(dispatcher_mutex_); + elapsed_dispatchers_.insert(its_id); + return; + } + } else { + while (!handlers_.empty() && is_active_dispatcher(its_id)) { + std::shared_ptr its_handler = handlers_.front(); + handlers_.pop_front(); + its_lock.unlock(); + invoke_handler(its_handler); + its_lock.lock(); + + remove_elapsed_dispatchers(); + } + } + } + + std::lock_guard its_lock(dispatcher_mutex_); + elapsed_dispatchers_.insert(std::this_thread::get_id()); +} + +void application_impl::invoke_handler(std::shared_ptr &_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 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::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 its_lock(dispatcher_mutex_); + blocked_dispatchers_.erase(its_id); + } +} + +bool application_impl::is_active_dispatcher(std::thread::id &_id) { + std::lock_guard 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 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 availability_lock(availability_mutex_); + availability_.clear(); } - stopped_ = false; - for (auto &t : dispatchers_) { - if(t.joinable()) { - t.join(); + { + std::lock_guard its_lock(subscription_mutex_); + subscription_.clear(); + } + + { + std::lock_guard its_lock(subscription_error_mutex_); + eventgroup_error_handlers_.clear(); + } + + { + std::lock_guard its_lock(members_mutex_); + members_.clear(); + } +} + +void application_impl::wait_for_stop() { + + { + std::unique_lock 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 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 its_event = routing_->get_event(_service, + _instance, _event); + if (its_event && its_event->is_field() && its_event->is_set()) { + std::shared_ptr 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> 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 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 e921227fe..8bd1d3631 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 68f61544b..0259b2a7a 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::get() { return runtime_impl::get(); } diff --git a/implementation/runtime/src/runtime_impl.cpp b/implementation/runtime/src/runtime_impl.cpp index 2131da50f..4943b6dd5 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 runtime_impl::properties_; std::shared_ptr runtime_impl::the_runtime_ = std::make_shared(); +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_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 de8a97f31..d2351bc38 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 cc476a757..01c55cbe0 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 2d23c3cd5..52c7216bf 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 1625e80da..085bc7cd2 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 fde425ca7..25f08d273 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 @@ class entry_impl: public message_element_impl { void set_ttl(ttl_t _ttl); const std::vector & get_options(uint8_t _run) const; - void assign_option(const std::shared_ptr &_option, - uint8_t _run); + void assign_option(const std::shared_ptr &_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 016fdae59..6fb66f238 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 cde749757..0eb8893ba 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 @@ class eventgroupentry_impl: public entry_impl { 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 13b7158ad..ede92d399 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 @@ class fsm_base: public std::enable_shared_from_this { 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 1624b00df..75279e22f 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 #include +#include "../../routing/include/serviceinfo.hpp" namespace sc = boost::statechart; @@ -21,6 +22,9 @@ struct ev_none: sc::event { struct ev_timeout: sc::event { }; +struct ev_alt_timeout: sc::event { +}; + struct ev_status_change: sc::event { ev_status_change(bool _is_up) : is_up_(_is_up) { @@ -31,22 +35,25 @@ struct ev_status_change: sc::event { struct ev_find_service: sc::event { - 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 &_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 &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 { }; +struct ev_request_service: sc::event { +}; + } // 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 8fd426b76..e753b4e04 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 b8051cc25..c233f0f20 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 48938b032..c2b962f88 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 0308a06cf..75046572b 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 39ae3a1ce..c05b76e69 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 b0702df2a..a8573b8c1 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 90a6a4834..21e8b9cdb 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 fd12698c7..13f447856 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 565b22b70..e1f8d1e4a 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 9e62deb67..99fe507c1 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 @@ class request { 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 47255a265..656e2d5ef 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 cc0e14e83..111d56edc 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 894de0c09..ebc81fa75 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 #include +#include "../../routing/include/serviceinfo.hpp" +#include "../../endpoints/include/endpoint.hpp" namespace vsomeip { @@ -41,12 +43,28 @@ class service_discovery { 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 &_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& _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 &_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 f3fe7fdfb..915b3e31a 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 #include #include +#include "../../routing/include/serviceinfo.hpp" + #include "../include/fsm_base.hpp" #include "../include/fsm_events.hpp" @@ -40,7 +42,8 @@ struct fsm: sc::state_machine, public fsm_base { void set_fsm(std::shared_ptr _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 { sc::result react(const ev_find_service &_event); }; -struct announce: sc::state { +struct offer; +struct find; +struct main: sc::state> { + main(my_context _context); +}; + +struct offer: sc::state > { - announce(my_context _context); + offer(my_context _context); typedef mpl::list, sc::custom_reaction, @@ -106,9 +115,39 @@ struct announce: sc::state { 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, idle> { + + find(my_context _context); + + uint8_t run_; +}; + +struct idle: sc::state { + idle(my_context _context); + + typedef mpl::list >reactions; + + sc::result react(const ev_request_service &_event); }; -} // namespace _offer +struct send: sc::state { + send(my_context _context); + + typedef mpl::list< + sc::custom_reaction, + sc::custom_reaction + > reactions; + + sc::result react(const ev_alt_timeout &_event); + sc::result react(const ev_none &_event); +}; + +} // namespace _sd /////////////////////////////////////////////////////////////////////////////// // Interface @@ -121,13 +160,36 @@ class service_discovery_fsm: public std::enable_shared_from_this< 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 &_info, + service_t _service, instance_t _instance, + major_version_t _major, + minor_version_t _minor); + + void send_multicast_offer_service( + const std::shared_ptr &_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 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 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 27d800700..1795d89db 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 @@ class service_discovery_host { bool _flush) = 0; virtual bool send_to(const std::shared_ptr &_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 @@ class service_discovery_host { 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 _subscriber, - std::shared_ptr _target) = 0; + std::shared_ptr _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 @@ class service_discovery_host { 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 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 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 _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 7efb6eba7..4e6432815 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 #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 > > 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 { public: @@ -59,18 +71,36 @@ class service_discovery_impl: public service_discovery, 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 &_info, + service_t _service, instance_t _instance, + major_version_t _major, + minor_version_t _minor); + + void send_multicast_offer_service(const std::shared_ptr& _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 &_endpoint); + private: + + std::pair 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, @@ -78,24 +108,29 @@ class service_discovery_impl: public service_discovery, const boost::asio::ip::address &_address, uint16_t _port, bool _is_reliable); void insert_find_entries(std::shared_ptr &_message, - requests_t &_requests); + requests_t &_requests, uint32_t _start, uint32_t &_size, bool &_done); void insert_offer_entries(std::shared_ptr &_message, - services_t &_services); - void insert_offer_service(std::shared_ptr _message, + services_t &_services, uint32_t &_start, uint32_t _size, bool &_done); + bool insert_offer_service(std::shared_ptr _message, service_t _service, instance_t _instance, - const std::shared_ptr &_info); + const std::shared_ptr &_info, + uint32_t &_size); void insert_subscription(std::shared_ptr &_message, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + std::shared_ptr &_subscription, bool _insert_reliable, bool _insert_unreliable); + void insert_nack_subscription_on_resubscribe(std::shared_ptr &_message, service_t _service, instance_t _instance, eventgroup_t _eventgroup, std::shared_ptr &_subscription); void insert_subscription_ack(std::shared_ptr &_message, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - std::shared_ptr &_info, ttl_t _ttl); + std::shared_ptr &_info, ttl_t _ttl, uint8_t _counter, major_version_t _major, uint16_t _reserved); void insert_subscription_nack(std::shared_ptr &_message, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - std::shared_ptr &_info); + uint8_t _counter, major_version_t _major, uint16_t _reserved); void process_serviceentry(std::shared_ptr &_entry, - const std::vector > &_options); + const std::vector > &_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 @@ class service_discovery_impl: public service_discovery, uint16_t _reliable_port, const boost::asio::ip::address &_unreliable_address, uint16_t _unreliable_port); - void send_unicast_offer_service(const std::shared_ptr& _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 &_entry, - const std::vector > &_options); + void send_offer_service( + const std::shared_ptr &_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 &_entry, + const std::vector > &_options, + std::shared_ptr < message_impl > &its_message_response, + std::vector &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_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, const boost::asio::ip::address &_address); + bool is_tcp_connected(service_t _service, + instance_t _instance, + std::shared_ptr 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 &_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 _ip_option) const; void get_subscription_endpoints(subscription_type_e _subscription_type, @@ -146,6 +205,28 @@ class service_discovery_impl: public service_discovery, 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 + std::shared_ptr find_existing_option( + std::shared_ptr &_message, + AddressType _address, uint16_t _port, + layer_four_protocol_e _protocol, + option_type_e _option_type); + template + bool check_message_for_ip_option_and_assign_existing( + std::shared_ptr &_message, + std::shared_ptr _entry, AddressType _address, + uint16_t _port, layer_four_protocol_e _protocol, + option_type_e _option_type); + template + void assign_ip_option_to_entry(std::shared_ptr