From ca8af4e6da0eb1f5c268ace102c0ac6aa5545b5c Mon Sep 17 00:00:00 2001 From: Juergen Gehring Date: Thu, 25 Jan 2018 00:40:06 -0800 Subject: [PATCH] vsomeip 2.10.4 --- CHANGES | 9 + CMakeLists.txt | 2 +- documentation/vsomeipUserGuide | 41 +++- .../configuration/src/configuration_impl.cpp | 4 - .../include/tcp_client_endpoint_impl.hpp | 10 +- .../include/tcp_server_endpoint_impl.hpp | 19 +- .../src/tcp_client_endpoint_impl.cpp | 98 +++++++- .../src/tcp_server_endpoint_impl.cpp | 104 ++++++++- .../routing/include/routing_manager_proxy.hpp | 7 +- .../routing/include/routing_manager_stub.hpp | 1 + .../routing/src/routing_manager_base.cpp | 6 +- .../routing/src/routing_manager_impl.cpp | 6 +- .../routing/src/routing_manager_proxy.cpp | 70 +++--- .../routing/src/routing_manager_stub.cpp | 12 +- .../runtime/include/application_impl.hpp | 5 +- .../runtime/src/application_impl.cpp | 209 +++++++++++------- .../src/service_discovery_impl.cpp | 1 - test/application_tests/application_test.cpp | 124 +++++++++++ 18 files changed, 582 insertions(+), 146 deletions(-) diff --git a/CHANGES b/CHANGES index 385bac1b2..1fa9a5fff 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,15 @@ Changes ======= +v2.10.4 +- Extended diagnosis plugin to handle requests for + "disableRxAndEnableTx" and "disableRxAndTx". +- Catch unhandled user code exceptions thrown from called handlers. +- Don't send SubscribeEventGroupNACK for pending subscriptions on next + offer to reduce the amount of StopSubscribe/Subscribe messages. +- Added possibility to apply filter for client side logging + using VSOMEIP_CLIENTSIDELOGGING environment variable. + v2.10.3 - Interpret all incoming TTLs five times longer in service discovery to prevent inadvertent expiration of remote offers during high load diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d958b4ae..d1df17848 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project (vsomeip) set (VSOMEIP_MAJOR_VERSION 2) set (VSOMEIP_MINOR_VERSION 10) -set (VSOMEIP_PATCH_VERSION 3) +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) diff --git a/documentation/vsomeipUserGuide b/documentation/vsomeipUserGuide index 882890d35..0c222b991 100644 --- a/documentation/vsomeipUserGuide +++ b/documentation/vsomeipUserGuide @@ -231,11 +231,14 @@ On startup the following environment variables are read out: applications, all other configuration files are only read by the application that is responsible for connections to external devices. If this configuration variable is not set, the default mandatory files vsomeip_std.json, vsomeip_app.json and vsomeip_plc.json are used. -* `VSOMEIP_CLIENTSIDELOGGING`: Set this variable to an empty string or an arbitrary - value to enable logging of received messages to DLT in all applications - acting as routing manager proxies. For example add the following line to the - application's systemd service file: +* `VSOMEIP_CLIENTSIDELOGGING`: Set this variable to an empty string to enable logging of + any received messages to DLT in all applications acting as routing manager proxies. For + example add the following line to the application's systemd service file: `Environment=VSOMEIP_CLIENTSIDELOGGING=""` + To enable service-specific logs, provide a space- or colon-separated list of ServiceIDs (using + 4-digit hexadecimal notation, optionally followed by dot-separted InstanceID). For example: + `Environment=VSOMEIP_CLIENTSIDELOGGING="b003.0001 f013.000a 1001 1002"` + `Environment=VSOMEIP_CLIENTSIDELOGGING="b003.0001:f013.000a:1001:1002"` NOTE: If the file/folder that is configured by `VSOMEIP_CONFIGURATION` does _not_ exist, the default configuration locations will be used. @@ -907,9 +910,37 @@ Specifies a service for the _offers_. + Specifies a instance for the _offers_ -In the config/ folder are some vSomeIP configuration files to run the vSomeIP examples with activated security checks. +In the `config/` folder are some vSomeIP configuration files to run the vSomeIP +examples with activated security checks. +Additionally there's a security test in the `test/` subfolder which can be used +for further reference. + They give a basic overview how to use the security related configuration tags described in this chapter to run a simple request/response or subscribe/notify example locally or over remote. +Audit Mode +~~~~~~~~~~ +vSomeIP's security implementation can be put in a so called 'Audit Mode' where +all security violations will be logged but allowed. This mode can be used to +build a security configuration. + +To activate the 'Audit Mode' the 'security' object has to be included in the +json file but the 'check_credentials' switch has to be set to false. For +example: + +[source, json] +---- + [...] + "services" : + [ + [...] + ], + "security" : + { + "check_credentials" : "false" + }, + "routing" : "service-sample", + [...] +---- + Autoconfiguration ----------------- vsomeip supports the automatic configuration of client identifiers and the routing. diff --git a/implementation/configuration/src/configuration_impl.cpp b/implementation/configuration/src/configuration_impl.cpp index 243f93ef1..43e3c675e 100644 --- a/implementation/configuration/src/configuration_impl.cpp +++ b/implementation/configuration/src/configuration_impl.cpp @@ -351,10 +351,6 @@ bool configuration_impl::load_data(const std::vector &_elements, } } - for (auto its_service : services_) { - VSOMEIP_INFO << "service: " << its_service.first; - } - return is_logging_loaded_ && has_routing && has_applications; } diff --git a/implementation/endpoints/include/tcp_client_endpoint_impl.hpp b/implementation/endpoints/include/tcp_client_endpoint_impl.hpp index 7ba35aae2..801c98c0a 100644 --- a/implementation/endpoints/include/tcp_client_endpoint_impl.hpp +++ b/implementation/endpoints/include/tcp_client_endpoint_impl.hpp @@ -25,7 +25,8 @@ class tcp_client_endpoint_impl: public tcp_client_endpoint_base_impl { endpoint_type _remote, boost::asio::io_service &_io, std::uint32_t _max_message_size, - std::uint32_t buffer_shrink_threshold); + std::uint32_t buffer_shrink_threshold, + std::chrono::milliseconds _send_timeout); virtual ~tcp_client_endpoint_impl(); void start(); @@ -52,6 +53,11 @@ class tcp_client_endpoint_impl: public tcp_client_endpoint_base_impl { const std::string get_address_port_local() const; void handle_recv_buffer_exception(const std::exception &_e); void set_local_port(); + std::size_t write_completion_condition( + const boost::system::error_code& _error, + std::size_t _bytes_transferred, std::size_t _bytes_to_send, + service_t _service, method_t _method, client_t _client, session_t _session, + std::chrono::steady_clock::time_point _start); const std::uint32_t recv_buffer_size_initial_; @@ -64,6 +70,8 @@ class tcp_client_endpoint_impl: public tcp_client_endpoint_base_impl { const boost::asio::ip::address remote_address_; const std::uint16_t remote_port_; std::chrono::steady_clock::time_point last_cookie_sent_; + const std::chrono::milliseconds send_timeout_; + const std::chrono::milliseconds send_timeout_warning_; }; } // namespace vsomeip diff --git a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp index 3d639d993..ab6fdb992 100644 --- a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp @@ -30,7 +30,8 @@ class tcp_server_endpoint_impl: public tcp_server_endpoint_base_impl { endpoint_type _local, boost::asio::io_service &_io, std::uint32_t _max_message_size, - std::uint32_t _buffer_shrink_threshold); + std::uint32_t _buffer_shrink_threshold, + std::chrono::milliseconds _send_timeout); virtual ~tcp_server_endpoint_impl(); void start(); @@ -64,7 +65,8 @@ class tcp_server_endpoint_impl: public tcp_server_endpoint_base_impl { std::uint32_t _max_message_size, std::uint32_t _buffer_shrink_threshold, bool _magic_cookies_enabled, - boost::asio::io_service & _io_service); + boost::asio::io_service & _io_service, + std::chrono::milliseconds _send_timeout); socket_type & get_socket(); std::unique_lock get_socket_lock(); @@ -84,7 +86,8 @@ class tcp_server_endpoint_impl: public tcp_server_endpoint_base_impl { std::uint32_t _recv_buffer_size_initial, std::uint32_t _buffer_shrink_threshold, bool _magic_cookies_enabled, - boost::asio::io_service & _io_service); + boost::asio::io_service & _io_service, + std::chrono::milliseconds _send_timeout); void send_magic_cookie(message_buffer_ptr_t &_buffer); bool is_magic_cookie(size_t _offset) const; void receive_cbk(boost::system::error_code const &_error, @@ -92,7 +95,12 @@ class tcp_server_endpoint_impl: public tcp_server_endpoint_base_impl { void calculate_shrink_count(); const std::string get_address_port_local() const; void handle_recv_buffer_exception(const std::exception &_e); - + std::size_t write_completion_condition( + const boost::system::error_code& _error, + std::size_t _bytes_transferred, std::size_t _bytes_to_send, + service_t _service, method_t _method, client_t _client, session_t _session, + std::chrono::steady_clock::time_point _start); + void stop_and_remove_connection(); std::mutex socket_mutex_; tcp_server_endpoint_impl::socket_type socket_; @@ -112,6 +120,8 @@ class tcp_server_endpoint_impl: public tcp_server_endpoint_base_impl { std::uint16_t remote_port_; std::atomic magic_cookies_enabled_; std::chrono::steady_clock::time_point last_cookie_sent_; + const std::chrono::milliseconds send_timeout_; + const std::chrono::milliseconds send_timeout_warning_; }; std::mutex acceptor_mutex_; @@ -121,6 +131,7 @@ class tcp_server_endpoint_impl: public tcp_server_endpoint_base_impl { connections_t connections_; const std::uint32_t buffer_shrink_threshold_; const std::uint16_t local_port_; + const std::chrono::milliseconds send_timeout_; private: void remove_connection(connection *_connection); diff --git a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp index 6a5df8853..2646f0191 100644 --- a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp @@ -14,8 +14,10 @@ #include "../include/tcp_client_endpoint_impl.hpp" #include "../../logging/include/logger.hpp" #include "../../utility/include/utility.hpp" +#include "../../utility/include/byteorder.hpp" #include "../../configuration/include/internal.hpp" + namespace ip = boost::asio::ip; namespace vsomeip { @@ -26,7 +28,8 @@ tcp_client_endpoint_impl::tcp_client_endpoint_impl( endpoint_type _remote, boost::asio::io_service &_io, std::uint32_t _max_message_size, - std::uint32_t _buffer_shrink_threshold) + std::uint32_t _buffer_shrink_threshold, + std::chrono::milliseconds _send_timeout) : tcp_client_endpoint_base_impl(_host, _local, _remote, _io, _max_message_size), recv_buffer_size_initial_(VSOMEIP_SOMEIP_HEADER_SIZE), recv_buffer_(recv_buffer_size_initial_, 0), @@ -36,7 +39,9 @@ tcp_client_endpoint_impl::tcp_client_endpoint_impl( buffer_shrink_threshold_(_buffer_shrink_threshold), remote_address_(_remote.address()), remote_port_(_remote.port()), - last_cookie_sent_(std::chrono::steady_clock::now() - std::chrono::seconds(11)) { + last_cookie_sent_(std::chrono::steady_clock::now() - std::chrono::seconds(11)), + send_timeout_(_send_timeout), + send_timeout_warning_(_send_timeout / 2) { is_supporting_magic_cookies_ = true; } @@ -67,6 +72,27 @@ void tcp_client_endpoint_impl::restart() { } { std::lock_guard its_lock(mutex_); + for (const auto&m : queue_) { + const service_t its_service = VSOMEIP_BYTES_TO_WORD( + (*m)[VSOMEIP_SERVICE_POS_MIN], + (*m)[VSOMEIP_SERVICE_POS_MAX]); + const method_t its_method = VSOMEIP_BYTES_TO_WORD( + (*m)[VSOMEIP_METHOD_POS_MIN], + (*m)[VSOMEIP_METHOD_POS_MAX]); + const client_t its_client = VSOMEIP_BYTES_TO_WORD( + (*m)[VSOMEIP_CLIENT_POS_MIN], + (*m)[VSOMEIP_CLIENT_POS_MAX]); + const session_t its_session = VSOMEIP_BYTES_TO_WORD( + (*m)[VSOMEIP_SESSION_POS_MIN], + (*m)[VSOMEIP_SESSION_POS_MAX]); + VSOMEIP_WARNING << "tce::restart: dropping message: " + << "remote:" << get_address_port_remote() << " (" + << 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_method << "." + << std::hex << std::setw(4) << std::setfill('0') << its_session << "]" + << " size: " << std::dec << m->size(); + } queue_.clear(); } start_connect_timer(); @@ -174,6 +200,18 @@ void tcp_client_endpoint_impl::send_queued() { } else { return; } + const service_t its_service = VSOMEIP_BYTES_TO_WORD( + (*its_buffer)[VSOMEIP_SERVICE_POS_MIN], + (*its_buffer)[VSOMEIP_SERVICE_POS_MAX]); + const method_t its_method = VSOMEIP_BYTES_TO_WORD( + (*its_buffer)[VSOMEIP_METHOD_POS_MIN], + (*its_buffer)[VSOMEIP_METHOD_POS_MAX]); + const client_t its_client = VSOMEIP_BYTES_TO_WORD( + (*its_buffer)[VSOMEIP_CLIENT_POS_MIN], + (*its_buffer)[VSOMEIP_CLIENT_POS_MAX]); + const session_t its_session = VSOMEIP_BYTES_TO_WORD( + (*its_buffer)[VSOMEIP_SESSION_POS_MIN], + (*its_buffer)[VSOMEIP_SESSION_POS_MAX]); if (has_enabled_magic_cookies_) { const std::chrono::steady_clock::time_point now = @@ -200,6 +238,13 @@ void tcp_client_endpoint_impl::send_queued() { boost::asio::async_write( *socket_, boost::asio::buffer(*its_buffer), + std::bind(&tcp_client_endpoint_impl::write_completion_condition, + std::static_pointer_cast(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2, + its_buffer->size(), + its_service, its_method, its_client, its_session, + std::chrono::steady_clock::now()), std::bind( &tcp_client_endpoint_base_impl::send_cbk, shared_from_this(), @@ -233,6 +278,55 @@ void tcp_client_endpoint_impl::set_local_port() { } } +std::size_t tcp_client_endpoint_impl::write_completion_condition( + const boost::system::error_code& _error, std::size_t _bytes_transferred, + std::size_t _bytes_to_send, service_t _service, method_t _method, + client_t _client, session_t _session, + std::chrono::steady_clock::time_point _start) { + + if (_error) { + VSOMEIP_ERROR << "tce::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send << " " + << "remote:" << get_address_port_remote() << " (" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _method << "." + << std::hex << std::setw(4) << std::setfill('0') << _session << "]"; + return 0; + } + + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + std::chrono::milliseconds passed = std::chrono::duration_cast(now - _start); + if (passed > send_timeout_warning_) { + if (passed > send_timeout_) { + VSOMEIP_ERROR << "tce::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") took longer than " << std::dec << send_timeout_.count() + << "ms bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send << " " + << "remote:" << get_address_port_remote() << " (" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _method << "." + << std::hex << std::setw(4) << std::setfill('0') << _session << "]"; + } else { + VSOMEIP_WARNING << "tce::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") took longer than " << std::dec << send_timeout_warning_.count() + << "ms bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send << " " + << "remote:" << get_address_port_remote() << " (" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _method << "." + << std::hex << std::setw(4) << std::setfill('0') << _session << "]"; + } + } + return _bytes_to_send - _bytes_transferred; +} + std::uint16_t tcp_client_endpoint_impl::get_remote_port() const { return remote_port_; } diff --git a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp index 2392f58d1..37e35541b 100644 --- a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp @@ -14,6 +14,7 @@ #include "../include/tcp_server_endpoint_impl.hpp" #include "../../logging/include/logger.hpp" #include "../../utility/include/utility.hpp" +#include "../../utility/include/byteorder.hpp" #include "../../configuration/include/internal.hpp" namespace ip = boost::asio::ip; @@ -23,11 +24,13 @@ namespace vsomeip { tcp_server_endpoint_impl::tcp_server_endpoint_impl( std::shared_ptr _host, endpoint_type _local, boost::asio::io_service &_io, std::uint32_t _max_message_size, - std::uint32_t _buffer_shrink_threshold) + std::uint32_t _buffer_shrink_threshold, + std::chrono::milliseconds _send_timeout) : tcp_server_endpoint_base_impl(_host, _local, _io, _max_message_size), acceptor_(_io), buffer_shrink_threshold_(_buffer_shrink_threshold), - local_port_(_local.port()) { + local_port_(_local.port()), + send_timeout_(_send_timeout) { is_supporting_magic_cookies_ = true; boost::system::error_code ec; @@ -55,7 +58,7 @@ void tcp_server_endpoint_impl::start() { std::dynamic_pointer_cast( shared_from_this()), max_message_size_, buffer_shrink_threshold_, has_enabled_magic_cookies_, - service_); + service_, send_timeout_); { std::unique_lock its_socket_lock(new_connection->get_socket_lock()); @@ -203,7 +206,8 @@ tcp_server_endpoint_impl::connection::connection( std::uint32_t _initial_recv_buffer_size, std::uint32_t _buffer_shrink_threshold, bool _magic_cookies_enabled, - boost::asio::io_service &_io_service) : + boost::asio::io_service &_io_service, + std::chrono::milliseconds _send_timeout) : socket_(_io_service), server_(_server), max_message_size_(_max_message_size), @@ -215,7 +219,9 @@ tcp_server_endpoint_impl::connection::connection( buffer_shrink_threshold_(_buffer_shrink_threshold), remote_port_(0), magic_cookies_enabled_(_magic_cookies_enabled), - last_cookie_sent_(std::chrono::steady_clock::now() - std::chrono::seconds(11)) { + last_cookie_sent_(std::chrono::steady_clock::now() - std::chrono::seconds(11)), + send_timeout_(_send_timeout), + send_timeout_warning_(_send_timeout / 2) { } tcp_server_endpoint_impl::connection::ptr @@ -224,14 +230,15 @@ tcp_server_endpoint_impl::connection::create( std::uint32_t _max_message_size, std::uint32_t _buffer_shrink_threshold, bool _magic_cookies_enabled, - boost::asio::io_service & _io_service) { + boost::asio::io_service & _io_service, + std::chrono::milliseconds _send_timeout) { const std::uint32_t its_initial_receveive_buffer_size = VSOMEIP_SOMEIP_HEADER_SIZE + 8 + MAGIC_COOKIE_SIZE + 8 + VSOMEIP_MAX_TCP_MESSAGE_SIZE; return ptr(new connection(_server, _max_message_size, its_initial_receveive_buffer_size, _buffer_shrink_threshold, _magic_cookies_enabled, - _io_service)); + _io_service, _send_timeout)); } tcp_server_endpoint_impl::socket_type & @@ -304,6 +311,18 @@ void tcp_server_endpoint_impl::connection::send_queued( return; } message_buffer_ptr_t its_buffer = _queue_iterator->second.front(); + const service_t its_service = VSOMEIP_BYTES_TO_WORD( + (*its_buffer)[VSOMEIP_SERVICE_POS_MIN], + (*its_buffer)[VSOMEIP_SERVICE_POS_MAX]); + const method_t its_method = VSOMEIP_BYTES_TO_WORD( + (*its_buffer)[VSOMEIP_METHOD_POS_MIN], + (*its_buffer)[VSOMEIP_METHOD_POS_MAX]); + const client_t its_client = VSOMEIP_BYTES_TO_WORD( + (*its_buffer)[VSOMEIP_CLIENT_POS_MIN], + (*its_buffer)[VSOMEIP_CLIENT_POS_MAX]); + const session_t its_session = VSOMEIP_BYTES_TO_WORD( + (*its_buffer)[VSOMEIP_SESSION_POS_MIN], + (*its_buffer)[VSOMEIP_SESSION_POS_MAX]); if (magic_cookies_enabled_) { const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); @@ -317,6 +336,13 @@ void tcp_server_endpoint_impl::connection::send_queued( { std::lock_guard its_lock(socket_mutex_); boost::asio::async_write(socket_, boost::asio::buffer(*its_buffer), + std::bind(&tcp_server_endpoint_impl::connection::write_completion_condition, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2, + its_buffer->size(), + its_service, its_method, its_client, its_session, + std::chrono::steady_clock::now()), std::bind(&tcp_server_endpoint_base_impl::send_cbk, its_server, _queue_iterator, @@ -630,6 +656,70 @@ tcp_server_endpoint_impl::connection::get_recv_buffer_capacity() const { return recv_buffer_.capacity(); } +std::size_t +tcp_server_endpoint_impl::connection::write_completion_condition( + const boost::system::error_code& _error, + std::size_t _bytes_transferred, std::size_t _bytes_to_send, + service_t _service, method_t _method, client_t _client, session_t _session, + std::chrono::steady_clock::time_point _start) { + if (_error) { + VSOMEIP_ERROR << "tse::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send << " " + << "remote:" << get_address_port_remote() << " (" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _method << "." + << std::hex << std::setw(4) << std::setfill('0') << _session << "]"; + stop_and_remove_connection(); + return 0; + } + + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + std::chrono::milliseconds passed = std::chrono::duration_cast(now - _start); + if (passed > send_timeout_warning_) { + if (passed > send_timeout_) { + VSOMEIP_ERROR << "tse::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") took longer than " << std::dec << send_timeout_.count() + << "ms bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send + << " remote:" << get_address_port_remote() << " (" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _method << "." + << std::hex << std::setw(4) << std::setfill('0') << _session << "]"; + } else { + VSOMEIP_WARNING << "tse::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") took longer than " << std::dec << send_timeout_warning_.count() + << "ms bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send + << " remote:" << get_address_port_remote() << " (" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _method << "." + << std::hex << std::setw(4) << std::setfill('0') << _session << "]"; + } + } + return _bytes_to_send - _bytes_transferred; +} + +void tcp_server_endpoint_impl::connection::stop_and_remove_connection() { + std::shared_ptr its_server(server_.lock()); + if (!its_server) { + VSOMEIP_ERROR << "tse::connection::stop_and_remove_connection " + " couldn't lock server_"; + return; + } + { + std::lock_guard its_lock(its_server->connections_mutex_); + stop(); + } + its_server->remove_connection(this); +} + // Dummies void tcp_server_endpoint_impl::receive() { // intentionally left empty diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_proxy.hpp index dcf6152ef..806024bb8 100644 --- a/implementation/routing/include/routing_manager_proxy.hpp +++ b/implementation/routing/include/routing_manager_proxy.hpp @@ -29,7 +29,8 @@ class logger; class routing_manager_proxy: public routing_manager_base { public: - routing_manager_proxy(routing_manager_host *_host, bool _client_side_logging); + routing_manager_proxy(routing_manager_host *_host, bool _client_side_logging, + const std::set > & _client_side_logging_filter); virtual ~routing_manager_proxy(); void init(); @@ -217,13 +218,14 @@ class routing_manager_proxy: public routing_manager_base { std::set pending_event_registrations_; std::map> pending_incoming_subscripitons_; - std::mutex incoming_subscripitons_mutex_; + std::mutex incoming_subscriptions_mutex_; std::mutex state_mutex_; std::condition_variable state_condition_; std::map > > remote_subscriber_count_; + std::mutex remote_subscriber_count_mutex_; mutable std::mutex sender_mutex_; @@ -236,6 +238,7 @@ class routing_manager_proxy: public routing_manager_base { bool request_debounce_timer_running_; const bool client_side_logging_; + const std::set > client_side_logging_filter_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_stub.hpp b/implementation/routing/include/routing_manager_stub.hpp index ec5dd4e15..f825b0b17 100644 --- a/implementation/routing/include/routing_manager_stub.hpp +++ b/implementation/routing/include/routing_manager_stub.hpp @@ -154,6 +154,7 @@ class routing_manager_stub: public endpoint_host, std::string local_receiver_path_; std::shared_ptr endpoint_; std::shared_ptr local_receiver_; + std::mutex local_receiver_mutex_; std::map> > > > routing_info_; diff --git a/implementation/routing/src/routing_manager_base.cpp b/implementation/routing/src/routing_manager_base.cpp index 9036e5a7c..1d0c795c5 100644 --- a/implementation/routing/src/routing_manager_base.cpp +++ b/implementation/routing/src/routing_manager_base.cpp @@ -1001,10 +1001,8 @@ std::shared_ptr routing_manager_base::get_deserializer() { } void routing_manager_base::put_deserializer(std::shared_ptr _deserializer) { - { - std::lock_guard its_lock(deserializer_mutex_); - deserializers_.push(_deserializer); - } + std::lock_guard its_lock(deserializer_mutex_); + deserializers_.push(_deserializer); deserializer_condition_.notify_one(); } diff --git a/implementation/routing/src/routing_manager_impl.cpp b/implementation/routing/src/routing_manager_impl.cpp index 34398ade4..88aaca3ce 100644 --- a/implementation/routing/src/routing_manager_impl.cpp +++ b/implementation/routing/src/routing_manager_impl.cpp @@ -1726,7 +1726,8 @@ std::shared_ptr routing_manager_impl::create_client_endpoint( io_, configuration_->get_max_message_size_reliable( _address.to_string(), _remote_port), - configuration_->get_buffer_shrink_threshold()); + configuration_->get_buffer_shrink_threshold(), + std::chrono::milliseconds(configuration_->get_sd_ttl() * 666)); if (configuration_->has_enabled_magic_cookies(_address.to_string(), _remote_port)) { @@ -1763,7 +1764,8 @@ std::shared_ptr routing_manager_impl::create_server_endpoint( boost::asio::ip::tcp::endpoint(its_unicast, _port), io_, configuration_->get_max_message_size_reliable( its_unicast.to_string(), _port), - configuration_->get_buffer_shrink_threshold()); + configuration_->get_buffer_shrink_threshold(), + std::chrono::milliseconds(configuration_->get_sd_ttl() * 666)); if (configuration_->has_enabled_magic_cookies( its_unicast.to_string(), _port) || configuration_->has_enabled_magic_cookies( diff --git a/implementation/routing/src/routing_manager_proxy.cpp b/implementation/routing/src/routing_manager_proxy.cpp index 4224b574e..a62ee9666 100644 --- a/implementation/routing/src/routing_manager_proxy.cpp +++ b/implementation/routing/src/routing_manager_proxy.cpp @@ -36,7 +36,8 @@ namespace vsomeip { routing_manager_proxy::routing_manager_proxy(routing_manager_host *_host, - bool _client_side_logging) : + bool _client_side_logging, + const std::set > & _client_side_logging_filter) : routing_manager_base(_host), is_connected_(false), is_started_(false), @@ -47,7 +48,8 @@ routing_manager_proxy::routing_manager_proxy(routing_manager_host *_host, logger_(logger::get()), request_debounce_timer_ (io_), request_debounce_timer_running_(false), - client_side_logging_(_client_side_logging) + client_side_logging_(_client_side_logging), + client_side_logging_filter_(_client_side_logging_filter) { } @@ -625,24 +627,28 @@ bool routing_manager_proxy::send(client_t _client, const byte_t *_data, service_t its_service = VSOMEIP_BYTES_TO_WORD( _data[VSOMEIP_SERVICE_POS_MIN], _data[VSOMEIP_SERVICE_POS_MAX]); - method_t its_method = VSOMEIP_BYTES_TO_WORD( - _data[VSOMEIP_METHOD_POS_MIN], - _data[VSOMEIP_METHOD_POS_MAX]); - session_t its_session = VSOMEIP_BYTES_TO_WORD( - _data[VSOMEIP_SESSION_POS_MIN], - _data[VSOMEIP_SESSION_POS_MAX]); - client_t its_client = VSOMEIP_BYTES_TO_WORD( - _data[VSOMEIP_CLIENT_POS_MIN], - _data[VSOMEIP_CLIENT_POS_MAX]); - VSOMEIP_INFO << "routing_manager_proxy::send: (" - << std::hex << std::setw(4) << std::setfill('0') << client_ <<"): [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << _instance << "." - << std::hex << std::setw(4) << std::setfill('0') << its_method << ":" - << std::hex << std::setw(4) << std::setfill('0') << its_session << ":" - << std::hex << std::setw(4) << std::setfill('0') << its_client << "] " - << "type=" << std::hex << static_cast(_data[VSOMEIP_MESSAGE_TYPE_POS]) - << " thread=" << std::hex << std::this_thread::get_id(); + if (client_side_logging_filter_.empty() + || (1 == client_side_logging_filter_.count(std::make_tuple(its_service, ANY_INSTANCE))) + || (1 == client_side_logging_filter_.count(std::make_tuple(its_service, _instance)))) { + method_t its_method = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_METHOD_POS_MIN], + _data[VSOMEIP_METHOD_POS_MAX]); + session_t its_session = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_SESSION_POS_MIN], + _data[VSOMEIP_SESSION_POS_MAX]); + client_t its_client = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_CLIENT_POS_MIN], + _data[VSOMEIP_CLIENT_POS_MAX]); + VSOMEIP_INFO << "routing_manager_proxy::send: (" + << std::hex << std::setw(4) << std::setfill('0') << client_ <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_method << ":" + << std::hex << std::setw(4) << std::setfill('0') << its_session << ":" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "] " + << "type=" << std::hex << static_cast(_data[VSOMEIP_MESSAGE_TYPE_POS]) + << " thread=" << std::hex << std::this_thread::get_id(); + } } else { VSOMEIP_ERROR << "routing_manager_proxy::send: (" << std::hex << std::setw(4) << std::setfill('0') << client_ @@ -924,7 +930,10 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, } } #ifdef USE_DLT - if (client_side_logging_) { + if (client_side_logging_ + && (client_side_logging_filter_.empty() + || (1 == client_side_logging_filter_.count(std::make_tuple(its_message->get_service(), ANY_INSTANCE))) + || (1 == client_side_logging_filter_.count(std::make_tuple(its_message->get_service(), its_message->get_instance()))))) { tc::trace_header its_header; if (its_header.prepare(nullptr, false, its_instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, @@ -974,7 +983,7 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, std::memcpy(&its_subscription_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 10], sizeof(its_subscription_id)); { - std::unique_lock its_lock(incoming_subscripitons_mutex_); + std::unique_lock its_lock(incoming_subscriptions_mutex_); if (its_subscription_id != DEFAULT_SUBSCRIPTION) { its_lock.unlock(); // Remote subscriber: Notify routing manager initially + count subscribes @@ -1216,10 +1225,9 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, send_registered_ack(); send_pending_commands(); state_ = inner_state_type_e::ST_REGISTERED; + // Notify stop() call about clean deregistration + state_condition_.notify_one(); } - - // Notify stop() call about clean deregistration - state_condition_.notify_one(); } } else if (routing_info_entry == routing_info_entry_e::RIE_DEL_CLIENT) { { @@ -1236,10 +1244,9 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, { std::lock_guard its_lock(state_mutex_); state_ = inner_state_type_e::ST_DEREGISTERED; + // Notify stop() call about clean deregistration + state_condition_.notify_one(); } - - // Notify stop() call about clean deregistration - state_condition_.notify_one(); } else if (its_client != VSOMEIP_ROUTING_CLIENT) { remove_local(its_client); } @@ -1327,7 +1334,7 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, major_version_t major_; event_t event_; }; - std::lock_guard its_lock(incoming_subscripitons_mutex_); + std::lock_guard its_lock(incoming_subscriptions_mutex_); std::forward_list subscription_actions; if (pending_incoming_subscripitons_.size()) { { @@ -1429,10 +1436,10 @@ void routing_manager_proxy::reconnect(const std::unordered_set &_clien { std::lock_guard its_lock(state_mutex_); state_ = inner_state_type_e::ST_DEREGISTERED; + // Notify stop() call about clean deregistration + state_condition_.notify_one(); } - // Notify stop() call about clean deregistration - state_condition_.notify_one(); // Remove all local connections/endpoints for (const auto its_client : _clients) { @@ -1830,6 +1837,7 @@ void routing_manager_proxy::notify_remote_initially(service_t _service, instance uint32_t routing_manager_proxy::get_remote_subscriber_count(service_t _service, instance_t _instance, eventgroup_t _eventgroup, bool _increment) { + std::lock_guard its_lock(remote_subscriber_count_mutex_); uint32_t count (0); bool found(false); auto found_service = remote_subscriber_count_.find(_service); diff --git a/implementation/routing/src/routing_manager_stub.cpp b/implementation/routing/src/routing_manager_stub.cpp index 08a91c791..504458ea2 100644 --- a/implementation/routing/src/routing_manager_stub.cpp +++ b/implementation/routing/src/routing_manager_stub.cpp @@ -1287,6 +1287,8 @@ void routing_manager_stub::send_subscribe_ack(client_t _client, service_t _servi sizeof(_client)); std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_event, sizeof(_event)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 10], + &DEFAULT_SUBSCRIPTION, sizeof(DEFAULT_SUBSCRIPTION)); its_endpoint->send(&its_command[0], sizeof(its_command), true); } @@ -1317,6 +1319,8 @@ void routing_manager_stub::send_subscribe_nack(client_t _client, service_t _serv sizeof(_client)); std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_event, sizeof(_event)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 10], + &DEFAULT_SUBSCRIPTION, sizeof(DEFAULT_SUBSCRIPTION)); its_endpoint->send(&its_command[0], sizeof(its_command), true); } @@ -1420,6 +1424,8 @@ void routing_manager_stub::check_watchdog() { } void routing_manager_stub::create_local_receiver() { + std::lock_guard its_lock(local_receiver_mutex_); + if (local_receiver_) { return; } @@ -1791,9 +1797,9 @@ void routing_manager_stub::on_client_id_timer_expired(boost::system::error_code } } for (auto client : erroneous_clients) { - VSOMEIP_WARNING << "Expected client 0x" << std::hex - << client << " hasn't reconnected to the routing manager. " - << "Release identifier as client went offline while no" + VSOMEIP_WARNING << "Releasing client identifier " + << std::hex << std::setw(4) << std::setfill('0') << client << ". " + << "Its corresponding application went offline while no " << "routing manager was running."; host_->handle_client_error(client); } diff --git a/implementation/runtime/include/application_impl.hpp b/implementation/runtime/include/application_impl.hpp index 28ce86b5f..2d6cd8221 100644 --- a/implementation/runtime/include/application_impl.hpp +++ b/implementation/runtime/include/application_impl.hpp @@ -368,8 +368,8 @@ class application_impl: public application, std::map> dispatchers_; // Dispatcher threads that elapsed and can be removed std::set elapsed_dispatchers_; - // Dispatcher threads that blocked - std::set blocked_dispatchers_; + // Dispatcher threads that are running + std::set running_dispatchers_; // Mutex to protect access to dispatchers_ & elapsed_dispatchers_ std::mutex dispatcher_mutex_; // Condition to wakeup the dispatcher thread @@ -418,6 +418,7 @@ class application_impl: public application, std::chrono::seconds watchdog_interval_; bool client_side_logging_; + std::set > client_side_logging_filter_; }; } // namespace vsomeip diff --git a/implementation/runtime/src/application_impl.cpp b/implementation/runtime/src/application_impl.cpp index a282399ed..1d49df16a 100644 --- a/implementation/runtime/src/application_impl.cpp +++ b/implementation/runtime/src/application_impl.cpp @@ -108,6 +108,48 @@ bool application_impl::init() { client_side_logging_ = true; VSOMEIP_INFO << "Client side logging for application: " << name_ << " is enabled"; + + if ('\0' != *client_side_logging) { + std::stringstream its_converter(client_side_logging); + if ('"' == its_converter.peek()) { + its_converter.get(); // skip quote + } + uint16_t val(0xffffu); + bool stop_parsing(false); + do { + const uint16_t prev_val(val); + its_converter >> std::hex >> std::setw(4) >> val; + if (its_converter.good()) { + const std::stringstream::int_type c = its_converter.eof()?'\0':its_converter.get(); + switch (c) { + case '"': + case '.': + case ':': + case ' ': + case '\0': { + if ('.' != c) { + if (0xffffu == prev_val) { + VSOMEIP_INFO << "+filter " + << std::hex << std::setw(4) << std::setfill('0') << val; + client_side_logging_filter_.insert(std::make_tuple(val, ANY_INSTANCE)); + } else { + VSOMEIP_INFO << "+filter " + << std::hex << std::setw(4) << std::setfill('0') << prev_val << "." + << std::hex << std::setw(4) << std::setfill('0') << val; + client_side_logging_filter_.insert(std::make_tuple(prev_val, val)); + } + val = 0xffffu; + } + } + break; + default: + stop_parsing = true; + break; + } + } + } + while (!stop_parsing && its_converter.good()); + } } std::shared_ptr its_configuration = get_configuration(); @@ -157,7 +199,7 @@ bool application_impl::init() { routing_ = std::make_shared(this); } else { VSOMEIP_INFO << "Instantiating routing manager [Proxy]."; - routing_ = std::make_shared(this, client_side_logging_); + routing_ = std::make_shared(this, client_side_logging_, client_side_logging_filter_); } routing_->init(); @@ -273,8 +315,8 @@ void application_impl::start() { { std::lock_guard its_lock_start_stop(block_stop_mutex_); block_stopping_ = true; + block_stop_cv_.notify_all(); } - block_stop_cv_.notify_all(); stopped_ = false; return; @@ -357,8 +399,8 @@ void application_impl::start() { { std::lock_guard its_lock_start_stop(block_stop_mutex_); block_stopping_ = true; + block_stop_cv_.notify_all(); } - block_stop_cv_.notify_all(); { std::lock_guard its_lock(start_stop_mutex_); @@ -414,7 +456,10 @@ void application_impl::stop() { } - stop_cv_.notify_one(); + { + std::lock_guard its_lock_start_stop(start_stop_mutex_); + stop_cv_.notify_one(); + } if (block) { std::unique_lock block_stop_lock(block_stop_mutex_); @@ -697,7 +742,10 @@ bool application_impl::are_available_unlocked(available_t &_available, void application_impl::send(std::shared_ptr _message, bool _flush) { std::lock_guard its_lock(session_mutex_); bool is_request = utility::is_request(_message); - if (client_side_logging_) { + if (client_side_logging_ + && (client_side_logging_filter_.empty() + || (1 == client_side_logging_filter_.count(std::make_tuple(_message->get_service(), ANY_INSTANCE))) + || (1 == client_side_logging_filter_.count(std::make_tuple(_message->get_service(), _message->get_instance()))))) { VSOMEIP_INFO << "application_impl::send: (" << std::hex << std::setw(4) << std::setfill('0') << client_ <<"): [" << std::hex << std::setw(4) << std::setfill('0') << _message->get_service() << "." @@ -1029,24 +1077,26 @@ void application_impl::deliver_subscription_state(service_t _service, instance_t } } } - for (auto &handler : handlers) { + { std::unique_lock handlers_lock(handlers_mutex_); - std::shared_ptr its_sync_handler - = std::make_shared([handler, _service, - _instance, _eventgroup, - _event, _error]() { - handler(_service, _instance, - _eventgroup, _event, _error); - }); - its_sync_handler->handler_type_ = handler_type_e::SUBSCRIPTION; - its_sync_handler->service_id_ = _service; - its_sync_handler->instance_id_ = _instance; - its_sync_handler->method_id_ = _event; - its_sync_handler->eventgroup_id_ = _eventgroup; - handlers_.push_back(its_sync_handler); - } - if (handlers.size()) { - dispatcher_condition_.notify_all(); + for (auto &handler : handlers) { + std::shared_ptr its_sync_handler + = std::make_shared([handler, _service, + _instance, _eventgroup, + _event, _error]() { + handler(_service, _instance, + _eventgroup, _event, _error); + }); + its_sync_handler->handler_type_ = handler_type_e::SUBSCRIPTION; + its_sync_handler->service_id_ = _service; + its_sync_handler->instance_id_ = _instance; + its_sync_handler->method_id_ = _event; + its_sync_handler->eventgroup_id_ = _eventgroup; + handlers_.push_back(its_sync_handler); + } + if (handlers.size()) { + dispatcher_condition_.notify_one(); + } } } @@ -1069,18 +1119,16 @@ void application_impl::on_subscription_error(service_t _service, } } if (handler) { - { - std::unique_lock handlers_lock(handlers_mutex_); - std::shared_ptr its_sync_handler - = std::make_shared([handler, _error]() { - handler(_error); - }); - its_sync_handler->handler_type_ = handler_type_e::SUBSCRIPTION; - its_sync_handler->service_id_ = _service; - its_sync_handler->instance_id_ = _instance; - its_sync_handler->eventgroup_id_ = _eventgroup; - handlers_.push_back(its_sync_handler); - } + std::unique_lock handlers_lock(handlers_mutex_); + std::shared_ptr its_sync_handler + = std::make_shared([handler, _error]() { + handler(_error); + }); + its_sync_handler->handler_type_ = handler_type_e::SUBSCRIPTION; + its_sync_handler->service_id_ = _service; + its_sync_handler->instance_id_ = _instance; + its_sync_handler->eventgroup_id_ = _eventgroup; + handlers_.push_back(its_sync_handler); dispatcher_condition_.notify_all(); } } @@ -1257,15 +1305,13 @@ void application_impl::on_state(state_type_e _state) { } } if (has_state_handler) { - { - std::lock_guard its_lock(handlers_mutex_); - std::shared_ptr its_sync_handler - = std::make_shared([handler, _state]() { - handler(_state); - }); - its_sync_handler->handler_type_ = handler_type_e::STATE; - handlers_.push_back(its_sync_handler); - } + std::lock_guard its_lock(handlers_mutex_); + std::shared_ptr its_sync_handler + = std::make_shared([handler, _state]() { + handler(_state); + }); + its_sync_handler->handler_type_ = handler_type_e::STATE; + handlers_.push_back(its_sync_handler); dispatcher_condition_.notify_one(); } } @@ -1391,6 +1437,7 @@ void application_impl::on_availability(service_t _service, instance_t _instance, } if (its_handlers.size()) { + std::lock_guard handlers_lock(handlers_mutex_); dispatcher_condition_.notify_one(); } } @@ -1466,21 +1513,19 @@ void application_impl::on_message(const std::shared_ptr &&_message) { } if (its_handlers.size()) { - { - std::lock_guard its_lock(handlers_mutex_); - for (const auto &its_handler : its_handlers) { - auto handler = its_handler.handler_; - std::shared_ptr its_sync_handler = - std::make_shared([handler, _message]() { - handler(std::move(_message)); - }); - its_sync_handler->handler_type_ = handler_type_e::MESSAGE; - its_sync_handler->service_id_ = _message->get_service(); - its_sync_handler->instance_id_ = _message->get_instance(); - its_sync_handler->method_id_ = _message->get_method(); - its_sync_handler->session_id_ = _message->get_session(); - handlers_.push_back(its_sync_handler); - } + std::lock_guard its_lock(handlers_mutex_); + for (const auto &its_handler : its_handlers) { + auto handler = its_handler.handler_; + std::shared_ptr its_sync_handler = + std::make_shared([handler, _message]() { + handler(std::move(_message)); + }); + its_sync_handler->handler_type_ = handler_type_e::MESSAGE; + its_sync_handler->service_id_ = _message->get_service(); + its_sync_handler->instance_id_ = _message->get_instance(); + its_sync_handler->method_id_ = _message->get_method(); + its_sync_handler->session_id_ = _message->get_session(); + handlers_.push_back(its_sync_handler); } dispatcher_condition_.notify_one(); } @@ -1588,7 +1633,6 @@ void application_impl::invoke_handler(std::shared_ptr &_handler) { bool active_dispatcher_available(false); if (is_dispatching_) { std::lock_guard its_lock(dispatcher_mutex_); - blocked_dispatchers_.insert(its_id); active_dispatcher_available = has_active_dispatcher(); } if (active_dispatcher_available) { @@ -1612,7 +1656,10 @@ void application_impl::invoke_handler(std::shared_ptr &_handler) { } } }); - if (client_side_logging_) { + if (client_side_logging_ + && (client_side_logging_filter_.empty() + || (1 == client_side_logging_filter_.count(std::make_tuple(its_sync_handler->service_id_, ANY_INSTANCE))) + || (1 == client_side_logging_filter_.count(std::make_tuple(its_sync_handler->service_id_, its_sync_handler->instance_id_))))) { VSOMEIP_INFO << "Invoking handler: (" << std::hex << std::setw(4) << std::setfill('0') << client_ <<"): [" << std::hex << std::setw(4) << std::setfill('0') << its_sync_handler->service_id_ << "." @@ -1622,17 +1669,28 @@ void application_impl::invoke_handler(std::shared_ptr &_handler) { << "type=" << static_cast(its_sync_handler->handler_type_) << " thread=" << std::hex << its_id; } - _handler->handler_(); - its_dispatcher_timer.cancel(); + { + std::lock_guard its_lock(dispatcher_mutex_); + running_dispatchers_.insert(its_id); + } + try { + _handler->handler_(); + } catch (const std::exception &e) { + VSOMEIP_ERROR << "application_impl::invoke_handler caught exception: " + << e.what(); + print_blocking_call(its_sync_handler); + } + boost::system::error_code ec; + its_dispatcher_timer.cancel(ec); if (is_dispatching_) { std::lock_guard its_lock(dispatcher_mutex_); - blocked_dispatchers_.erase(its_id); + running_dispatchers_.erase(its_id); } } bool application_impl::has_active_dispatcher() { for (const auto &d : dispatchers_) { - if (blocked_dispatchers_.find(d.first) == blocked_dispatchers_.end() && + if (running_dispatchers_.find(d.first) == running_dispatchers_.end() && elapsed_dispatchers_.find(d.first) == elapsed_dispatchers_.end()) { return true; } @@ -1647,7 +1705,7 @@ bool application_impl::is_active_dispatcher(const std::thread::id &_id) { std::lock_guard its_lock(dispatcher_mutex_); for (const auto &d : dispatchers_) { if (d.first != _id && - blocked_dispatchers_.find(d.first) == blocked_dispatchers_.end() && + running_dispatchers_.find(d.first) == running_dispatchers_.end() && elapsed_dispatchers_.find(d.first) == elapsed_dispatchers_.end()) { return false; } @@ -1741,7 +1799,7 @@ void application_impl::shutdown() { its_dispatcher.second->detach(); } } - blocked_dispatchers_.clear(); + running_dispatchers_.clear(); elapsed_dispatchers_.clear(); dispatchers_.clear(); } @@ -2064,15 +2122,13 @@ void application_impl::on_offered_services_info(std::vector its_lock(handlers_mutex_); - std::shared_ptr its_sync_handler - = std::make_shared([handler, _services]() { - handler(_services); - }); - its_sync_handler->handler_type_ = handler_type_e::OFFERED_SERVICES_INFO; - handlers_.push_back(its_sync_handler); - } + std::lock_guard its_lock(handlers_mutex_); + std::shared_ptr its_sync_handler + = std::make_shared([handler, _services]() { + handler(_services); + }); + its_sync_handler->handler_type_ = handler_type_e::OFFERED_SERVICES_INFO; + handlers_.push_back(its_sync_handler); dispatcher_condition_.notify_one(); } } @@ -2097,9 +2153,8 @@ void application_impl::watchdog_cbk(boost::system::error_code const &_error) { = std::make_shared([handler]() { handler(); }); its_sync_handler->handler_type_ = handler_type_e::WATCHDOG; handlers_.push_back(its_sync_handler); + dispatcher_condition_.notify_one(); } - dispatcher_condition_.notify_one(); - } } diff --git a/implementation/service_discovery/src/service_discovery_impl.cpp b/implementation/service_discovery/src/service_discovery_impl.cpp index e25ca5bb5..f2171fb61 100644 --- a/implementation/service_discovery/src/service_discovery_impl.cpp +++ b/implementation/service_discovery/src/service_discovery_impl.cpp @@ -1085,7 +1085,6 @@ bool service_discovery_impl::send(bool _is_announcing) { std::shared_ptr < message_impl > its_message; if(_is_announcing) { - remote_subscription_not_acknowledge_all(); its_message = its_runtime->create_message(); its_messages.push_back(its_message); diff --git a/test/application_tests/application_test.cpp b/test/application_tests/application_test.cpp index b7c3ac096..7862528d2 100644 --- a/test/application_tests/application_test.cpp +++ b/test/application_tests/application_test.cpp @@ -310,6 +310,123 @@ class someip_application_shutdown_test: public ::testing::Test { std::thread shutdown_thread_; }; +class someip_application_exception_test: public ::testing::Test { + +protected: + void SetUp() { + is_registered_ = false; + is_available_ = false; + + app_ = runtime::get()->create_application("application_test"); + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN, + std::bind(&someip_application_exception_test::on_message_shutdown, this, + std::placeholders::_1)); + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN+1, + std::bind(&someip_application_exception_test::on_message_exception, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&someip_application_exception_test::on_state, this, + std::placeholders::_1)); + app_->register_availability_handler( + vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&someip_application_exception_test::on_availability, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + shutdown_thread_ = std::thread(&someip_application_exception_test::send_shutdown_message, this); + + app_->start(); + } + + void TearDown() { + shutdown_thread_.join(); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + std::lock_guard its_lock(mutex_); + is_registered_ = true; + cv_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + (void)_service; + (void)_instance; + if(_is_available) { + std::lock_guard its_lock(mutex_); + is_available_ = _is_available; + cv_.notify_one(); + } + } + + void on_message_shutdown(const std::shared_ptr& _request) + { + (void)_request; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + app_->clear_all_handler(); + app_->stop(); + } + + void on_message_exception(const std::shared_ptr& _request) + { + (void)_request; + throw std::invalid_argument("something went terribly wrong"); + } + + void send_shutdown_message() { + { + std::unique_lock its_lock(mutex_); + while(!is_registered_) { + cv_.wait(its_lock); + } + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + while(!is_available_) { + cv_.wait(its_lock); + } + } + + std::shared_ptr r = runtime::get()->create_request(); + // call method which throws exception + r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + r->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN+1); + app_->send(r); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + + //shutdown test + r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + r->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN); + app_->send(r); + } + + bool is_registered_; + bool is_available_; + std::shared_ptr app_; + std::condition_variable cv_; + std::mutex mutex_; + std::thread shutdown_thread_; +}; + /** * @test Stop the application through a method invoked from a dispatcher thread */ @@ -317,6 +434,13 @@ TEST_F(someip_application_shutdown_test, stop_application_from_dispatcher_thread } +/** + * @test Catch unhandled exceptions from invoked handlers + */ +TEST_F(someip_application_exception_test, catch_exception_in_invoked_handler) { + +} + #ifndef _WIN32 int main(int argc, char** argv) {