From 5315798ff81796217b55eb8c622f154bb0a1c487 Mon Sep 17 00:00:00 2001 From: Juergen Gehring Date: Fri, 7 Apr 2017 03:30:13 -0700 Subject: vSomeIP 2.6.2 --- CHANGES | 8 + CMakeLists.txt | 2 +- documentation/vsomeipUserGuide | 8 + .../configuration/include/configuration.hpp | 1 + .../configuration/include/configuration_impl.hpp | 3 +- .../configuration/include/internal.hpp.in | 20 + .../configuration/src/configuration_impl.cpp | 21 +- implementation/endpoints/include/endpoint.hpp | 4 + implementation/endpoints/include/endpoint_impl.hpp | 5 + .../include/local_client_endpoint_impl.hpp | 6 - .../endpoints/include/tcp_server_endpoint_impl.hpp | 2 + .../include/virtual_server_endpoint_impl.hpp | 2 + implementation/endpoints/src/endpoint_impl.cpp | 7 + .../endpoints/src/local_client_endpoint_impl.cpp | 13 +- .../endpoints/src/tcp_client_endpoint_impl.cpp | 11 +- .../endpoints/src/tcp_server_endpoint_impl.cpp | 26 +- .../endpoints/src/virtual_server_endpoint_impl.cpp | 5 + .../routing/include/routing_manager_base.hpp | 7 + .../routing/include/routing_manager_host.hpp | 1 + .../routing/include/routing_manager_impl.hpp | 9 +- .../routing/include/routing_manager_proxy.hpp | 33 +- .../routing/include/routing_manager_stub.hpp | 40 +- .../routing/include/routing_manager_stub_host.hpp | 5 +- implementation/routing/include/types.hpp | 6 + .../routing/src/routing_manager_base.cpp | 37 +- .../routing/src/routing_manager_impl.cpp | 97 ++--- .../routing/src/routing_manager_proxy.cpp | 244 ++++++++--- .../routing/src/routing_manager_stub.cpp | 470 +++++++++++++-------- implementation/runtime/src/application_impl.cpp | 2 - .../include/service_discovery_host.hpp | 5 +- .../src/service_discovery_impl.cpp | 7 +- implementation/utility/include/utility.hpp | 2 + implementation/utility/src/utility.cpp | 55 ++- test/CMakeLists.txt | 81 ++++ .../restart_routing_test_autoconfig.json | 24 ++ .../restart_routing_test_client.cpp | 158 +++++++ .../restart_routing_test_client.hpp | 50 +++ .../restart_routing_test_client.json | 48 +++ .../restart_routing_test_client_start.sh | 9 + .../restart_routing_test_service.cpp | 133 ++++++ .../restart_routing_test_service.hpp | 44 ++ .../restart_routing_test_service.json | 44 ++ .../restart_routing_test_service_start.sh | 9 + .../restart_routing_test_starter.sh | 312 ++++++++++++++ test/someip_test_globals.hpp | 2 + 45 files changed, 1706 insertions(+), 372 deletions(-) create mode 100644 test/restart_routing_tests/restart_routing_test_autoconfig.json create mode 100644 test/restart_routing_tests/restart_routing_test_client.cpp create mode 100644 test/restart_routing_tests/restart_routing_test_client.hpp create mode 100644 test/restart_routing_tests/restart_routing_test_client.json create mode 100755 test/restart_routing_tests/restart_routing_test_client_start.sh create mode 100644 test/restart_routing_tests/restart_routing_test_service.cpp create mode 100644 test/restart_routing_tests/restart_routing_test_service.hpp create mode 100644 test/restart_routing_tests/restart_routing_test_service.json create mode 100755 test/restart_routing_tests/restart_routing_test_service_start.sh create mode 100755 test/restart_routing_tests/restart_routing_test_starter.sh diff --git a/CHANGES b/CHANGES index f8f5401..712308b 100644 --- a/CHANGES +++ b/CHANGES @@ -288,3 +288,11 @@ v2.6.0 v2.6.1 - Fixed clearing of subscribers on stop offer service + +v2.6.2 +- Service-Disovery performance improvements +- Made Routing Manager restartable +- Fixed file handle leak caused by remote ECU reboot +- Activate TCP-Keep-Alive for TCP endpoints +- Debouncing of request-service messages (routing info performance) +- Fixed false session-id handling of identification request diff --git a/CMakeLists.txt b/CMakeLists.txt index f53cdf5..a7e67bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project (vsomeip) set (VSOMEIP_MAJOR_VERSION 2) set (VSOMEIP_MINOR_VERSION 6) -set (VSOMEIP_PATCH_VERSION 1) +set (VSOMEIP_PATCH_VERSION 2) set (VSOMEIP_VERSION ${VSOMEIP_MAJOR_VERSION}.${VSOMEIP_MINOR_VERSION}.${VSOMEIP_PATCH_VERSION}) set (PACKAGE_VERSION ${VSOMEIP_VERSION}) # Used in documentatin/doxygen.in set (CMAKE_VERBOSE_MAKEFILE off) diff --git a/documentation/vsomeipUserGuide b/documentation/vsomeipUserGuide index 4bc644d..b2c7d1d 100644 --- a/documentation/vsomeipUserGuide +++ b/documentation/vsomeipUserGuide @@ -399,6 +399,14 @@ callbacks if max_dispatchers is configured greater than 0). The number of internal threads to process messages and events within an application. Valid values are 1-255. Default is 2. + +** 'request_debounce_time' (optional) ++ +Specifies a debounce-time interval in ms in which request-service messages are sent to +the routing manager. If an application requests many services in short same time +the load of sent messages to the routing manager and furthermore the replies from the +routing manager (which contains the routing info for the requested service if available) +can be heavily reduced. The default value if not specified is 10ms. ++ * `services` (array) + Contains the services of the service provider. diff --git a/implementation/configuration/include/configuration.hpp b/implementation/configuration/include/configuration.hpp index 88a978b..26ebf36 100644 --- a/implementation/configuration/include/configuration.hpp +++ b/implementation/configuration/include/configuration.hpp @@ -74,6 +74,7 @@ public: 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::size_t get_io_thread_count(const std::string &_name) const = 0; + virtual std::size_t get_request_debouncing(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, diff --git a/implementation/configuration/include/configuration_impl.hpp b/implementation/configuration/include/configuration_impl.hpp index 9693d72..9f7c3c3 100644 --- a/implementation/configuration/include/configuration_impl.hpp +++ b/implementation/configuration/include/configuration_impl.hpp @@ -80,6 +80,7 @@ public: 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::size_t get_io_thread_count(const std::string &_name) const; + VSOMEIP_EXPORT std::size_t get_request_debouncing(const std::string &_name) const; VSOMEIP_EXPORT std::set > get_remote_services() const; @@ -227,7 +228,7 @@ protected: std::string logfile_; boost::log::trivial::severity_level loglevel_; - std::map> applications_; + std::map> applications_; std::set client_identifiers_; std::map #include +#include #define VSOMEIP_ENV_APPLICATION_NAME "VSOMEIP_APPLICATION_NAME" #define VSOMEIP_ENV_CONFIGURATION "VSOMEIP_CONFIGURATION" @@ -56,6 +57,8 @@ #define VSOMEIP_MAX_DESERIALIZER 5 +#define VSOMEIP_REQUEST_DEBOUNCE_TIME 10 + #define VSOMEIP_COMMAND_HEADER_SIZE 7 #define VSOMEIP_COMMAND_TYPE_POS 0 @@ -89,6 +92,7 @@ #define VSOMEIP_REGISTER_EVENT 0x1B #define VSOMEIP_UNREGISTER_EVENT 0x1C #define VSOMEIP_ID_RESPONSE 0x1D +#define VSOMEIP_ID_REQUEST 0x1E #define VSOMEIP_OFFER_SERVICE_COMMAND_SIZE 16 #define VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE 17 @@ -101,6 +105,7 @@ #define VSOMEIP_REGISTER_EVENT_COMMAND_SIZE 15 #define VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE 14 #define VSOMEIP_ID_RESPONSE_COMMAND_SIZE 12 +#define VSOMEIP_ID_REQUEST_COMMAND_SIZE 13 #ifndef _WIN32 #include @@ -126,10 +131,25 @@ typedef enum { RIE_DEL_CLIENT = 0x3, } routing_info_entry_e; +struct service_data_t { + service_t service_; + instance_t instance_; + major_version_t major_; + minor_version_t minor_; + bool use_exclusive_proxy_; // only used for requests! + + bool operator<(const service_data_t &_other) const { + return (service_ < _other.service_ + || (service_ == _other.service_ + && instance_ < _other.instance_)); + } +}; + struct configuration_data_t { #ifndef _WIN32 volatile char initialized_; pthread_mutex_t mutex_; + pid_t pid_; #endif unsigned short client_base_; diff --git a/implementation/configuration/src/configuration_impl.cpp b/implementation/configuration/src/configuration_impl.cpp index d2c6283..7375bdb 100644 --- a/implementation/configuration/src/configuration_impl.cpp +++ b/implementation/configuration/src/configuration_impl.cpp @@ -441,6 +441,7 @@ void configuration_impl::load_application_data( std::size_t its_max_dispatchers(VSOMEIP_MAX_DISPATCHERS); std::size_t its_max_dispatch_time(VSOMEIP_MAX_DISPATCH_TIME); std::size_t its_io_thread_count(VSOMEIP_IO_THREAD_COUNT); + std::size_t its_request_debounce_time(VSOMEIP_REQUEST_DEBOUNCE_TIME); for (auto i = _tree.begin(); i != _tree.end(); ++i) { std::string its_key(i->first); std::string its_value(i->second.data()); @@ -470,6 +471,13 @@ void configuration_impl::load_application_data( VSOMEIP_WARNING << "Max. number of threads per application is 255"; its_io_thread_count = 255; } + } else if (its_key == "request_debounce_time") { + its_converter << std::dec << its_value; + its_converter >> its_request_debounce_time; + if (its_request_debounce_time > 10000) { + VSOMEIP_WARNING << "Max. request debounce time is 10.000ms"; + its_request_debounce_time = 10000; + } } } if (its_name != "") { @@ -487,7 +495,8 @@ void configuration_impl::load_application_data( } applications_[its_name] = std::make_tuple(its_id, its_max_dispatchers, - its_max_dispatch_time, its_io_thread_count); + its_max_dispatch_time, its_io_thread_count, + its_request_debounce_time); } else { VSOMEIP_WARNING << "Multiple configurations for application " << its_name << ". Ignoring a configuration from " @@ -1797,6 +1806,16 @@ 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_request_debouncing(const std::string &_name) const { + size_t debounce_time = VSOMEIP_REQUEST_DEBOUNCE_TIME; + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + debounce_time = std::get<4>(found_application->second); + } + + return debounce_time; +} + std::size_t configuration_impl::get_io_thread_count(const std::string &_name) const { std::size_t its_io_thread_count = VSOMEIP_IO_THREAD_COUNT; diff --git a/implementation/endpoints/include/endpoint.hpp b/implementation/endpoints/include/endpoint.hpp index 39b018e..e8752c0 100644 --- a/implementation/endpoints/include/endpoint.hpp +++ b/implementation/endpoints/include/endpoint.hpp @@ -16,6 +16,8 @@ class endpoint_definition; class endpoint { public: + typedef std::function error_handler_t; + virtual ~endpoint() {} virtual void start() = 0; @@ -46,6 +48,8 @@ public: virtual uint32_t get_use_count() = 0; virtual void restart() = 0; + + virtual void register_error_handler(error_handler_t _error) = 0; }; } // namespace vsomeip diff --git a/implementation/endpoints/include/endpoint_impl.hpp b/implementation/endpoints/include/endpoint_impl.hpp index 3c9b3da..6b8b274 100644 --- a/implementation/endpoints/include/endpoint_impl.hpp +++ b/implementation/endpoints/include/endpoint_impl.hpp @@ -51,6 +51,8 @@ public: void decrement_use_count(); uint32_t get_use_count(); + void register_error_handler(error_handler_t _error_handler); + public: // required virtual bool is_client() const = 0; @@ -81,6 +83,9 @@ protected: std::mutex local_mutex_; endpoint_type local_; + + error_handler_t error_handler_; + std::mutex error_handler_mutex_; }; } // namespace vsomeip diff --git a/implementation/endpoints/include/local_client_endpoint_impl.hpp b/implementation/endpoints/include/local_client_endpoint_impl.hpp index 46d5c1d..7b71968 100644 --- a/implementation/endpoints/include/local_client_endpoint_impl.hpp +++ b/implementation/endpoints/include/local_client_endpoint_impl.hpp @@ -31,8 +31,6 @@ typedef client_endpoint_impl< class local_client_endpoint_impl: public local_client_endpoint_base_impl { public: - typedef std::function error_handler_t; - local_client_endpoint_impl(std::shared_ptr _host, endpoint_type _remote, boost::asio::io_service &_io, @@ -47,8 +45,6 @@ public: bool get_remote_address(boost::asio::ip::address &_address) const; unsigned short get_remote_port() const; - void register_error_handler(error_handler_t _error_handler); - void restart(); private: @@ -62,8 +58,6 @@ private: std::size_t _bytes); message_buffer_t recv_buffer_; - - error_handler_t error_handler_; }; } // namespace vsomeip diff --git a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp index c7b69f4..5875e71 100644 --- a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp @@ -34,6 +34,8 @@ public: void start(); void stop(); + void stop_all_connections(const boost::asio::ip::address &_address); + bool send_to(const std::shared_ptr _target, const byte_t *_data, uint32_t _size, bool _flush); void send_queued(queue_iterator_type _queue_iterator); diff --git a/implementation/endpoints/include/virtual_server_endpoint_impl.hpp b/implementation/endpoints/include/virtual_server_endpoint_impl.hpp index 8237e30..5e8c49e 100644 --- a/implementation/endpoints/include/virtual_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/virtual_server_endpoint_impl.hpp @@ -51,6 +51,8 @@ public: void restart(); + void register_error_handler(error_handler_t _handler); + private: std::string address_; uint16_t port_; diff --git a/implementation/endpoints/src/endpoint_impl.cpp b/implementation/endpoints/src/endpoint_impl.cpp index 1707502..1d16d05 100644 --- a/implementation/endpoints/src/endpoint_impl.cpp +++ b/implementation/endpoints/src/endpoint_impl.cpp @@ -134,6 +134,13 @@ uint32_t endpoint_impl::get_use_count() { return use_count_; } +template +void endpoint_impl::register_error_handler(error_handler_t _error_handler) { + std::lock_guard its_lock(error_handler_mutex_); + this->error_handler_ = _error_handler; +} + + // Instantiate template #ifndef _WIN32 template class endpoint_impl; diff --git a/implementation/endpoints/src/local_client_endpoint_impl.cpp b/implementation/endpoints/src/local_client_endpoint_impl.cpp index 6535ec6..4c79047 100644 --- a/implementation/endpoints/src/local_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/local_client_endpoint_impl.cpp @@ -183,8 +183,13 @@ void local_client_endpoint_impl::receive_cbk( // routing manager. For the routing manager proxies, the corresponding // client endpoint (that connect to the same client) are removed // after the proxy has received the routing info. - if (error_handler_) - error_handler_(); + error_handler_t handler; + { + std::lock_guard its_lock(error_handler_mutex_); + handler = error_handler_; + } + if (handler) + handler(); } else { receive(); } @@ -200,8 +205,4 @@ unsigned short local_client_endpoint_impl::get_remote_port() const { return 0; } -void local_client_endpoint_impl::register_error_handler(error_handler_t _error_handler) { - error_handler_ = _error_handler; -} - } // namespace vsomeip diff --git a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp index 916c78a..4afe3ef 100644 --- a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp @@ -67,6 +67,12 @@ void tcp_client_endpoint_impl::connect() { << "Nagle algorithm: " << its_error.message(); } + socket_.set_option(boost::asio::socket_base::keep_alive(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "tcp_client_endpoint::connect: couldn't enable " + << "keep_alive: " << its_error.message(); + } + // 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 @@ -351,8 +357,9 @@ void tcp_client_endpoint_impl::receive_cbk( receive(); } else { if (_error == boost::asio::error::connection_reset || - _error == boost::asio::error::eof) { - VSOMEIP_TRACE << "tcp_client_endpoint: connection_reseted/EOF ~> close socket!"; + _error == boost::asio::error::eof || + _error == boost::asio::error::timed_out) { + VSOMEIP_WARNING << "tcp_client_endpoint receive_cbk error detected: " << _error.message(); shutdown_and_close_socket(); } else { receive(); diff --git a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp index 39f2802..85766ef 100644 --- a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp @@ -85,6 +85,22 @@ void tcp_server_endpoint_impl::stop() { } } +void tcp_server_endpoint_impl::stop_all_connections(const boost::asio::ip::address &_address) { + std::lock_guard its_lock(connections_mutex_); + endpoint_type type; + + for (const auto &c : connections_) { + if(c.first.address() == _address) { + VSOMEIP_INFO << "Stopping connections for " << _address.to_string() + << " : " << std::dec << c.first.port(); + c.second->stop(); + type = c.first; + } + } + connections_.erase(type); +} + + bool tcp_server_endpoint_impl::send_to( const std::shared_ptr _target, const byte_t *_data, @@ -162,6 +178,12 @@ void tcp_server_endpoint_impl::accept_cbk(connection::ptr _connection, _connection->set_remote_info(remote); // Nagle algorithm off new_connection_socket.set_option(ip::tcp::no_delay(true), its_error); + + new_connection_socket.set_option(boost::asio::socket_base::keep_alive(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "tcp_server_endpoint::connect: couldn't enable " + << "keep_alive: " << its_error.message(); + } } if (!its_error) { { @@ -485,7 +507,9 @@ void tcp_server_endpoint_impl::connection::receive_cbk( } } if (_error == boost::asio::error::eof - || _error == boost::asio::error::connection_reset) { + || _error == boost::asio::error::connection_reset + || _error == boost::asio::error::timed_out) { + VSOMEIP_WARNING << "tcp_server_endpoint receive_cbk error detected: " << _error.message(); { std::lock_guard its_lock(its_server->connections_mutex_); stop(); diff --git a/implementation/endpoints/src/virtual_server_endpoint_impl.cpp b/implementation/endpoints/src/virtual_server_endpoint_impl.cpp index 4ea9ed2..6f20929 100644 --- a/implementation/endpoints/src/virtual_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/virtual_server_endpoint_impl.cpp @@ -113,4 +113,9 @@ void virtual_server_endpoint_impl::restart() { } +void virtual_server_endpoint_impl::register_error_handler( + error_handler_t _handler) { + (void)_handler; +} + } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_base.hpp b/implementation/routing/include/routing_manager_base.hpp index 625ed6a..e0ad57e 100644 --- a/implementation/routing/include/routing_manager_base.hpp +++ b/implementation/routing/include/routing_manager_base.hpp @@ -110,6 +110,7 @@ public: endpoint *_receiver, const boost::asio::ip::address &_remote_address, std::uint16_t _remote_port) = 0; + #ifndef _WIN32 virtual bool check_credentials(client_t _client, uid_t _uid, gid_t _gid); #endif @@ -119,6 +120,9 @@ public: virtual std::shared_ptr find_event(service_t _service, instance_t _instance, event_t _event) const; + virtual void register_client_error_handler(client_t _client, + const std::shared_ptr &_endpoint) = 0; + protected: std::shared_ptr find_service(service_t _service, instance_t _instance) const; std::shared_ptr create_service_info(service_t _service, @@ -182,6 +186,9 @@ protected: instance_t _instance, eventgroup_t _eventgroup, event_t _event); + void send_identify_request(service_t _service, instance_t _instance, + major_version_t _major, bool _reliable); + private: std::shared_ptr create_local_unlocked(client_t _client); std::shared_ptr find_local_unlocked(client_t _client); diff --git a/implementation/routing/include/routing_manager_host.hpp b/implementation/routing/include/routing_manager_host.hpp index bbea181..4b0edad 100644 --- a/implementation/routing/include/routing_manager_host.hpp +++ b/implementation/routing/include/routing_manager_host.hpp @@ -36,6 +36,7 @@ public: client_t _client, bool _subscribed) = 0; virtual void on_subscription_error(service_t _service, instance_t _instance, eventgroup_t _eventgroup, uint16_t _error) = 0; + virtual void send(std::shared_ptr _message, bool _flush) = 0; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_impl.hpp b/implementation/routing/include/routing_manager_impl.hpp index 2992c9e..a6d7f0d 100644 --- a/implementation/routing/include/routing_manager_impl.hpp +++ b/implementation/routing/include/routing_manager_impl.hpp @@ -171,7 +171,7 @@ public: std::shared_ptr create_service_discovery_endpoint(const std::string &_address, uint16_t _port, bool _reliable); void init_routing_info(); - std::chrono::milliseconds add_routing_info(service_t _service, instance_t _instance, + void add_routing_info(service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, ttl_t _ttl, const boost::asio::ip::address &_reliable_address, uint16_t _reliable_port, @@ -181,6 +181,8 @@ public: bool _has_reliable, bool _has_unreliable); std::chrono::milliseconds update_routing_info(std::chrono::milliseconds _elapsed); + void on_reboot(const boost::asio::ip::address &_address); + void on_subscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, std::shared_ptr _subscriber, @@ -204,8 +206,9 @@ public: bool has_identified(client_t _client, service_t _service, instance_t _instance, bool _reliable); - void on_clientendpoint_error(client_t _client); - void confirm_pending_offers(client_t _client); + void register_client_error_handler(client_t _client, + const std::shared_ptr &_endpoint); + void handle_client_error(client_t _client); void set_routing_state(routing_state_e _routing_state); diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_proxy.hpp index e725913..0bc25f7 100644 --- a/implementation/routing/include/routing_manager_proxy.hpp +++ b/implementation/routing/include/routing_manager_proxy.hpp @@ -95,17 +95,20 @@ public: void on_identify_response(client_t _client, service_t _service, instance_t _instance, bool _reliable); + void register_client_error_handler(client_t _client, + const std::shared_ptr &_endpoint); + void handle_client_error(client_t _client); + private: void register_application(); void deregister_application(); + void reconnect(const std::unordered_set &_clients); + void send_pong() const; void send_offer_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor); - 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, @@ -163,6 +166,10 @@ private: event_t _event, client_t _client); + void request_debounce_timeout_cbk(boost::system::error_code const &_error); + + void send_request_services(std::set& _requests); + private: enum class inner_state_type_e : std::uint8_t { ST_REGISTERED = 0x0, @@ -180,21 +187,9 @@ private: std::mutex known_clients_mutex_; std::unordered_set known_clients_; - struct service_data_t { - service_t service_; - instance_t instance_; - major_version_t major_; - minor_version_t minor_; - bool use_exclusive_proxy_; // only used for requests! - - bool operator<(const service_data_t &_other) const { - return (service_ < _other.service_ - || (service_ == _other.service_ - && instance_ < _other.instance_)); - } - }; std::set pending_offers_; - std::set pending_requests_; + std::set requests_; + std::set requests_to_debounce_; struct event_data_t { service_t service_; @@ -230,6 +225,10 @@ private: boost::asio::steady_timer register_application_timer_; std::shared_ptr logger_; + + std::mutex request_timer_mutex_; + boost::asio::steady_timer request_debounce_timer_; + bool request_debounce_timer_running_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_stub.hpp b/implementation/routing/include/routing_manager_stub.hpp index 819352f..13911dc 100644 --- a/implementation/routing/include/routing_manager_stub.hpp +++ b/implementation/routing/include/routing_manager_stub.hpp @@ -20,6 +20,7 @@ #include "../../endpoints/include/endpoint_host.hpp" #include "../../configuration/include/internal.hpp" +#include "types.hpp" namespace vsomeip { @@ -80,14 +81,19 @@ public: void create_local_receiver(); bool send_ping(client_t _client); bool is_registered(client_t _client) const; - void deregister_erroneous_client(client_t _client); client_t get_client() const; - void on_request_service(client_t _client, service_t _service, - instance_t _instance, major_version_t _major, - minor_version_t _minor); + void handle_requests(const client_t _client, std::set& _requests); + + void send_identify_request_command(std::shared_ptr _target, + service_t _service, instance_t _instance, major_version_t _major, + bool _reliable); + #ifndef _WIN32 virtual bool check_credentials(client_t _client, uid_t _uid, gid_t _gid); #endif + + void update_registration(client_t _client, registration_type_e _type); + private: void broadcast(const std::vector &_command) const; @@ -96,12 +102,6 @@ private: void broadcast_routing_stop(); - void send_routing_info_delta(client_t _target, routing_info_entry_e _entry, - client_t _client, service_t _service = ANY_SERVICE, - instance_t _instance = ANY_INSTANCE, - major_version_t _major = ANY_MAJOR, - minor_version_t _minor = ANY_MINOR); - void inform_requesters(client_t _hoster, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, routing_info_entry_e _entry, @@ -122,6 +122,15 @@ private: }; bool is_already_connected(client_t _source, client_t _sink); + void create_client_routing_info(const client_t _target); + void insert_client_routing_info(client_t _target, routing_info_entry_e _entry, + client_t _client, service_t _service = ANY_SERVICE, + instance_t _instance = ANY_INSTANCE, + major_version_t _major = ANY_MAJOR, + minor_version_t _minor = ANY_MINOR); + void send_client_routing_info(const client_t _target); + + void on_client_id_timer_expired(boost::system::error_code const &_error); private: routing_manager_stub_host *host_; @@ -129,6 +138,10 @@ private: std::mutex watchdog_timer_mutex_; boost::asio::steady_timer watchdog_timer_; + boost::asio::steady_timer client_id_timer_; + std::set used_client_ids_; + std::mutex used_client_ids_mutex_; + std::string endpoint_path_; std::string local_receiver_path_; std::shared_ptr endpoint_; @@ -147,11 +160,6 @@ private: std::mutex client_registration_mutex_; std::condition_variable client_registration_condition_; - enum class registration_type_e : std::uint8_t { - REGISTER = 0x1, - DEREGISTER = 0x2, - DEREGISTER_ERROR_CASE = 0x3 - }; std::map> pending_client_registrations_; const std::uint32_t max_local_message_size_; static const std::vector its_ping_; @@ -162,6 +170,8 @@ private: std::map > > > service_requests_; std::map> connection_matrix_; + + std::map> client_routing_info_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_stub_host.hpp b/implementation/routing/include/routing_manager_stub_host.hpp index 1606439..344d594 100644 --- a/implementation/routing/include/routing_manager_stub_host.hpp +++ b/implementation/routing/include/routing_manager_stub_host.hpp @@ -79,8 +79,9 @@ public: bool _reliable) = 0; virtual void on_pong(client_t _client) = 0; - virtual void on_clientendpoint_error(client_t _client) = 0; - virtual void confirm_pending_offers(client_t _client) = 0; + + virtual void handle_client_error(client_t _client) = 0; + virtual void set_routing_state(routing_state_e _routing_state) = 0; }; diff --git a/implementation/routing/include/types.hpp b/implementation/routing/include/types.hpp index 9b803a5..720e937 100644 --- a/implementation/routing/include/types.hpp +++ b/implementation/routing/include/types.hpp @@ -27,6 +27,12 @@ typedef std::map > > > eventgroups_t; +enum class registration_type_e : std::uint8_t { + REGISTER = 0x1, + DEREGISTER = 0x2, + DEREGISTER_ON_ERROR = 0x3 +}; + } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_base.cpp b/implementation/routing/src/routing_manager_base.cpp index 8f10057..04e4adb 100644 --- a/implementation/routing/src/routing_manager_base.cpp +++ b/implementation/routing/src/routing_manager_base.cpp @@ -13,7 +13,6 @@ #include "../../logging/include/logger.hpp" #include "../../endpoints/include/local_client_endpoint_impl.hpp" #include "../../endpoints/include/local_server_endpoint_impl.hpp" -#include "../include/routing_manager_impl.hpp" namespace vsomeip { @@ -624,22 +623,16 @@ std::shared_ptr routing_manager_base::create_local_unlocked(client_t _ #endif , io_, configuration_->get_max_message_size_local()); + // Messages sent to the VSOMEIP_ROUTING_CLIENT are meant to be routed to + // external devices. Therefore, its local endpoint must not be found by + // a call to find_local. Thus it must not be inserted to the list of local + // clients. 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] = std::static_pointer_cast(its_endpoint); - - routing_manager_impl *its_manager = dynamic_cast(this); - if (its_manager != nullptr) { - its_endpoint->register_error_handler( - std::bind(&routing_manager_impl::on_clientendpoint_error, - its_manager, _client)); - } + local_endpoints_[_client] = its_endpoint; } + register_client_error_handler(_client, its_endpoint); - return (its_endpoint); + return its_endpoint; } std::shared_ptr routing_manager_base::create_local(client_t _client) { @@ -682,6 +675,7 @@ void routing_manager_base::remove_local(client_t _client) { std::shared_ptr its_endpoint(find_local(_client)); if (its_endpoint) { + its_endpoint->register_error_handler(nullptr); its_endpoint->stop(); VSOMEIP_INFO << "Client [" << std::hex << get_client() << "] is closing connection to [" << std::hex << _client << "]"; @@ -1033,4 +1027,19 @@ routing_manager_base::get_subscriptions(const client_t _client) { return result; } +void routing_manager_base::send_identify_request(service_t _service, + instance_t _instance, major_version_t _major, bool _reliable) { + auto message = runtime::get()->create_message(_reliable); + message->set_service(_service); + message->set_instance(_instance); + message->set_client(get_client()); + message->set_method(ANY_METHOD - 1); + message->set_interface_version(_major); + message->set_message_type(message_type_e::MT_REQUEST); + + // Initiate a request/response to the remote service + // Use host for sending to ensure correct session id is set + host_->send(message, true); +} + } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_impl.cpp b/implementation/routing/src/routing_manager_impl.cpp index 145ff35..bfc232e 100644 --- a/implementation/routing/src/routing_manager_impl.cpp +++ b/implementation/routing/src/routing_manager_impl.cpp @@ -300,9 +300,12 @@ void routing_manager_impl::request_service(client_t _client, service_t _service, if (_client == get_client()) { stub_->create_local_receiver(); - } - stub_->on_request_service(_client, _service, _instance, _major, _minor); + service_data_t request = { _service, _instance, _major, _minor, _use_exclusive_proxy }; + std::set requests; + requests.insert(request); + stub_->handle_requests(_client, requests); + } } void routing_manager_impl::release_service(client_t _client, service_t _service, @@ -1775,7 +1778,7 @@ bool routing_manager_impl::is_field(service_t _service, instance_t _instance, return false; } -std::chrono::milliseconds routing_manager_impl::add_routing_info( +void routing_manager_impl::add_routing_info( service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, ttl_t _ttl, const boost::asio::ip::address &_reliable_address, @@ -1783,37 +1786,6 @@ std::chrono::milliseconds routing_manager_impl::add_routing_info( const boost::asio::ip::address &_unreliable_address, uint16_t _unreliable_port) { - std::chrono::seconds default_ttl(DEFAULT_TTL); - std::chrono::milliseconds its_smallest_ttl = - std::chrono::duration_cast(default_ttl); - std::chrono::milliseconds its_ttl(std::chrono::duration_cast( - std::chrono::seconds(_ttl))); - - bool offer_exists(false); - for (auto &s : get_services()) { - for (auto &i : s.second) { - if (i.second->is_local()) { - continue; //ignore local services - } - std::chrono::milliseconds its_found_ttl(i.second->get_precise_ttl()); - if ( its_found_ttl < its_smallest_ttl ) { - its_smallest_ttl = its_found_ttl; - if( its_ttl < its_smallest_ttl ) { - its_smallest_ttl = its_ttl; - } - } - offer_exists = true; - } - } - //if no remote service is in the list yet - if( !offer_exists ) { - if( its_ttl < its_smallest_ttl ) { - // set smallest TTL to TTL of first incoming remote offer - // this allows expiration of service if no further offer message is received which would trigger update_routing info - its_smallest_ttl = its_ttl; - } - } - // Create/Update service info std::shared_ptr its_info(find_service(_service, _instance)); if (!its_info) { @@ -1845,7 +1817,7 @@ std::chrono::milliseconds routing_manager_impl::add_routing_info( << std::hex << std::setfill('0') << std::setw(4) << _instance << "." << std::dec << static_cast(its_info->get_major()) << "." << its_info->get_minor() << "]"; - return its_smallest_ttl; + return; } else { its_info->set_ttl(_ttl); } @@ -2007,8 +1979,6 @@ std::chrono::milliseconds routing_manager_impl::add_routing_info( stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, _major, _minor); } } - - return its_smallest_ttl; } void routing_manager_impl::del_routing_info(service_t _service, instance_t _instance, @@ -2847,22 +2817,14 @@ bool routing_manager_impl::send_identify_message(client_t _client, std::lock_guard its_lock(identified_clients_mutex_); identifying_clients_[_service][_instance][_reliable].insert(_client); } - auto message = runtime::get()->create_message(_reliable); - 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())) { - its_endpoint->send(serializer_->get_data(), serializer_->get_size()); - serializer_->reset(); - } else { - return false; - } + + if (_client == get_client()) { + send_identify_request(_service, _instance, _major, _reliable); + } else { + stub_->send_identify_request_command(find_local(_client), + _service, _instance, _major, _reliable); } + return true; } @@ -3251,16 +3213,16 @@ void routing_manager_impl::on_pong(client_t _client) { } } -void routing_manager_impl::on_clientendpoint_error(client_t _client) { - if (stub_->is_registered(_client)) { - VSOMEIP_WARNING << "Application/Client " - << std::hex << std::setw(4) << std::setfill('0') - << _client << " will be deregistered because of an client endpoint error."; - stub_->deregister_erroneous_client(_client); - } +void routing_manager_impl::register_client_error_handler(client_t _client, + const std::shared_ptr &_endpoint) { + _endpoint->register_error_handler( + std::bind(&routing_manager_impl::handle_client_error, this, _client)); } -void routing_manager_impl::confirm_pending_offers(client_t _client) { +void routing_manager_impl::handle_client_error(client_t _client) { + if (stub_) + stub_->update_registration(_client, registration_type_e::DEREGISTER_ON_ERROR); + std::forward_list> its_offers; { @@ -3651,4 +3613,19 @@ bool routing_manager_impl::create_placeholder_event_and_subscribe( return is_inserted; } +void routing_manager_impl::on_reboot(const boost::asio::ip::address &_address){ + std::lock_guard its_lock(endpoint_mutex_); + for (auto its_port : server_endpoints_) { + for (auto its_endpoint : its_port.second) { + if (its_endpoint.first == true) { + std::shared_ptr endpoint = std::dynamic_pointer_cast(its_endpoint.second); + if (endpoint) { + endpoint->stop_all_connections(_address); + } + } + } + } +} + + } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_proxy.cpp b/implementation/routing/src/routing_manager_proxy.cpp index 79e85f2..00359f9 100644 --- a/implementation/routing/src/routing_manager_proxy.cpp +++ b/implementation/routing/src/routing_manager_proxy.cpp @@ -43,7 +43,9 @@ routing_manager_proxy::routing_manager_proxy(routing_manager_host *_host) : sender_(0), receiver_(0), register_application_timer_(io_), - logger_(logger::get()) + logger_(logger::get()), + request_debounce_timer_ (io_), + request_debounce_timer_running_(false) { } @@ -111,6 +113,11 @@ void routing_manager_proxy::stop() { is_started_ = false; its_lock.unlock(); + { + std::lock_guard its_lock(request_timer_mutex_); + request_debounce_timer_.cancel(); + } + if (receiver_) { receiver_->stop(); } @@ -251,12 +258,28 @@ void routing_manager_proxy::request_service(client_t _client, _minor, _use_exclusive_proxy); { std::lock_guard its_lock(state_mutex_); - if (state_ == inner_state_type_e::ST_REGISTERED) { - send_request_service(_client, _service, _instance, _major, _minor, - _use_exclusive_proxy); - } + size_t request_debouncing_time = configuration_->get_request_debouncing(host_->get_name()); service_data_t request = { _service, _instance, _major, _minor, _use_exclusive_proxy }; - pending_requests_.insert(request); + if (!request_debouncing_time) { + if (state_ == inner_state_type_e::ST_REGISTERED) { + std::set requests; + requests.insert(request); + send_request_services(requests); + } + requests_.insert(request); + } else { + requests_to_debounce_.insert(request); + std::lock_guard its_lock(request_timer_mutex_); + if (!request_debounce_timer_running_) { + request_debounce_timer_running_ = true; + request_debounce_timer_.expires_from_now(std::chrono::milliseconds(request_debouncing_time)); + request_debounce_timer_.async_wait( + std::bind( + &routing_manager_proxy::request_debounce_timeout_cbk, + std::dynamic_pointer_cast(shared_from_this()), + std::placeholders::_1)); + } + } } } @@ -266,18 +289,33 @@ void routing_manager_proxy::release_service(client_t _client, { std::lock_guard its_lock(state_mutex_); remove_pending_subscription(_service, _instance, 0xFFFF, ANY_EVENT); - if (state_ == inner_state_type_e::ST_REGISTERED) { - send_release_service(_client, _service, _instance); - } - auto it = pending_requests_.begin(); - while (it != pending_requests_.end()) { + + bool pending(false); + auto it = requests_to_debounce_.begin(); + while (it != requests_to_debounce_.end()) { if (it->service_ == _service && it->instance_ == _instance) { - break; + pending = true; } it++; } - if (it != pending_requests_.end()) pending_requests_.erase(it); + if (it != requests_to_debounce_.end()) requests_to_debounce_.erase(it); + + if (!pending && state_ == inner_state_type_e::ST_REGISTERED) { + send_release_service(_client, _service, _instance); + } + + { + auto it = requests_.begin(); + while (it != requests_.end()) { + if (it->service_ == _service + && it->instance_ == _instance) { + break; + } + it++; + } + if (it != requests_.end()) requests_.erase(it); + } } } @@ -754,6 +792,7 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, uint8_t is_remote_subscriber; client_t routing_host_id = configuration_->get_id(configuration_->get_routing_host()); client_t its_subscriber; + bool its_reliable; if (_size > VSOMEIP_COMMAND_SIZE_POS_MAX) { its_command = _data[VSOMEIP_COMMAND_TYPE_POS]; @@ -1006,6 +1045,24 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, << std::hex << std::setw(4) << std::setfill('0') << its_event << "]"; break; + case VSOMEIP_ID_REQUEST: + if (_size < VSOMEIP_ID_REQUEST_COMMAND_SIZE) { + VSOMEIP_WARNING << "Received a VSOMEIP_ID_REQUEST command with wrong size ~> skip!"; + break; + } + std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], + sizeof(its_service)); + std::memcpy(&its_instance, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2], + sizeof(its_instance)); + std::memcpy(&its_major, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], + sizeof(its_major)); + std::memcpy(&its_reliable, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 5], + sizeof(its_reliable)); + + send_identify_request(its_service, its_instance, its_major, its_reliable); + + break; + default: break; } @@ -1034,33 +1091,8 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, } } } - VSOMEIP_INFO << std::hex << "Application/Client " << get_client() - << " is deregistered."; - - // inform host about its own registration state changes - host_->on_state(static_cast(inner_state_type_e::ST_DEREGISTERED)); - - { - std::lock_guard its_lock(state_mutex_); - state_ = inner_state_type_e::ST_DEREGISTERED; - } - - // Notify stop() call about clean deregistration - state_condition_.notify_one(); - - // Remove all local connections/endpoints - for (const auto client : clients_to_delete) { - if (client != VSOMEIP_ROUTING_CLIENT) { - remove_local(client); - } - } - VSOMEIP_INFO << std::hex << "Application/Client " << get_client() - <<": Reconnecting to routing manager."; - std::lock_guard its_lock(sender_mutex_); - if (sender_) { - sender_->restart(); - } + reconnect(clients_to_delete); // Abort due to routing manager has stopped return; @@ -1242,6 +1274,33 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, } } +void routing_manager_proxy::reconnect(const std::unordered_set &_clients) { + // inform host about its own registration state changes + host_->on_state(static_cast(inner_state_type_e::ST_DEREGISTERED)); + + { + std::lock_guard its_lock(state_mutex_); + state_ = inner_state_type_e::ST_DEREGISTERED; + } + + // Notify stop() call about clean deregistration + state_condition_.notify_one(); + + // Remove all local connections/endpoints + for (const auto its_client : _clients) { + if (its_client != VSOMEIP_ROUTING_CLIENT) { + remove_local(its_client); + } + } + + VSOMEIP_INFO << std::hex << "Application/Client " << get_client() + <<": Reconnecting to routing manager."; + std::lock_guard its_lock(sender_mutex_); + if (sender_) { + sender_->restart(); + } +} + void routing_manager_proxy::register_application() { byte_t its_command[] = { VSOMEIP_REGISTER_APPLICATION, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -1265,7 +1324,8 @@ void routing_manager_proxy::register_application() { register_application_timer_.async_wait( std::bind( &routing_manager_proxy::register_application_timeout_cbk, - this, std::placeholders::_1)); + std::dynamic_pointer_cast(shared_from_this()), + std::placeholders::_1)); } } } @@ -1303,37 +1363,43 @@ void routing_manager_proxy::send_pong() const { } } -void routing_manager_proxy::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)_client; - - byte_t its_command[VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; +void routing_manager_proxy::send_request_services(std::set& _requests) { + if (!_requests.size()) { + return; + } + uint32_t its_size = (VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE - VSOMEIP_COMMAND_HEADER_SIZE) + * (uint32_t)_requests.size(); + std::vector its_command(its_size + VSOMEIP_COMMAND_HEADER_SIZE); its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_REQUEST_SERVICE; std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, sizeof(client_)); std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4] = _major; - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5], &_minor, - sizeof(_minor)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 9], &_use_exclusive_proxy, - sizeof(_use_exclusive_proxy)); + + uint32_t entry_size = (sizeof(service_t) + sizeof(instance_t) + sizeof(major_version_t) + + sizeof(minor_version_t) + sizeof(bool)); + + int i = 0; + for (auto its_service : _requests) { + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + (i * entry_size)], &its_service.service_, + sizeof(its_service.service_)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2 + (i * entry_size)], &its_service.instance_, + sizeof(its_service.instance_)); + its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4 + (i * entry_size)] = its_service.major_; + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5 + (i * entry_size)], &its_service.minor_, + sizeof(its_service.minor_)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 9 + (i * entry_size)], &its_service.use_exclusive_proxy_, + sizeof(its_service.use_exclusive_proxy_)); + ++i; + } { std::lock_guard its_lock(sender_mutex_); if (sender_) { - sender_->send(its_command, sizeof(its_command)); + sender_->send(&its_command[0], its_size + VSOMEIP_COMMAND_HEADER_SIZE); } } - } void routing_manager_proxy::send_release_service(client_t _client, service_t _service, @@ -1504,10 +1570,7 @@ void routing_manager_proxy::send_pending_commands() { per.event_, per.eventgroups_, per.is_field_, per.is_provided_); - for (auto &po : pending_requests_) { - send_request_service(client_, po.service_, po.instance_, - po.major_, po.minor_, po.use_exclusive_proxy_); - } + send_request_services(requests_); } void routing_manager_proxy::init_receiver() { @@ -1681,4 +1744,59 @@ bool routing_manager_proxy::create_placeholder_event_and_subscribe( } return is_inserted; } + +void routing_manager_proxy::request_debounce_timeout_cbk( + boost::system::error_code const &_error) { + std::lock_guard its_lock(state_mutex_); + if (!_error) { + if (requests_to_debounce_.size()) { + if (state_ == inner_state_type_e::ST_REGISTERED) { + send_request_services(requests_to_debounce_); + requests_.insert(requests_to_debounce_.begin(), + requests_to_debounce_.end()); + requests_to_debounce_.clear(); + } else { + { + std::lock_guard its_lock(request_timer_mutex_); + request_debounce_timer_running_ = true; + request_debounce_timer_.expires_from_now(std::chrono::milliseconds(configuration_->get_request_debouncing(host_->get_name()))); + request_debounce_timer_.async_wait( + std::bind( + &routing_manager_proxy::request_debounce_timeout_cbk, + std::dynamic_pointer_cast(shared_from_this()), + std::placeholders::_1)); + return; + } + } + } + } + { + std::lock_guard its_lock(request_timer_mutex_); + request_debounce_timer_running_ = false; + } +} + +void routing_manager_proxy::register_client_error_handler(client_t _client, + const std::shared_ptr &_endpoint) { + _endpoint->register_error_handler( + std::bind(&routing_manager_proxy::handle_client_error, this, _client)); +} + +void routing_manager_proxy::handle_client_error(client_t _client) { + if (_client != VSOMEIP_ROUTING_CLIENT) { + VSOMEIP_INFO << "Client 0x" << std::hex << get_client() + << " handles a client error(" << std::hex << _client << ")"; + remove_local(_client); + } else { + bool should_reconnect(true); + { + std::unique_lock its_lock(state_mutex_); + should_reconnect = is_started_; + } + if (should_reconnect) { + reconnect(known_clients_); + } + } +} + } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_stub.cpp b/implementation/routing/src/routing_manager_stub.cpp index 4146f59..526d6ce 100644 --- a/implementation/routing/src/routing_manager_stub.cpp +++ b/implementation/routing/src/routing_manager_stub.cpp @@ -46,6 +46,7 @@ routing_manager_stub::routing_manager_stub( host_(_host), io_(_host->get_io()), watchdog_timer_(_host->get_io()), + client_id_timer_(_host->get_io()), endpoint_(nullptr), local_receiver_(nullptr), configuration_(_configuration), @@ -65,6 +66,20 @@ void routing_manager_stub::init() { } void routing_manager_stub::start() { + { + std::lock_guard its_lock(used_client_ids_mutex_); + used_client_ids_ = utility::get_used_client_ids(); + // Wait VSOMEIP_MAX_CONNECT_TIMEOUT * 2 and expect after that time + // that all client_ids are used have to be connected to the routing. + // Otherwise they can be marked as "erroneous client". + client_id_timer_.expires_from_now(std::chrono::milliseconds(VSOMEIP_MAX_CONNECT_TIMEOUT * 2)); + client_id_timer_.async_wait( + std::bind( + &routing_manager_stub::on_client_id_timer_expired, + std::dynamic_pointer_cast(shared_from_this()), + std::placeholders::_1)); + } + if(!endpoint_) { // application has been stopped and started again init_routing_endpoint(); @@ -109,6 +124,11 @@ void routing_manager_stub::stop() { watchdog_timer_.cancel(); } + { + std::lock_guard its_lock(used_client_ids_mutex_); + client_id_timer_.cancel(); + } + if( !is_socket_activated_) { endpoint_->stop(); endpoint_ = nullptr; @@ -207,7 +227,6 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, const byte_t *its_data; uint32_t its_size; bool its_reliable(false); - bool use_exclusive_proxy(false); subscription_type_e its_subscription_type; bool is_remote_subscriber(false); client_t its_client_from_header; @@ -234,25 +253,11 @@ 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: - { - std::lock_guard its_lock(client_registration_mutex_); - VSOMEIP_INFO << "Application/Client " - << std::hex << std::setw(4) << std::setfill('0') - << its_client << " is registering."; - pending_client_registrations_[its_client].push_back(registration_type_e::REGISTER); - client_registration_condition_.notify_one(); - } + update_registration(its_client, registration_type_e::REGISTER); break; case VSOMEIP_DEREGISTER_APPLICATION: - { - 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(registration_type_e::DEREGISTER); - client_registration_condition_.notify_one(); - } + update_registration(its_client, registration_type_e::DEREGISTER); break; case VSOMEIP_PONG: @@ -468,31 +473,44 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, break; } case VSOMEIP_REQUEST_SERVICE: - if (_size != VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a REQUEST_SERVICE command with wrong size ~> skip!"; + { + uint32_t entry_size = (sizeof(service_t) + sizeof(instance_t) + sizeof(major_version_t) + + sizeof(minor_version_t) + sizeof(bool)); + uint32_t request_count(its_size / entry_size); + std::set requests; + for (uint32_t i = 0; i < request_count; ++i) { + service_t its_service; + instance_t its_instance; + major_version_t its_major; + minor_version_t its_minor; + bool use_exclusive_proxy; + std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + (i * entry_size)], + sizeof(its_service)); + std::memcpy(&its_instance, + &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2 + (i * entry_size)], + sizeof(its_instance)); + std::memcpy(&its_major, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4 + (i * entry_size)], + sizeof(its_major)); + std::memcpy(&its_minor, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 5 + (i * entry_size)], + sizeof(its_minor)); + std::memcpy(&use_exclusive_proxy, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 9 + (i * entry_size)], + sizeof(use_exclusive_proxy)); + if (configuration_->is_client_allowed(its_client, its_service, its_instance)) { + host_->request_service(its_client, its_service, its_instance, + its_major, its_minor, use_exclusive_proxy); + service_data_t request = { its_service, its_instance, + its_major, its_minor, use_exclusive_proxy }; + requests.insert(request); + } else { + VSOMEIP_WARNING << "Security: Client " << std::hex + << its_client << " requests service/instance " + << its_service << "/" << its_instance + << " which violates the security policy ~> Skip request!"; + } + } + handle_requests(its_client, requests); break; } - std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], - sizeof(its_service)); - std::memcpy(&its_instance, - &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2], - sizeof(its_instance)); - std::memcpy(&its_major, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_major)); - std::memcpy(&its_minor, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 5], - sizeof(its_minor)); - std::memcpy(&use_exclusive_proxy, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 9], - sizeof(use_exclusive_proxy)); - if (configuration_->is_client_allowed(its_client, its_service, its_instance)) { - host_->request_service(its_client, its_service, its_instance, - its_major, its_minor, use_exclusive_proxy); - } else { - VSOMEIP_WARNING << "Security: Client " << std::hex - << its_client << " requests service/instance " - << its_service << "/" << its_instance - << " which violates the security policy ~> Skip request!"; - } - break; case VSOMEIP_RELEASE_SERVICE: if (_size != VSOMEIP_RELEASE_SERVICE_COMMAND_SIZE) { @@ -594,7 +612,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, &_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(" + VSOMEIP_INFO << "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 @@ -673,13 +691,15 @@ void routing_manager_stub::client_registration_func(void) { // the client acknowledged its registered state! // Don't inform client if we deregister because of an client // endpoint error to avoid writing in an already closed socket - if (b != registration_type_e::DEREGISTER_ERROR_CASE) { + if (b != registration_type_e::DEREGISTER_ON_ERROR) { std::lock_guard its_guard(routing_info_mutex_); - send_routing_info_delta(r.first, + create_client_routing_info(r.first); + insert_client_routing_info(r.first, b == registration_type_e::REGISTER ? routing_info_entry_e::RIE_ADD_CLIENT : routing_info_entry_e::RIE_DEL_CLIENT, r.first); + send_client_routing_info(r.first); } if (b != registration_type_e::REGISTER) { { @@ -689,8 +709,10 @@ void routing_manager_stub::client_registration_func(void) { for (auto its_client : its_connection->second) { if (its_client != r.first && its_client != VSOMEIP_ROUTING_CLIENT) { - send_routing_info_delta(its_client, + create_client_routing_info(its_client); + insert_client_routing_info(its_client, routing_info_entry_e::RIE_DEL_CLIENT, r.first); + send_client_routing_info(its_client); } } connection_matrix_.erase(r.first); @@ -701,10 +723,9 @@ void routing_manager_stub::client_registration_func(void) { service_requests_.erase(r.first); } host_->remove_local(r.first); - } - if (b == registration_type_e::DEREGISTER_ERROR_CASE) { - utility::release_client_id(r.first); - host_->confirm_pending_offers(r.first); + if (b == registration_type_e::DEREGISTER_ON_ERROR) { + utility::release_client_id(r.first); + } } } } @@ -837,85 +858,33 @@ void routing_manager_stub::on_stop_offer_service(client_t _client, } } -void routing_manager_stub::send_routing_info_delta(client_t _target, - routing_info_entry_e _entry, - client_t _client, service_t _service, instance_t _instance, - major_version_t _major, minor_version_t _minor) { - std::shared_ptr its_endpoint = host_->find_local(_target); - if (its_endpoint) { - connection_matrix_[_target].insert(_client); - - std::vector its_command; - - // Routing command - its_command.push_back(VSOMEIP_ROUTING_INFO); - - // Sender client - client_t client = get_client(); - for (uint32_t i = 0; i < sizeof(client_t); ++i) { - its_command.push_back( - reinterpret_cast(&client)[i]); - } - - // Overall size placeholder - byte_t size_placeholder = 0x0; - for (uint32_t i = 0; i < sizeof(uint32_t); ++i) { - its_command.push_back(size_placeholder); - } - - // Routing Info State Change - for (uint32_t i = 0; i < sizeof(routing_info_entry_e); ++i) { - its_command.push_back( - reinterpret_cast(&_entry)[i]); - } +void routing_manager_stub::create_client_routing_info(const client_t _target) { + std::vector its_command; + its_command.push_back(VSOMEIP_ROUTING_INFO); - std::size_t its_size_pos = its_command.size(); - std::size_t its_entry_size = its_command.size(); + // Sender client + client_t client = get_client(); + for (uint32_t i = 0; i < sizeof(client_t); ++i) { + its_command.push_back( + reinterpret_cast(&client)[i]); + } - // 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(&_client)[i]); - } + // 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 (_entry == routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE || - _entry == routing_info_entry_e::RIE_DEL_SERVICE_INSTANCE) { - //Service - uint32_t its_service_entry_size = uint32_t(sizeof(service_t) - + 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]); - } - for (uint32_t i = 0; i < sizeof(service_t); ++i) { - its_command.push_back( - reinterpret_cast(&_service)[i]); - } - // 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(&_major)[i]); - } - // Minor version - for (uint32_t i = 0; i < sizeof(minor_version_t); ++i) { - its_command.push_back( - reinterpret_cast(&_minor)[i]); - } - } + client_routing_info_[_target] = its_command; +} - // 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)); +void routing_manager_stub::send_client_routing_info(const client_t _target) { + if (client_routing_info_.find(_target) == client_routing_info_.end()) { + return; + } + std::shared_ptr its_endpoint = host_->find_local(_target); + if (its_endpoint) { + auto its_command = client_routing_info_[_target]; // File overall size std::size_t its_size = its_command.size() - VSOMEIP_COMMAND_PAYLOAD_POS; @@ -937,9 +906,83 @@ void routing_manager_stub::send_routing_info_delta(client_t _target, } else { VSOMEIP_ERROR << "Routing info exceeds maximum message size: Can't send!"; } + + client_routing_info_.erase(_target); } } +void routing_manager_stub::insert_client_routing_info(client_t _target, + routing_info_entry_e _entry, + client_t _client, service_t _service, + instance_t _instance, + major_version_t _major, + minor_version_t _minor) { + + if (client_routing_info_.find(_target) == client_routing_info_.end()) { + return; + } + + connection_matrix_[_target].insert(_client); + + auto its_command = client_routing_info_[_target]; + + // Routing Info State Change + for (uint32_t i = 0; i < sizeof(routing_info_entry_e); ++i) { + its_command.push_back( + reinterpret_cast(&_entry)[i]); + } + + 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(&_client)[i]); + } + + if (_entry == routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE || + _entry == routing_info_entry_e::RIE_DEL_SERVICE_INSTANCE) { + //Service + uint32_t its_service_entry_size = uint32_t(sizeof(service_t) + + 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]); + } + for (uint32_t i = 0; i < sizeof(service_t); ++i) { + its_command.push_back( + reinterpret_cast(&_service)[i]); + } + // 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(&_major)[i]); + } + // Minor version + for (uint32_t i = 0; i < sizeof(minor_version_t); ++i) { + its_command.push_back( + reinterpret_cast(&_minor)[i]); + } + } + + // 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)); + + client_routing_info_[_target] = its_command; +} + void routing_manager_stub::inform_requesters(client_t _hoster, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, routing_info_entry_e _entry, bool _inform_service) { @@ -958,14 +1001,18 @@ void routing_manager_stub::inform_requesters(client_t _hoster, service_t _servic if (_hoster != VSOMEIP_ROUTING_CLIENT && _hoster != host_->get_client()) { if (!is_already_connected(_hoster, its_client.first)) { - send_routing_info_delta(_hoster, + create_client_routing_info(_hoster); + insert_client_routing_info(_hoster, routing_info_entry_e::RIE_ADD_CLIENT, its_client.first); + send_client_routing_info(_hoster); } } } - send_routing_info_delta(its_client.first, _entry, _hoster, + create_client_routing_info(its_client.first); + insert_client_routing_info(its_client.first, _entry, _hoster, _service, _instance, _major, _minor); + send_client_routing_info(its_client.first); } } } @@ -1223,7 +1270,7 @@ void routing_manager_stub::check_watchdog() { } } for (auto i : lost) { - deregister_erroneous_client(i); + host_->handle_client_error(i); } start_watchdog(); }; @@ -1373,10 +1420,10 @@ void routing_manager_stub::on_ping_timer_expired( } for (const client_t client : timed_out_clients) { - // client did not respond to ping. Report client_endpoint_error - // in order to accept pending offers trying to replace the offers of - // the now not responding client - host_->on_clientendpoint_error(client); + // Client did not respond to ping. Report client_error in order to + // accept pending offers trying to replace the offers of the client + // that seems to be gone. + host_->handle_client_error(client); } if (pinged_clients_remaining) { boost::system::error_code ec; @@ -1435,72 +1482,98 @@ bool routing_manager_stub::is_registered(client_t _client) const { return (routing_info_.find(_client) != routing_info_.end()); } -void routing_manager_stub::deregister_erroneous_client(client_t _client) { - std::lock_guard its_lock(client_registration_mutex_); +void routing_manager_stub::update_registration(client_t _client, + registration_type_e _type) { + VSOMEIP_INFO << "Application/Client " - << std::hex << std::setw(4) << std::setfill('0') - << _client << " is deregistering."; - pending_client_registrations_[_client].push_back(registration_type_e::DEREGISTER_ERROR_CASE); + << std::hex << std::setw(4) << std::setfill('0') << _client + << " is " + << (_type == registration_type_e::REGISTER ? + "registering." : "deregistering."); + + std::lock_guard its_lock(client_registration_mutex_); + pending_client_registrations_[_client].push_back(_type); client_registration_condition_.notify_one(); + + if (_type != registration_type_e::REGISTER) { + std::lock_guard its_lock(used_client_ids_mutex_); + used_client_ids_.erase(_client); + } } client_t routing_manager_stub::get_client() const { return host_->get_client(); } -void routing_manager_stub::on_request_service(client_t _client, service_t _service, - instance_t _instance, major_version_t _major, - minor_version_t _minor) { - +void routing_manager_stub::handle_requests(const client_t _client, std::set& _requests) { + if (!_requests.size()) { + return; + } std::lock_guard its_guard(routing_info_mutex_); - service_requests_[_client][_service][_instance] = std::make_pair(_major, _minor); - - for (auto found_client : routing_info_) { - auto found_service = found_client.second.second.find(_service); - if (found_service != found_client.second.second.end()) { - if (_instance == ANY_INSTANCE) { - if (found_client.first != VSOMEIP_ROUTING_CLIENT && - found_client.first != host_->get_client()) { - if (!is_already_connected(found_client.first, _client)) { - send_routing_info_delta(found_client.first, - routing_info_entry_e::RIE_ADD_CLIENT, _client); - } - } - if (_client != VSOMEIP_ROUTING_CLIENT && - _client != host_->get_client()) { - for (auto instance : found_service->second) { - send_routing_info_delta(_client, - routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, - found_client.first, _service, instance.first, - instance.second.first, instance.second.second); - } - } - - break; - } else { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { + create_client_routing_info(_client); + for (auto request : _requests) { + service_requests_[_client][request.service_][request.instance_] + = std::make_pair(request.major_, request.minor_); + for (auto found_client : routing_info_) { + auto found_service = found_client.second.second.find(request.service_); + if (found_service != found_client.second.second.end()) { + if (request.instance_ == ANY_INSTANCE) { if (found_client.first != VSOMEIP_ROUTING_CLIENT && found_client.first != host_->get_client()) { if (!is_already_connected(found_client.first, _client)) { - send_routing_info_delta(found_client.first, + if (_client == found_client.first) { + insert_client_routing_info(found_client.first, routing_info_entry_e::RIE_ADD_CLIENT, _client); + } else { + create_client_routing_info(found_client.first); + insert_client_routing_info(found_client.first, + routing_info_entry_e::RIE_ADD_CLIENT, _client); + send_client_routing_info(found_client.first); + } } } if (_client != VSOMEIP_ROUTING_CLIENT && _client != host_->get_client()) { - send_routing_info_delta(_client, - routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, - found_client.first, _service, _instance, - found_instance->second.first, - found_instance->second.second); + for (auto instance : found_service->second) { + insert_client_routing_info(_client, + routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, + found_client.first, request.service_, instance.first, + instance.second.first, instance.second.second); + } } - break; + } else { + auto found_instance = found_service->second.find(request.instance_); + if (found_instance != found_service->second.end()) { + if (found_client.first != VSOMEIP_ROUTING_CLIENT && + found_client.first != host_->get_client()) { + if (!is_already_connected(found_client.first, _client)) { + if (_client == found_client.first) { + insert_client_routing_info(found_client.first, + routing_info_entry_e::RIE_ADD_CLIENT, _client); + } else { + create_client_routing_info(found_client.first); + insert_client_routing_info(found_client.first, + routing_info_entry_e::RIE_ADD_CLIENT, _client); + send_client_routing_info(found_client.first); + } + } + } + if (_client != VSOMEIP_ROUTING_CLIENT && + _client != host_->get_client()) { + insert_client_routing_info(_client, + routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, + found_client.first, request.service_, request.instance_, + found_instance->second.first, + found_instance->second.second); + } + break; + } } } } } + send_client_routing_info(_client); } #ifndef _WIN32 @@ -1509,4 +1582,55 @@ bool routing_manager_stub::check_credentials(client_t _client, uid_t _uid, gid_t } #endif +void routing_manager_stub::send_identify_request_command(std::shared_ptr _target, + service_t _service, instance_t _instance, major_version_t _major, bool _reliable) { + if (_target) { + byte_t its_command[VSOMEIP_ID_REQUEST_COMMAND_SIZE]; + uint32_t its_size = VSOMEIP_ID_REQUEST_COMMAND_SIZE + - VSOMEIP_COMMAND_HEADER_SIZE; + its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_ID_REQUEST; + client_t client = get_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, + sizeof(_service)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, + sizeof(_instance)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_major, + sizeof(_major)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5], &_reliable, + sizeof(_reliable)); + + _target->send(its_command, sizeof(its_command)); + } +} + +void routing_manager_stub::on_client_id_timer_expired(boost::system::error_code const &_error) { + std::set used_client_ids; + { + std::lock_guard its_lock(used_client_ids_mutex_); + used_client_ids = used_client_ids_; + used_client_ids_.clear(); + } + + std::set erroneous_clients; + if (!_error) { + std::lock_guard its_lock(routing_info_mutex_); + for (auto client : used_client_ids) { + if (client != VSOMEIP_ROUTING_CLIENT && client != get_client()) { + if (routing_info_.find(client) == routing_info_.end()) { + erroneous_clients.insert(client); + } + } + } + } + for (auto client : erroneous_clients) { + VSOMEIP_WARNING << "Routinger Manager 0x" << std::hex << get_client() + << " : Release died Client 0x" << std::hex << client; + host_->handle_client_error(client); + } +} + } // namespace vsomeip diff --git a/implementation/runtime/src/application_impl.cpp b/implementation/runtime/src/application_impl.cpp index d4d4ed7..3ae0d61 100644 --- a/implementation/runtime/src/application_impl.cpp +++ b/implementation/runtime/src/application_impl.cpp @@ -973,9 +973,7 @@ void application_impl::on_state(state_type_e _state) { void application_impl::on_availability(service_t _service, instance_t _instance, bool _is_available, major_version_t _major, minor_version_t _minor) { - std::vector its_handlers; - { std::lock_guard availability_lock(availability_mutex_); if (_is_available == is_available_unlocked(_service, _instance, _major, _minor)) { diff --git a/implementation/service_discovery/include/service_discovery_host.hpp b/implementation/service_discovery/include/service_discovery_host.hpp index 710e4e7..0e1de9e 100644 --- a/implementation/service_discovery/include/service_discovery_host.hpp +++ b/implementation/service_discovery/include/service_discovery_host.hpp @@ -44,7 +44,7 @@ public: virtual bool send_to(const std::shared_ptr &_target, const byte_t *_data, uint32_t _size, uint16_t _sd_port) = 0; - virtual std::chrono::milliseconds add_routing_info(service_t _service, instance_t _instance, + virtual void add_routing_info(service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, ttl_t _ttl, const boost::asio::ip::address &_reliable_address, uint16_t _reliable_port, @@ -81,6 +81,9 @@ public: virtual void expire_subscriptions(const boost::asio::ip::address &_address) = 0; virtual void expire_services(const boost::asio::ip::address &_address) = 0; + virtual void on_reboot(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::steady_clock::time_point &_expiration) = 0; diff --git a/implementation/service_discovery/src/service_discovery_impl.cpp b/implementation/service_discovery/src/service_discovery_impl.cpp index 9fc955d..7318eda 100644 --- a/implementation/service_discovery/src/service_discovery_impl.cpp +++ b/implementation/service_discovery/src/service_discovery_impl.cpp @@ -1039,6 +1039,7 @@ void service_discovery_impl::on_message(const byte_t *_data, length_t _length, its_message->get_reboot_flag(), its_message->get_session())) { host_->expire_subscriptions(_sender); host_->expire_services(_sender); + host_->on_reboot(_sender); } std::chrono::milliseconds expired = stop_ttl_timer(); @@ -1214,10 +1215,14 @@ void service_discovery_impl::process_offerservice_serviceentry( its_request->set_sent_counter(std::uint8_t(repetitions_max_ + 1)); } - smallest_ttl_ = host_->add_routing_info(_service, _instance, + host_->add_routing_info(_service, _instance, _major, _minor, _ttl, _reliable_address, _reliable_port, _unreliable_address, _unreliable_port); + const std::chrono::milliseconds its_precise_ttl(_ttl * 1000); + if (its_precise_ttl < smallest_ttl_) { + smallest_ttl_ = its_precise_ttl; + } std::lock_guard its_lock(subscribed_mutex_); auto found_service = subscribed_.find(_service); diff --git a/implementation/utility/include/utility.hpp b/implementation/utility/include/utility.hpp index a638860..e48be1a 100644 --- a/implementation/utility/include/utility.hpp +++ b/implementation/utility/include/utility.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -88,6 +89,7 @@ public: static client_t request_client_id(const std::shared_ptr &_config, const std::string &_name, client_t _client); static void release_client_id(client_t _client); + static std::set get_used_client_ids(); static inline bool is_valid_message_type(message_type_e _type) { return (_type == message_type_e::MT_REQUEST diff --git a/implementation/utility/src/utility.cpp b/implementation/utility/src/utility.cpp index 8fc48db..f4f4449 100644 --- a/implementation/utility/src/utility.cpp +++ b/implementation/utility/src/utility.cpp @@ -7,6 +7,7 @@ #include #else #include + #include #include #include #include @@ -306,8 +307,6 @@ bool utility::auto_configuration_init(const std::shared_ptr &_con the_configuration_data__->routing_manager_host_ = 0x0000; std::string its_name = _config->get_routing_host(); - if (its_name == "") - the_configuration_data__->routing_manager_host_ = the_configuration_data__->client_base_; its_configuration_refs__++; @@ -340,7 +339,6 @@ bool utility::auto_configuration_init(const std::shared_ptr &_con VSOMEIP_ERROR << "utility::auto_configuration_init: " "ftruncate failed: " << std::strerror(errno); } else { - void *its_segment = mmap(0, sizeof(configuration_data_t), PROT_READ | PROT_WRITE, MAP_SHARED, its_descriptor, 0); @@ -460,6 +458,43 @@ bool utility::is_used_client_id(client_t _client) { return false; } +std::set utility::get_used_client_ids() { + std::set clients; + + std::unique_lock its_lock(its_local_configuration_mutex__); + + if (the_configuration_data__ != nullptr) { +#ifdef _WIN32 + DWORD waitResult = WaitForSingleObject(configuration_data_mutex, INFINITE); + assert(waitResult == WAIT_OBJECT_0); + (void)waitResult; +#else + if (EOWNERDEAD == pthread_mutex_lock(&the_configuration_data__->mutex_)) { + VSOMEIP_WARNING << "utility::request_client_id EOWNERDEAD"; + check_client_id_consistency(); + if (0 != pthread_mutex_consistent(&the_configuration_data__->mutex_)) { + VSOMEIP_ERROR << "pthread_mutex_consistent() failed "; + } + } +#endif + for (int i = 0; + i < the_configuration_data__->max_used_client_ids_index_; + i++) { + clients.insert(the_configuration_data__->used_client_ids_[i]); + } + +#ifdef _WIN32 + BOOL releaseResult = ReleaseMutex(configuration_data_mutex); + assert(releaseResult); + (void)releaseResult; +#else + pthread_mutex_unlock(&the_configuration_data__->mutex_); +#endif + } + + return clients; +} + client_t utility::request_client_id(const std::shared_ptr &_config, const std::string &_name, client_t _client) { std::unique_lock its_lock(its_local_configuration_mutex__); @@ -476,7 +511,18 @@ client_t utility::request_client_id(const std::shared_ptr &_confi VSOMEIP_ERROR << "pthread_mutex_consistent() failed "; } } + + pid_t pid = getpid(); + if (the_configuration_data__->pid_ != 0) { + if (pid != the_configuration_data__->pid_) { + if (kill(the_configuration_data__->pid_, 0) == -1) { + VSOMEIP_WARNING << "Routing Manager seems to be inactive. Taking over..."; + the_configuration_data__->routing_manager_host_ = 0x0000; + } + } + } #endif + const std::string its_name = _config->get_routing_host(); bool set_client_as_manager_host(false); if (its_name != "" && its_name == _name) { @@ -572,6 +618,9 @@ client_t utility::request_client_id(const std::shared_ptr &_confi if (set_client_as_manager_host) { the_configuration_data__->routing_manager_host_ = _client; +#ifndef _WIN32 + the_configuration_data__->pid_ = pid; +#endif } the_configuration_data__->used_client_ids_[ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7f841af..41f253a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -514,6 +514,80 @@ else() ) endif() ############################################################################## +# restart_routing-test +############################################################################## + +if(NOT ${TESTS_BAT}) + set(TEST_RESTART_ROUTING_NAME restart_routing_test) + + set(TEST_RESTART_ROUTING_SERVICE restart_routing_test_service) + add_executable(${TEST_RESTART_ROUTING_SERVICE} restart_routing_tests/${TEST_RESTART_ROUTING_SERVICE}.cpp) + target_link_libraries(${TEST_RESTART_ROUTING_SERVICE} + vsomeip + ${Boost_LIBRARIES} + ${DL_LIBRARY} + ${TEST_LINK_LIBRARIES} + ) + + # Copy config file for service into $BUILDDIR/test + set(TEST_RESTART_ROUTING_SERVICE_CONFIG_FILE ${TEST_RESTART_ROUTING_SERVICE}.json) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/restart_routing_tests/${TEST_RESTART_ROUTING_SERVICE_CONFIG_FILE} + ${PROJECT_BINARY_DIR}/test/${TEST_RESTART_ROUTING_SERVICE_CONFIG_FILE} + ${TEST_RESTART_ROUTING_SERVICE} + ) + + # Copy bashscript to start service into $BUILDDIR/test + set(TEST_RESTART_ROUTING_SERVICE_START_SCRIPT ${TEST_RESTART_ROUTING_SERVICE}_start.sh) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/restart_routing_tests/${TEST_RESTART_ROUTING_SERVICE_START_SCRIPT} + ${PROJECT_BINARY_DIR}/test/${TEST_RESTART_ROUTING_SERVICE_START_SCRIPT} + ${TEST_RESTART_ROUTING_SERVICE} + ) + + set(TEST_RESTART_ROUTING_CLIENT restart_routing_test_client) + add_executable(${TEST_RESTART_ROUTING_CLIENT} + restart_routing_tests/${TEST_RESTART_ROUTING_CLIENT}.cpp + ) + target_link_libraries(${TEST_RESTART_ROUTING_CLIENT} + vsomeip + ${Boost_LIBRARIES} + ${DL_LIBRARY} + ${TEST_LINK_LIBRARIES} + ) + + # Copy config file for client into $BUILDDIR/test + set(TEST_RESTART_ROUTING_CLIENT_CONFIG_FILE ${TEST_RESTART_ROUTING_CLIENT}.json) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/restart_routing_tests/${TEST_RESTART_ROUTING_CLIENT_CONFIG_FILE} + ${PROJECT_BINARY_DIR}/test/${TEST_RESTART_ROUTING_CLIENT_CONFIG_FILE} + ${TEST_RESTART_ROUTING_CLIENT} + ) + + # Copy bashscript to start client into $BUILDDIR/test + set(TEST_RESTART_ROUTING_CLIENT_START_SCRIPT ${TEST_RESTART_ROUTING_CLIENT}_start.sh) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/restart_routing_tests/${TEST_RESTART_ROUTING_CLIENT_START_SCRIPT} + ${PROJECT_BINARY_DIR}/test/${TEST_RESTART_ROUTING_CLIENT_START_SCRIPT} + ${TEST_RESTART_ROUTING_CLIENT} + ) + + # Copy bashscript to start client and server $BUILDDIR/test + set(TEST_RESTART_ROUTING_STARTER restart_routing_test_starter.sh) + copy_to_builddir(${PROJECT_SOURCE_DIR}/test/restart_routing_tests/${TEST_RESTART_ROUTING_STARTER} + ${PROJECT_BINARY_DIR}/test/${TEST_RESTART_ROUTING_STARTER} + ${TEST_RESTART_ROUTING_CLIENT} + ) + + # Copy config file for autoconfig into $BUILDDIR/test + set(TEST_RESTART_ROUTING_AUTO_CONFIG_FILE ${TEST_RESTART_ROUTING_NAME}_autoconfig.json) + copy_to_builddir( + ${PROJECT_SOURCE_DIR}/test/restart_routing_tests/${TEST_RESTART_ROUTING_AUTO_CONFIG_FILE} + ${PROJECT_BINARY_DIR}/test/${TEST_RESTART_ROUTING_AUTO_CONFIG_FILE} + ${TEST_RESTART_ROUTING_CLIENT} + ) +endif() +############################################################################## # payload-test ############################################################################## @@ -1712,6 +1786,8 @@ if(NOT ${TESTS_BAT}) add_dependencies(build_tests ${TEST_OFFER_CLIENT}) add_dependencies(build_tests ${TEST_OFFER_SERVICE_EXTERNAL}) add_dependencies(build_tests ${TEST_OFFER_EXTERNAL_SD_MESSAGE_SENDER}) + add_dependencies(build_tests ${TEST_RESTART_ROUTING_SERVICE}) + add_dependencies(build_tests ${TEST_RESTART_ROUTING_CLIENT}) else() add_dependencies(build_tests ${TEST_LOCAL_ROUTING_SERVICE}) add_dependencies(build_tests ${TEST_LOCAL_ROUTING_CLIENT}) @@ -2071,6 +2147,11 @@ if(NOT ${TESTS_BAT}) add_test(NAME ${TEST_OFFER_NAME}_external COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_OFFER_EXTERNAL_MASTER_STARTER}) set_tests_properties(${TEST_OFFER_NAME}_local PROPERTIES TIMEOUT 360) + + # Restart-Routing tests + add_test(NAME ${TEST_RESTART_ROUTING_NAME} + COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_RESTART_ROUTING_STARTER} + ) else() # Routing tests add_test(NAME ${TEST_LOCAL_ROUTING_NAME} diff --git a/test/restart_routing_tests/restart_routing_test_autoconfig.json b/test/restart_routing_tests/restart_routing_test_autoconfig.json new file mode 100644 index 0000000..f50dba7 --- /dev/null +++ b/test/restart_routing_tests/restart_routing_test_autoconfig.json @@ -0,0 +1,24 @@ +{ + "unicast" : "127.0.0.1", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "warning", + "console" : "true", + "file" : + { + "enable" : "true", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30491", + "protocol" : "udp" + } +} diff --git a/test/restart_routing_tests/restart_routing_test_client.cpp b/test/restart_routing_tests/restart_routing_test_client.cpp new file mode 100644 index 0000000..a8c0acc --- /dev/null +++ b/test/restart_routing_tests/restart_routing_test_client.cpp @@ -0,0 +1,158 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "restart_routing_test_client.hpp" + +routing_restart_test_client::routing_restart_test_client() + : app_(vsomeip::runtime::get()->create_application()), + is_available_(false), + sender_(std::bind(&routing_restart_test_client::run, this)), + received_responses_(0) { + +} + +bool routing_restart_test_client::init() { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_state_handler( + std::bind(&routing_restart_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&routing_restart_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&routing_restart_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + return true; +} + +void routing_restart_test_client::start() { + VSOMEIP_INFO << "Starting..."; + + app_->start(); +} + +void routing_restart_test_client::stop() { + VSOMEIP_INFO << "Stopping..."; + + shutdown_service(); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + app_->clear_all_handler(); + app_->stop(); +} + +void routing_restart_test_client::on_state(vsomeip::state_type_e _state) { + if(_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + } +} + +void routing_restart_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + + VSOMEIP_INFO << std::hex << "Client 0x" << app_->get_client() + << " : Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + + if(vsomeip_test::TEST_SERVICE_SERVICE_ID == _service + && vsomeip_test::TEST_SERVICE_INSTANCE_ID == _instance) { + std::unique_lock its_lock(mutex_); + if(is_available_ && !_is_available) { + is_available_ = false; + } + else if(_is_available && !is_available_) { + is_available_ = true; + condition_.notify_one(); + } + } +} + +void routing_restart_test_client::on_message(const std::shared_ptr &_response) { + VSOMEIP_INFO << "Received a response from Service [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_service() + << "." + << std::setw(4) << std::setfill('0') << std::hex << _response->get_instance() + << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_client() + << "/" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_session() + << "]"; + + if (_response->get_service() == vsomeip_test::TEST_SERVICE_SERVICE_ID && + _response->get_instance() == vsomeip_test::TEST_SERVICE_INSTANCE_ID) { + received_responses_++; + if (received_responses_ == vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_ROUTING_RESTART_TESTS) { + VSOMEIP_WARNING << std::hex << app_->get_client() + << ": Received all messages ~> going down!"; + } + } +} + +void routing_restart_test_client::run() { + for (uint32_t i = 0; i < vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_ROUTING_RESTART_TESTS; ++i) { + { + std::unique_lock its_lock(mutex_); + while (!is_available_) + { + condition_.wait(its_lock); + } + } + + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID); + app_->send(request, true); + + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + EXPECT_EQ(vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_ROUTING_RESTART_TESTS, + received_responses_); + + stop(); +} + +void routing_restart_test_client::join_sender_thread() +{ + if (sender_.joinable()) { + sender_.join(); + } +} + +void routing_restart_test_client::shutdown_service() { + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN); + app_->send(request,true); +} + +TEST(someip_restart_routing_test, request_response_over_restart) +{ + routing_restart_test_client test_client; + if (test_client.init()) { + test_client.start(); + test_client.join_sender_thread(); + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/restart_routing_tests/restart_routing_test_client.hpp b/test/restart_routing_tests/restart_routing_test_client.hpp new file mode 100644 index 0000000..fdc56d4 --- /dev/null +++ b/test/restart_routing_tests/restart_routing_test_client.hpp @@ -0,0 +1,50 @@ + +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef RESTART_ROUTING_TEST_CLIENT_HPP +#define RESTART_ROUTING_TEST_CLIENT_HPP + +#include + +#include + +#include "../someip_test_globals.hpp" + +#include +#include +#include +#include + +class routing_restart_test_client { +public: + routing_restart_test_client(); + bool init(); + void start(); + void stop(); + + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr &_response); + + void run(); + void join_sender_thread(); + +private: + void shutdown_service(); + + std::shared_ptr app_; + + std::mutex mutex_; + std::condition_variable condition_; + bool is_available_; + + std::thread sender_; + + std::atomic received_responses_; +}; + +#endif // RESTART_ROUTING_TEST_CLIENT_HPP diff --git a/test/restart_routing_tests/restart_routing_test_client.json b/test/restart_routing_tests/restart_routing_test_client.json new file mode 100644 index 0000000..0d901d8 --- /dev/null +++ b/test/restart_routing_tests/restart_routing_test_client.json @@ -0,0 +1,48 @@ +{ + "unicast" : "127.0.0.1", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "warning", + "console" : "true", + "file" : + { + "enable" : "true", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "restart_routing_test_client1", + "id" : "0x1343" + }, + { + "name" : "restart_routing_test_client2", + "id" : "0x1344" + }, + { + "name" : "restart_routing_test_client3", + "id" : "0x1345" + }, + { + "name" : "restart_routing_test_client4", + "id" : "0x1346" + } + ], + "services" : + [ + ], + + "routing" : "vsomeipd", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30491", + "protocol" : "udp" + } +} diff --git a/test/restart_routing_tests/restart_routing_test_client_start.sh b/test/restart_routing_tests/restart_routing_test_client_start.sh new file mode 100755 index 0000000..de944b9 --- /dev/null +++ b/test/restart_routing_tests/restart_routing_test_client_start.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client diff --git a/test/restart_routing_tests/restart_routing_test_service.cpp b/test/restart_routing_tests/restart_routing_test_service.cpp new file mode 100644 index 0000000..cf4bba1 --- /dev/null +++ b/test/restart_routing_tests/restart_routing_test_service.cpp @@ -0,0 +1,133 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "restart_routing_test_service.hpp" + +routing_restart_test_service::routing_restart_test_service() : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + blocked_(false), + number_of_received_messages_(0), + offer_thread_(std::bind(&routing_restart_test_service::run, this)) { +} + +bool routing_restart_test_service::init() { + std::lock_guard its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&routing_restart_test_service::on_message, 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, + std::bind(&routing_restart_test_service::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&routing_restart_test_service::on_state, this, + std::placeholders::_1)); + return true; +} + +void routing_restart_test_service::start() { + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void routing_restart_test_service::stop() { + VSOMEIP_INFO << "Stopping..."; + app_->clear_all_handler(); + app_->stop(); +} + +void routing_restart_test_service::join_offer_thread() { + if (offer_thread_.joinable()) { + offer_thread_.join(); + } +} + +void routing_restart_test_service::offer() { + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void routing_restart_test_service::stop_offer() { + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void routing_restart_test_service::on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) { + if(!is_registered_) { + is_registered_ = true; + std::lock_guard its_lock(mutex_); + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else { + is_registered_ = false; + } +} + +void routing_restart_test_service::on_message(const std::shared_ptr& _request) { + ASSERT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _request->get_service()); + ASSERT_EQ(vsomeip_test::TEST_SERVICE_METHOD_ID, _request->get_method()); + + VSOMEIP_INFO << "Received a message with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _request->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_session() << "]"; + + // send response + std::shared_ptr its_response = + vsomeip::runtime::get()->create_response(_request); + + app_->send(its_response, true); + + number_of_received_messages_++; + if(number_of_received_messages_ == vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_ROUTING_RESTART_TESTS) { + VSOMEIP_INFO << "Received all messages!"; + } +} + +void routing_restart_test_service::on_message_shutdown( + const std::shared_ptr& _request) { + (void)_request; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + stop(); +} + +void routing_restart_test_service::run() { + std::unique_lock its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + offer(); +} + +TEST(someip_restart_routing_test, send_response_for_every_request) { + routing_restart_test_service test_service; + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } +} + +#ifndef _WIN32 +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/test/restart_routing_tests/restart_routing_test_service.hpp b/test/restart_routing_tests/restart_routing_test_service.hpp new file mode 100644 index 0000000..3abfe17 --- /dev/null +++ b/test/restart_routing_tests/restart_routing_test_service.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef RESTART_ROUTING_TEST_SERVICE_HPP +#define RESTART_ROUTING_TEST_SERVICE_HPP + +#include + +#include + +#include "../someip_test_globals.hpp" + +#include +#include +#include + +class routing_restart_test_service { +public: + routing_restart_test_service(); + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr &_request); + void on_message_shutdown(const std::shared_ptr &_request); + void run(); + +private: + std::shared_ptr app_; + bool is_registered_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + std::uint32_t number_of_received_messages_; + std::thread offer_thread_; +}; + +#endif // RESTART_ROUTING_TEST_SERVICE_HPP diff --git a/test/restart_routing_tests/restart_routing_test_service.json b/test/restart_routing_tests/restart_routing_test_service.json new file mode 100644 index 0000000..8ff90cb --- /dev/null +++ b/test/restart_routing_tests/restart_routing_test_service.json @@ -0,0 +1,44 @@ +{ + "unicast" : "127.0.0.1", + "logging" : + { + "level" : "warning", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/tmp/vsomeip.log" + }, + + "dlt" : "false" + }, + + "applications" : + [ + { + "name" : "vsomeipd", + "id" : "0x0815" + }, + { + "name" : "restart_routing_test_service", + "id" : "0x1277" + } + ], + + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ], + + "routing" : "vsomeipd", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp" + } +} diff --git a/test/restart_routing_tests/restart_routing_test_service_start.sh b/test/restart_routing_tests/restart_routing_test_service_start.sh new file mode 100755 index 0000000..b82be7c --- /dev/null +++ b/test/restart_routing_tests/restart_routing_test_service_start.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +./restart_routing_test_service diff --git a/test/restart_routing_tests/restart_routing_test_starter.sh b/test/restart_routing_tests/restart_routing_test_starter.sh new file mode 100755 index 0000000..0778e98 --- /dev/null +++ b/test/restart_routing_tests/restart_routing_test_starter.sh @@ -0,0 +1,312 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit sucessfully. + +FAIL=0 + +# NOW WITHOUT JSON +echo "----------------------------------------------" +echo "----------------------------------------------" +echo " Run test with auto configuration " +echo "----------------------------------------------" +echo "----------------------------------------------" + +export VSOMEIP_CONFIGURATION=restart_routing_test_autoconfig.json + +../daemon/./vsomeipd & +DAEMON_PID=$! + +sleep 2 + +# Start the service +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +./restart_routing_test_service & +SERIVCE_PID=$! + +# Start the client1 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client1 +./restart_routing_test_client & +CLIENT1_PID=$! + +# Start the client2 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client2 +./restart_routing_test_client & +CLIENT2_PID=$! + +# Start the client3 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client3 +./restart_routing_test_client & +CLIENT3_PID=$! + +# Start the client4 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client4 +./restart_routing_test_client & +CLIENT4_PID=$! + +sleep 2 +echo "----------------------------------------------" +echo " let vsomeipd crash (kill -9) " +echo "----------------------------------------------" +kill -9 $DAEMON_PID +echo "----------------------------------------------" +echo " restart vsomeipd " +echo "----------------------------------------------" +sleep 2 + +../daemon/./vsomeipd & +DAEMON_PID=$! + +wait $SERIVCE_PID || ((FAIL+=1)) +wait $CLIENT1_PID || ((FAIL+=1)) +wait $CLIENT2_PID || ((FAIL+=1)) +wait $CLIENT3_PID || ((FAIL+=1)) +wait $CLIENT4_PID || ((FAIL+=1)) + +kill $DAEMON_PID +wait $DAEMON_PID + +# Check if client and server both exited sucessfully and the service didnt't +# have any open tcp/udp sockets +if [ $FAIL -eq 0 ] +then + echo "Test Succeeded" +else + exit 1 +fi + +# NOW WITHOUT VSOMEIPD +echo "----------------------------------------------" +echo "----------------------------------------------" +echo " Run test with auto configuration no deamon " +echo "----------------------------------------------" +echo "----------------------------------------------" + +sleep 2 + +# Start the service +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +./restart_routing_test_service & +SERIVCE_PID=$! + +# Start the client1 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client1 +./restart_routing_test_client & +CLIENT1_PID=$! + +# Start the client2 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client2 +./restart_routing_test_client & +CLIENT2_PID=$! + +# Start the client3 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client3 +./restart_routing_test_client & +CLIENT3_PID=$! + +# Start the client4 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client4 +./restart_routing_test_client & +CLIENT4_PID=$! + +sleep 2 +echo "----------------------------------------------" +echo " let service (routing) crash (kill -9) " +echo "----------------------------------------------" +kill -9 $SERIVCE_PID +echo "----------------------------------------------" +echo " restart service (routing) " +echo "----------------------------------------------" +sleep 2 + +# Start the service +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +./restart_routing_test_service & +SERIVCE_PID=$! + +wait $SERIVCE_PID || ((FAIL+=1)) +wait $CLIENT1_PID || ((FAIL+=1)) +wait $CLIENT2_PID || ((FAIL+=1)) +wait $CLIENT3_PID || ((FAIL+=1)) +wait $CLIENT4_PID || ((FAIL+=1)) + +# Check if client and server both exited sucessfully and the service didnt't +# have any open tcp/udp sockets +if [ $FAIL -eq 0 ] +then + echo "Test Succeeded" +else + exit 1 +fi + + +echo "----------------------------------------------" +echo "----------------------------------------------" +echo " Run test with json configuration " +echo "----------------------------------------------" +echo "----------------------------------------------" + +sleep 2 + +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +../daemon/./vsomeipd & +DAEMON_PID=$! + +# Start the service +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +./restart_routing_test_service & +SERIVCE_PID=$! + +# Start the client1 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client1 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT1_PID=$! + +# Start the client2 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client2 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT2_PID=$! + +# Start the client3 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client3 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT3_PID=$! + +# Start the client4 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client4 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT4_PID=$! + +sleep 2 +echo "----------------------------------------------" +echo " let vsomeipd crash (kill -9) " +echo "----------------------------------------------" +kill -9 $DAEMON_PID +echo "----------------------------------------------" +echo " restart vsomeipd " +echo "----------------------------------------------" +sleep 2 + +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +../daemon/./vsomeipd & +DAEMON_PID=$! + +wait $SERIVCE_PID || ((FAIL+=1)) +wait $CLIENT1_PID || ((FAIL+=1)) +wait $CLIENT2_PID || ((FAIL+=1)) +wait $CLIENT3_PID || ((FAIL+=1)) +wait $CLIENT4_PID || ((FAIL+=1)) + +kill $DAEMON_PID +wait $DAEMON_PID + +# Check if client and server both exited sucessfully and the service didnt't +# have any open tcp/udp sockets +if [ $FAIL -eq 0 ] +then + echo "Test Succeeded" +else + exit 1 +fi + +echo "----------------------------------------------" +echo "----------------------------------------------" +echo "Run test with json configuration + kill service" +echo "----------------------------------------------" +echo "----------------------------------------------" + +sleep 2 + +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +../daemon/./vsomeipd & +DAEMON_PID=$! + +# Start the service +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +./restart_routing_test_service & +SERIVCE_PID=$! + +# Start the client1 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client1 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT1_PID=$! + +# Start the client2 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client2 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT2_PID=$! + +# Start the client3 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client3 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT3_PID=$! + +# Start the client4 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client4 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT4_PID=$! + +sleep 2 +echo "----------------------------------------------" +echo " let vsomeipd crash (kill -9) " +echo "----------------------------------------------" +kill -9 $DAEMON_PID +sleep 1 +echo "----------------------------------------------" +echo " let service crash (kill -9) " +echo "----------------------------------------------" +kill -9 $SERIVCE_PID +echo "----------------------------------------------" +echo " restart vsomeipd " +echo "----------------------------------------------" +sleep 2 + +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +../daemon/./vsomeipd & +DAEMON_PID=$! + +echo "----------------------------------------------" +echo " restart service " +echo "----------------------------------------------" +sleep 1 + +# Start the service again +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +./restart_routing_test_service & +SERIVCE_PID=$! + +wait $SERIVCE_PID || ((FAIL+=1)) +wait $CLIENT1_PID || ((FAIL+=1)) +wait $CLIENT2_PID || ((FAIL+=1)) +wait $CLIENT3_PID || ((FAIL+=1)) +wait $CLIENT4_PID || ((FAIL+=1)) + +kill $DAEMON_PID +wait $DAEMON_PID + +# Check if client and server both exited sucessfully and the service didnt't +# have any open tcp/udp sockets +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/test/someip_test_globals.hpp b/test/someip_test_globals.hpp index 08397a7..5a5f916 100644 --- a/test/someip_test_globals.hpp +++ b/test/someip_test_globals.hpp @@ -35,6 +35,8 @@ constexpr vsomeip::byte_t PAYLOAD_TEST_DATA = 0xDD; constexpr std::uint32_t MAX_PAYLOADSIZE = 1024*128; // TR_SOMEIP_00061 constexpr std::uint32_t MAX_PAYLOADSIZE_UDP = 1400; + +constexpr std::uint32_t NUMBER_OF_MESSAGES_TO_SEND_ROUTING_RESTART_TESTS = 32; } #endif /* SOMEIP_TEST_GLOBALS_HPP_ */ -- cgit v1.2.1