diff options
Diffstat (limited to 'implementation/routing')
24 files changed, 6125 insertions, 5057 deletions
diff --git a/implementation/routing/include/event.hpp b/implementation/routing/include/event.hpp index b22b6ed..97adb89 100644 --- a/implementation/routing/include/event.hpp +++ b/implementation/routing/include/event.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -13,7 +13,6 @@ #include <set> #include <atomic> -#include <boost/asio/io_service.hpp> #include <boost/asio/ip/address.hpp> #include <boost/asio/steady_timer.hpp> @@ -35,6 +34,8 @@ class message; class payload; class routing_manager; +struct debounce_filter_t; + class event : public std::enable_shared_from_this<event> { public: @@ -52,16 +53,19 @@ public: event_t get_event() const; void set_event(event_t _event); - const std::shared_ptr<payload> get_payload() const; + std::shared_ptr<payload> get_payload() const; void set_payload(const std::shared_ptr<payload> &_payload, const client_t _client, bool _force); void set_payload(const std::shared_ptr<payload> &_payload, const client_t _client, - const std::shared_ptr<endpoint_definition>& _target, bool _force); + const std::shared_ptr<endpoint_definition>& _target); + + bool prepare_update_payload(const std::shared_ptr<payload> &_payload, + bool _force); + void update_payload(); - bool set_payload_dont_notify(const std::shared_ptr<payload> &_payload); bool set_payload_notify_pending(const std::shared_ptr<payload> &_payload); void set_payload(const std::shared_ptr<payload> &_payload, bool _force); @@ -90,20 +94,25 @@ public: void set_epsilon_change_function( const epsilon_change_func_t &_epsilon_change_func); - const std::set<eventgroup_t> get_eventgroups() const; + std::set<eventgroup_t> get_eventgroups() const; std::set<eventgroup_t> get_eventgroups(client_t _client) const; void add_eventgroup(eventgroup_t _eventgroup); void set_eventgroups(const std::set<eventgroup_t> &_eventgroups); void notify_one(client_t _client, const std::shared_ptr<endpoint_definition> &_target); - void notify_one(client_t _client); + void notify_one(client_t _client, bool _force); - bool add_subscriber(eventgroup_t _eventgroup, client_t _client, bool _force); + bool add_subscriber(eventgroup_t _eventgroup, + const std::shared_ptr<debounce_filter_t> &_filter, + client_t _client, bool _force); void remove_subscriber(eventgroup_t _eventgroup, client_t _client); bool has_subscriber(eventgroup_t _eventgroup, client_t _client); std::set<client_t> get_subscribers(); + std::set<client_t> get_filtered_subscribers(bool _force); + std::set<client_t> update_and_get_filtered_subscribers( + const std::shared_ptr<payload> &_payload, bool _force); VSOMEIP_EXPORT std::set<client_t> get_subscribers(eventgroup_t _eventgroup); void clear_subscribers(); @@ -122,30 +131,34 @@ public: void remove_pending(const std::shared_ptr<endpoint_definition> &_target); + void set_session(); + private: void update_cbk(boost::system::error_code const &_error); - void notify(); + void notify(bool _force); void notify(client_t _client, const std::shared_ptr<endpoint_definition> &_target); void start_cycle(); void stop_cycle(); - bool compare(const std::shared_ptr<payload> &_lhs, + bool has_changed(const std::shared_ptr<payload> &_lhs, const std::shared_ptr<payload> &_rhs) const; - bool set_payload_helper(const std::shared_ptr<payload> &_payload, - bool _force); - void reset_payload(const std::shared_ptr<payload> &_payload); - - void notify_one_unlocked(client_t _client); + void notify_one_unlocked(client_t _client, bool _force); void notify_one_unlocked(client_t _client, const std::shared_ptr<endpoint_definition> &_target); + bool prepare_update_payload_unlocked( + const std::shared_ptr<payload> &_payload, bool _force); + void update_payload_unlocked(); + private: routing_manager *routing_; mutable std::mutex mutex_; - std::shared_ptr<message> message_; + + std::shared_ptr<message> current_; + std::shared_ptr<message> update_; std::atomic<event_type_e> type_; @@ -172,6 +185,11 @@ private: std::atomic<reliability_type_e> reliability_; std::set<std::shared_ptr<endpoint_definition> > pending_; + + std::mutex filters_mutex_; + std::map<client_t, epsilon_change_func_t> filters_; + std::mutex last_forwarded_mutex_; + std::map<client_t, std::chrono::steady_clock::time_point> last_forwarded_; }; } // namespace vsomeip_v3 diff --git a/implementation/routing/include/eventgroupinfo.hpp b/implementation/routing/include/eventgroupinfo.hpp index 8ec1ac6..1a5a1b9 100644 --- a/implementation/routing/include/eventgroupinfo.hpp +++ b/implementation/routing/include/eventgroupinfo.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -67,7 +67,7 @@ public: uint16_t _port); VSOMEIP_EXPORT bool is_sending_multicast() const; - VSOMEIP_EXPORT const std::set<std::shared_ptr<event> > get_events() const; + VSOMEIP_EXPORT std::set<std::shared_ptr<event> > get_events() const; VSOMEIP_EXPORT void add_event(const std::shared_ptr<event>& _event); VSOMEIP_EXPORT void remove_event(const std::shared_ptr<event>& _event); VSOMEIP_EXPORT reliability_type_e get_reliability() const; diff --git a/implementation/routing/include/function_types.hpp b/implementation/routing/include/function_types.hpp index 3f89c08..f74ff37 100644 --- a/implementation/routing/include/function_types.hpp +++ b/implementation/routing/include/function_types.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2018-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -10,9 +10,8 @@ namespace vsomeip_v3 { class remote_subscription; -typedef std::function< - void (const std::shared_ptr<remote_subscription> &_subscription) -> remote_subscription_callback_t; +using remote_subscription_callback_t = + std::function<void (const std::shared_ptr<remote_subscription> &_subscription)>; } // namespace vsomeip_v3 diff --git a/implementation/routing/include/remote_subscription.hpp b/implementation/routing/include/remote_subscription.hpp index ff94d5b..f5bf2a2 100644 --- a/implementation/routing/include/remote_subscription.hpp +++ b/implementation/routing/include/remote_subscription.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2018-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -100,7 +100,6 @@ private: std::weak_ptr<eventgroupinfo> eventgroupinfo_; - major_version_t major_; ttl_t ttl_; std::uint16_t reserved_; std::uint8_t counter_; diff --git a/implementation/routing/include/routing_host.hpp b/implementation/routing/include/routing_host.hpp index 337e4a7..1decea3 100644 --- a/implementation/routing/include/routing_host.hpp +++ b/implementation/routing/include/routing_host.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -11,6 +11,7 @@ #include <boost/asio/ip/address.hpp> #include <vsomeip/primitive_types.hpp> +#include <vsomeip/vsomeip_sec.h> #ifdef ANDROID #include "../../configuration/include/internal_android.hpp" @@ -28,15 +29,19 @@ public: virtual void on_message(const byte_t *_data, length_t _length, endpoint *_receiver, - const boost::asio::ip::address &_destination = - boost::asio::ip::address(), + bool _is_multicast = false, client_t _bound_client = VSOMEIP_ROUTING_CLIENT, - credentials_t _credentials = {ANY_UID, ANY_GID}, + const vsomeip_sec_client_t *_sec_client = nullptr, const boost::asio::ip::address &_remote_address = boost::asio::ip::address(), std::uint16_t _remote_port = 0) = 0; virtual client_t get_client() const = 0; + virtual void add_known_client(client_t _client, const std::string &_client_host) = 0; + + virtual void remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port) = 0; }; } // namespace vsomeip_v3 diff --git a/implementation/routing/include/routing_manager.hpp b/implementation/routing/include/routing_manager.hpp index fa0e675..6fa7693 100644 --- a/implementation/routing/include/routing_manager.hpp +++ b/implementation/routing/include/routing_manager.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -10,11 +10,19 @@ #include <set> #include <vector> -#include <boost/asio/io_service.hpp> +#if VSOMEIP_BOOST_VERSION < 106600 +# include <boost/asio/io_service.hpp> +# define io_context io_service +#else +# include <boost/asio/io_context.hpp> +#endif #include <vsomeip/function_types.hpp> +#include <vsomeip/structured_types.hpp> #include <vsomeip/message.hpp> #include <vsomeip/handler.hpp> +#include <vsomeip/vsomeip_sec.h> + #include "types.hpp" namespace vsomeip_v3 { @@ -30,10 +38,12 @@ public: virtual ~routing_manager() { } - virtual boost::asio::io_service & get_io() = 0; + virtual boost::asio::io_context &get_io() = 0; virtual client_t get_client() const = 0; - virtual void set_client(const client_t &_client) = 0; - virtual session_t get_session() = 0; +// virtual void set_client(const client_t &_client) = 0; + virtual session_t get_session(bool _is_request) = 0; + + virtual const vsomeip_sec_client_t *get_sec_client() const = 0; virtual void init() = 0; virtual void start() = 0; @@ -54,24 +64,29 @@ public: virtual void release_service(client_t _client, service_t _service, instance_t _instance) = 0; - virtual void subscribe(client_t _client, uid_t _uid, gid_t _gid, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, event_t _event) = 0; + virtual void subscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter) = 0; - virtual void unsubscribe(client_t _client, uid_t _uid, gid_t _gid, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, event_t _event) = 0; + virtual void unsubscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) = 0; - virtual bool send(client_t _client, std::shared_ptr<message> _message) = 0; + virtual bool send(client_t _client, std::shared_ptr<message> _message, + bool _force) = 0; virtual bool send(client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, bool _reliable, client_t _bound_client = VSOMEIP_ROUTING_CLIENT, - credentials_t _credentials = {ANY_UID, ANY_GID}, - uint8_t _status_check = 0, bool _sent_from_remote = false) = 0; + const vsomeip_sec_client_t *_sec_client = nullptr, + uint8_t _status_check = 0, + bool _sent_from_remote = false, + bool _force = true) = 0; virtual bool send_to(const client_t _client, const std::shared_ptr<endpoint_definition> &_target, - std::shared_ptr<message>) = 0; + std::shared_ptr<message> _message) = 0; virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target, const byte_t *_data, uint32_t _size, instance_t _instance) = 0; diff --git a/implementation/routing/include/routing_manager_adapter.hpp b/implementation/routing/include/routing_manager_adapter.hpp index a2195ee..26154b0 100644 --- a/implementation/routing/include/routing_manager_adapter.hpp +++ b/implementation/routing/include/routing_manager_adapter.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/routing/include/routing_manager_base.hpp b/implementation/routing/include/routing_manager_base.hpp index 270f4c4..e4f9073 100644 --- a/implementation/routing/include/routing_manager_base.hpp +++ b/implementation/routing/include/routing_manager_base.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -12,16 +12,19 @@ #include <condition_variable> #include <vsomeip/constants.hpp> +#include <vsomeip/vsomeip_sec.h> -#include "routing_host.hpp" -#include "routing_manager.hpp" -#include "routing_manager_host.hpp" #include "types.hpp" -#include "serviceinfo.hpp" #include "event.hpp" +#include "serviceinfo.hpp" +#include "routing_host.hpp" #include "eventgroupinfo.hpp" +#include "routing_manager.hpp" +#include "routing_manager_host.hpp" + #include "../../message/include/serializer.hpp" #include "../../message/include/deserializer.hpp" +#include "../../protocol/include/protocol.hpp" #include "../../configuration/include/configuration.hpp" #include "../../endpoints/include/endpoint_manager_base.hpp" @@ -43,10 +46,19 @@ public: routing_manager_base(routing_manager_host *_host); virtual ~routing_manager_base() = default; - virtual boost::asio::io_service & get_io(); + virtual boost::asio::io_context &get_io(); virtual client_t get_client() const; + + virtual std::string get_client_host() const; + virtual void set_client_host(const std::string &_client_host); virtual void set_client(const client_t &_client); - virtual session_t get_session(); + virtual session_t get_session(bool _is_request); + + virtual const vsomeip_sec_client_t *get_sec_client() const; + + virtual std::string get_env(client_t _client) const = 0; + + virtual bool is_routing_manager() const; virtual void init() = 0; void init(const std::shared_ptr<endpoint_manager_base>& _endpoint_manager); @@ -83,11 +95,14 @@ public: virtual std::set<std::shared_ptr<event>> find_events(service_t _service, instance_t _instance, eventgroup_t _eventgroup) const; - virtual void subscribe(client_t _client, uid_t _uid, gid_t _gid, + virtual void subscribe(client_t _client, + const vsomeip_sec_client_t *_sec_client, service_t _service, instance_t _instance, - eventgroup_t _eventgroup, major_version_t _major, event_t _event); + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter); - virtual void unsubscribe(client_t _client, uid_t _uid, gid_t _gid, + virtual void unsubscribe(client_t _client, + const vsomeip_sec_client_t *_sec_client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event); @@ -102,23 +117,22 @@ public: #endif ); - virtual bool send(client_t _client, std::shared_ptr<message> _message); + virtual bool send(client_t _client, std::shared_ptr<message> _message, + bool _force); virtual bool send(client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, bool _reliable, - client_t _bound_client = VSOMEIP_ROUTING_CLIENT, - credentials_t _credentials = {ANY_UID, ANY_GID}, - uint8_t _status_check = 0, bool _sent_from_remote = false) = 0; + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _sent_from_remote, + bool _force) = 0; // routing host -> will be implemented by routing_manager_impl/_proxy/ virtual void on_message(const byte_t *_data, length_t _length, - endpoint *_receiver, const boost::asio::ip::address &_destination - = boost::asio::ip::address(), client_t _bound_client = VSOMEIP_ROUTING_CLIENT, - credentials_t _credentials = {ANY_UID, ANY_GID}, - const boost::asio::ip::address &_remote_address = boost::asio::ip::address(), + endpoint *_receiver, bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + const boost::asio::ip::address &_remote_address, std::uint16_t _remote_port = 0) = 0; - virtual void set_routing_state(routing_state_e _routing_state) = 0; virtual routing_state_e get_routing_state(); @@ -138,6 +152,17 @@ public: std::shared_ptr<event> find_event(service_t _service, instance_t _instance, event_t _event) const; + // address data for vsomeip routing via TCP + bool get_guest(client_t _client, boost::asio::ip::address &_address, + port_t &_port) const; + void add_guest(client_t _client, const boost::asio::ip::address &_address, + port_t _port); + void remove_guest(client_t _client); + + void remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port); + virtual void on_connect(const std::shared_ptr<endpoint>& _endpoint) = 0; virtual void on_disconnect(const std::shared_ptr<endpoint>& _endpoint) = 0; protected: @@ -150,10 +175,12 @@ protected: services_t get_services_remote() const; bool is_available(service_t _service, instance_t _instance, major_version_t _major); - void remove_local(client_t _client, bool _remove_uid); + void remove_local(client_t _client, bool _remove_sec_client); void remove_local(client_t _client, - const std::set<std::tuple<service_t, instance_t, eventgroup_t>>& _subscribed_eventgroups, - bool _remove_uid); + const std::set< + std::tuple<service_t, instance_t, eventgroup_t> + > &_subscribed_eventgroups, + bool _remove_sec_client); std::shared_ptr<eventgroupinfo> find_eventgroup(service_t _service, instance_t _instance, eventgroup_t _eventgroup) const; @@ -163,15 +190,16 @@ protected: bool send_local_notification(client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, - bool _reliable = false, uint8_t _status_check = 0); + bool _reliable, uint8_t _status_check, bool _force); bool send_local( std::shared_ptr<endpoint> &_target, client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, - bool _reliable, uint8_t _command, uint8_t _status_check = 0) const; + bool _reliable, protocol::id_e _command, uint8_t _status_check) const; bool insert_subscription(service_t _service, instance_t _instance, - eventgroup_t _eventgroup, event_t _event, client_t _client, + eventgroup_t _eventgroup, event_t _event, + const std::shared_ptr<debounce_filter_t> &_filter, client_t _client, std::set<event_t> *_already_subscribed_events); std::shared_ptr<serializer> get_serializer(); @@ -182,9 +210,10 @@ protected: void send_pending_subscriptions(service_t _service, instance_t _instance, major_version_t _major); - virtual void send_subscribe(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, event_t _event) = 0; + virtual void send_subscribe(client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter) = 0; void remove_pending_subscription(service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event); @@ -209,9 +238,11 @@ protected: bool is_response_allowed(client_t _sender, service_t _service, instance_t _instance, method_t _method); - bool is_subscribe_to_any_event_allowed(credentials_t _credentials, client_t _client, + bool is_subscribe_to_any_event_allowed( + const vsomeip_sec_client_t *_sec_client, client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup); - void unsubscribe_all(service_t _service, instance_t _instance); + + void add_known_client(client_t _client, const std::string &_client_host); #ifdef VSOMEIP_ENABLE_COMPAT void set_incoming_subscription_state(client_t _client, service_t _service, instance_t _instance, @@ -227,12 +258,12 @@ protected: private: virtual bool create_placeholder_event_and_subscribe( service_t _service, instance_t _instance, eventgroup_t _eventgroup, - event_t _event, client_t _client) = 0; + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter, + client_t _client) = 0; protected: routing_manager_host *host_; - boost::asio::io_service &io_; - std::atomic<client_t> client_; + boost::asio::io_context &io_; std::shared_ptr<configuration> configuration_; @@ -245,8 +276,9 @@ protected: std::condition_variable deserializer_condition_; mutable std::mutex local_services_mutex_; - typedef std::map<service_t, std::map<instance_t, - std::tuple<major_version_t, minor_version_t, client_t>>> local_services_map_t; + using local_services_map_t = + std::map<service_t, std::map<instance_t, + std::tuple<major_version_t, minor_version_t, client_t>>>; local_services_map_t local_services_; std::map<service_t, std::map<instance_t, std::set<client_t> > > local_services_history_; @@ -264,9 +296,6 @@ protected: std::mutex event_registration_mutex_; - std::mutex routing_state_mutex_; - routing_state_e routing_state_; - #ifdef USE_DLT std::shared_ptr<trace::connector_impl> tc_; #endif @@ -277,8 +306,8 @@ protected: eventgroup_t eventgroup_; major_version_t major_; event_t event_; - uid_t uid_; - gid_t gid_; + std::shared_ptr<debounce_filter_t> filter_; + vsomeip_sec_client_t sec_client_; bool operator<(const subscription_data_t &_other) const { return (service_ < _other.service_ @@ -300,13 +329,26 @@ protected: std::shared_ptr<endpoint_manager_base> ep_mgr_; - std::uint32_t own_uid_; - std::uint32_t own_gid_; + mutable std::mutex known_clients_mutex_; + std::map<client_t, std::string> known_clients_; + + mutable std::mutex env_mutex_; + std::string env_; + + std::mutex routing_state_mutex_; + routing_state_e routing_state_; private: services_t services_; mutable std::mutex services_mutex_; + mutable std::mutex guests_mutex_; + std::map<client_t, + std::pair<boost::asio::ip::address, port_t> + > guests_; + + std::mutex add_known_client_mutex_; + #ifdef VSOMEIP_ENABLE_COMPAT std::map<service_t, std::map<instance_t, diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_client.hpp index 2b5335a..fb56ec7 100644 --- a/implementation/routing/include/routing_manager_proxy.hpp +++ b/implementation/routing/include/routing_manager_client.hpp @@ -1,41 +1,53 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -#ifndef VSOMEIP_V3_ROUTING_MANAGER_PROXY_HPP -#define VSOMEIP_V3_ROUTING_MANAGER_PROXY_HPP +#ifndef VSOMEIP_V3_ROUTING_MANAGER_CLIENT_HPP +#define VSOMEIP_V3_ROUTING_MANAGER_CLIENT_HPP #include <map> #include <mutex> #include <atomic> #include <tuple> -#include <boost/asio/io_service.hpp> #include <boost/asio/steady_timer.hpp> -#include "routing_manager_base.hpp" -#include "types.hpp" #include <vsomeip/enumeration_types.hpp> #include <vsomeip/handler.hpp> +#include "routing_manager_base.hpp" +#include "types.hpp" +#include "../../protocol/include/protocol.hpp" + namespace vsomeip_v3 { class configuration; class event; +#ifdef __linux__ +class netlink_connector; +#endif class routing_manager_host; -class routing_manager_proxy: public routing_manager_base { +namespace protocol { + class offered_services_response_command; + class update_security_credentials_command; +} + +class routing_manager_client + : public routing_manager_base { public: - routing_manager_proxy(routing_manager_host *_host, bool _client_side_logging, + routing_manager_client(routing_manager_host *_host, bool _client_side_logging, const std::set<std::tuple<service_t, instance_t> > & _client_side_logging_filter); - virtual ~routing_manager_proxy(); + virtual ~routing_manager_client(); void init(); void start(); void stop(); std::shared_ptr<configuration> get_configuration() const; + std::string get_env(client_t _client) const; + std::string get_env_unlocked(client_t _client) const; bool offer_service(client_t _client, service_t _service, instance_t _instance, @@ -52,20 +64,20 @@ public: void release_service(client_t _client, service_t _service, instance_t _instance); - void subscribe(client_t _client, uid_t _uid, gid_t _gid, + void subscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, - event_t _event); + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter); - void unsubscribe(client_t _client, uid_t _uid, gid_t _gid, + void unsubscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event); bool send(client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, bool _reliable, - client_t _bound_client = VSOMEIP_ROUTING_CLIENT, - credentials_t _credentials = {ANY_UID, ANY_GID}, - uint8_t _status_check = 0, bool _sent_from_remote = false); + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _sent_from_remote, + bool _force); bool send_to(const client_t _client, const std::shared_ptr<endpoint_definition> &_target, @@ -91,9 +103,8 @@ public: void on_connect(const std::shared_ptr<endpoint>& _endpoint); void on_disconnect(const std::shared_ptr<endpoint>& _endpoint); void on_message(const byte_t *_data, length_t _size, endpoint *_receiver, - const boost::asio::ip::address &_destination, - client_t _bound_client, - credentials_t _credentials, + bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, const boost::asio::ip::address &_remote_address, std::uint16_t _remote_port); @@ -103,7 +114,7 @@ public: const std::shared_ptr<endpoint> &_endpoint); void handle_client_error(client_t _client); - void on_offered_services_info(const byte_t *_data, uint32_t _size); + void on_offered_services_info(protocol::offered_services_response_command &_command); void send_get_offered_services_info(client_t _client, offer_type_e _offer_type); @@ -112,23 +123,30 @@ private: void register_application(); void deregister_application(); - void reconnect(const std::unordered_set<client_t> &_clients); + void reconnect(const std::map<client_t, std::string> &_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_release_service(client_t _client, service_t _service, instance_t _instance); + + void send_pending_event_registrations(client_t _client); + void send_register_event(client_t _client, service_t _service, instance_t _instance, event_t _notifier, const std::set<eventgroup_t> &_eventgroups, const event_type_e _type, reliability_type_e _reliability, - bool _is_provided); - void send_subscribe(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, event_t _event); + bool _is_provided, bool _is_cyclic); + + void send_subscribe(client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter); void send_subscribe_nack(client_t _subscriber, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event, @@ -176,12 +194,13 @@ private: bool is_client_known(client_t _client); bool create_placeholder_event_and_subscribe( - service_t _service, instance_t _instance, - eventgroup_t _eventgroup, event_t _notifier, client_t _client); + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _notifier, const std::shared_ptr<debounce_filter_t> &_filter, + client_t _client); void request_debounce_timeout_cbk(boost::system::error_code const &_error); - void send_request_services(std::set<service_data_t>& _requests); + void send_request_services(const std::set<protocol::service> &_requests); void send_unsubscribe_ack(service_t _service, instance_t _instance, eventgroup_t _eventgroup, remote_subscription_id_t _id); @@ -189,14 +208,23 @@ private: void resend_provided_event_registrations(); void send_resend_provided_event_response(pending_remote_offer_id_t _id); +#ifndef VSOMEIP_DISABLE_SECURITY void send_update_security_policy_response(pending_security_update_id_t _update_id); void send_remove_security_policy_response(pending_security_update_id_t _update_id); - void on_update_security_credentials(const byte_t *_data, uint32_t _size); + void on_update_security_credentials(const protocol::update_security_credentials_command &_command); +#endif void on_client_assign_ack(const client_t &_client); + port_t get_routing_port(); + void on_suspend(); +#if defined(__linux__) || defined(ANDROID) + void on_net_state_change(bool _is_interface, const std::string &_name, bool _is_available); +#endif + private: + enum class inner_state_type_e : std::uint8_t { ST_REGISTERED = 0x0, ST_DEREGISTERED = 0x1, @@ -212,12 +240,9 @@ private: std::shared_ptr<endpoint> sender_; // --> stub std::shared_ptr<endpoint> receiver_; // --> from everybody - std::mutex known_clients_mutex_; - std::unordered_set<client_t> known_clients_; - - std::set<service_data_t> pending_offers_; - std::set<service_data_t> requests_; - std::set<service_data_t> requests_to_debounce_; + std::set<protocol::service> pending_offers_; + std::set<protocol::service> requests_; + std::set<protocol::service> requests_to_debounce_; struct event_data_t { service_t service_; @@ -226,19 +251,20 @@ private: event_type_e type_; reliability_type_e reliability_; bool is_provided_; + bool is_cyclic_; std::set<eventgroup_t> eventgroups_; bool operator<(const event_data_t &_other) const { return std::tie(service_, instance_, notifier_, - type_, reliability_, is_provided_, eventgroups_) + type_, reliability_, is_provided_, is_cyclic_, eventgroups_) < std::tie(_other.service_, _other.instance_, _other.notifier_, _other.type_, _other.reliability_, - _other.is_provided_, _other.eventgroups_); + _other.is_provided_, _other.is_cyclic_, _other.eventgroups_); } }; std::set<event_data_t> pending_event_registrations_; - std::map<client_t, std::set<subscription_data_t>> pending_incoming_subscripitons_; + std::map<client_t, std::set<subscription_data_t>> pending_incoming_subscriptions_; std::recursive_mutex incoming_subscriptions_mutex_; std::mutex state_mutex_; @@ -260,8 +286,13 @@ private: const std::set<std::tuple<service_t, instance_t> > client_side_logging_filter_; std::mutex stop_mutex_; + +#if defined(__linux__) || defined(ANDROID) + std::shared_ptr<netlink_connector> local_link_connector_; + bool is_local_link_available_; +#endif }; } // namespace vsomeip_v3 -#endif // VSOMEIP_V3_ROUTING_MANAGER_PROXY_HPP_ +#endif // VSOMEIP_V3_ROUTING_MANAGER_CLIENT_HPP_ diff --git a/implementation/routing/include/routing_manager_host.hpp b/implementation/routing/include/routing_manager_host.hpp index 69133e2..18a74af 100644 --- a/implementation/routing/include/routing_manager_host.hpp +++ b/implementation/routing/include/routing_manager_host.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -8,9 +8,15 @@ #include <memory> -#include <boost/asio/io_service.hpp> +#if VSOMEIP_BOOST_VERSION < 106600 +# include <boost/asio/io_service.hpp> +# define io_context io_service +#else +# include <boost/asio/io_context.hpp> +#endif #include <vsomeip/error.hpp> +#include <vsomeip/vsomeip_sec.h> namespace vsomeip_v3 { @@ -24,22 +30,30 @@ public: virtual client_t get_client() const = 0; virtual void set_client(const client_t &_client) = 0; - virtual session_t get_session() = 0; + virtual session_t get_session(bool _is_request) = 0; + + virtual const vsomeip_sec_client_t *get_sec_client() const = 0; + virtual const std::string & get_name() const = 0; virtual std::shared_ptr<configuration> get_configuration() const = 0; - virtual boost::asio::io_service & get_io() = 0; + virtual boost::asio::io_context &get_io() = 0; virtual void on_availability(service_t _service, instance_t _instance, - bool _is_available, major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR) = 0; + availability_state_e _state, + major_version_t _major = DEFAULT_MAJOR, + minor_version_t _minor = DEFAULT_MINOR) = 0; virtual void on_state(state_type_e _state) = 0; virtual void on_message(std::shared_ptr<message> &&_message) = 0; virtual void on_subscription(service_t _service, instance_t _instance, - eventgroup_t _eventgroup, client_t _client, uid_t _uid, gid_t _gid, bool _subscribed, - std::function<void(bool)> _accepted_cb) = 0; + eventgroup_t _eventgroup, + client_t _client, const vsomeip_sec_client_t *_sec_client, + const std::string &_env, bool _subscribed, + const std::function<void(bool)> &_accepted_cb) = 0; virtual void on_subscription_status(service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event, uint16_t _error) = 0; virtual void send(std::shared_ptr<message> _message) = 0; - virtual void on_offered_services_info(std::vector<std::pair<service_t, instance_t>> &_services) = 0; + virtual void on_offered_services_info( + std::vector<std::pair<service_t, instance_t>> &_services) = 0; virtual bool is_routing() const = 0; }; diff --git a/implementation/routing/include/routing_manager_impl.hpp b/implementation/routing/include/routing_manager_impl.hpp index 3fd6eed..3c105c2 100644 --- a/implementation/routing/include/routing_manager_impl.hpp +++ b/implementation/routing/include/routing_manager_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -14,7 +14,6 @@ #include <unordered_set> #include <boost/asio/ip/address.hpp> -#include <boost/asio/io_service.hpp> #include <boost/asio/steady_timer.hpp> #include <vsomeip/primitive_types.hpp> @@ -36,7 +35,6 @@ class deserializer; class eventgroupinfo; class routing_manager_host; class routing_manager_stub; -class servicegroup; class serializer; class service_endpoint; @@ -55,8 +53,13 @@ public: routing_manager_impl(routing_manager_host *_host); ~routing_manager_impl(); - boost::asio::io_service & get_io(); + boost::asio::io_context &get_io(); client_t get_client() const; + const vsomeip_sec_client_t *get_sec_client() const; + std::string get_client_host() const; + void set_client_host(const std::string &_client_host); + + bool is_routing_manager() const; void init(); void start(); @@ -77,21 +80,23 @@ public: void release_service(client_t _client, service_t _service, instance_t _instance); - void subscribe(client_t _client, uid_t _uid, gid_t _gid, + void subscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, service_t _service, instance_t _instance, - eventgroup_t _eventgroup, major_version_t _major, event_t _event); + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter); - void unsubscribe(client_t _client, uid_t _uid, gid_t _gid, + void unsubscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event); - bool send(client_t _client, std::shared_ptr<message> _message); + bool send(client_t _client, std::shared_ptr<message> _message, + bool _force); bool send(client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, bool _reliable, - client_t _bound_client = VSOMEIP_ROUTING_CLIENT, - credentials_t _credentials = {ANY_UID, ANY_GID}, - uint8_t _status_check = 0, bool _sent_from_remote = false); + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _sent_from_remote, + bool _force); bool send_to(const client_t _client, const std::shared_ptr<endpoint_definition> &_target, @@ -120,7 +125,7 @@ public: event_t _notifier, const std::set<eventgroup_t> &_eventgroups, event_type_e _type, reliability_type_e _reliability, - bool _is_provided); + bool _is_provided, bool _is_cyclic); void unregister_shadow_event(client_t _client, service_t _service, instance_t _instance, event_t _event, @@ -140,7 +145,7 @@ public: void on_subscribe_nack(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event, - remote_subscription_id_t _id, bool _simulated); + remote_subscription_id_t _id); // interface to stub @@ -161,7 +166,7 @@ public: major_version_t _major, minor_version_t _minor); void on_availability(service_t _service, instance_t _instance, - bool _is_available, + availability_state_e _state, major_version_t _major, minor_version_t _minor); void on_pong(client_t _client); @@ -178,13 +183,13 @@ public: void on_disconnect(const std::shared_ptr<endpoint>& _endpoint); void on_message(const byte_t *_data, length_t _size, endpoint *_receiver, - const boost::asio::ip::address &_destination, - client_t _bound_client, credentials_t _credentials, - const boost::asio::ip::address &_remote_address, - std::uint16_t _remote_port); + bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port); bool on_message(service_t _service, instance_t _instance, const byte_t *_data, length_t _size, bool _reliable, - client_t _bound_client, credentials_t _credentials, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, uint8_t _check_status = 0, bool _is_from_remote = false); void on_notification(client_t _client, service_t _service, @@ -199,8 +204,6 @@ public: bool _magic_cookies_enabled); // interface "service_discovery_host" - typedef std::map<std::string, std::shared_ptr<servicegroup> > servicegroups_t; - const servicegroups_t & get_servicegroups() const; std::shared_ptr<eventgroupinfo> find_eventgroup(service_t _service, instance_t _instance, eventgroup_t _eventgroup) const; services_t get_offered_services() const; @@ -285,15 +288,27 @@ public: void on_resend_provided_events_response(pending_remote_offer_id_t _id); client_t find_local_client(service_t _service, instance_t _instance); std::set<client_t> find_local_clients(service_t _service, instance_t _instance); - bool is_subscribe_to_any_event_allowed(credentials_t _credentials, client_t _client, + bool is_subscribe_to_any_event_allowed( + const vsomeip_sec_client_t *_sec_client, client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup); +#ifndef VSOMEIP_DISABLE_SECURITY bool update_security_policy_configuration(uint32_t _uid, uint32_t _gid, const std::shared_ptr<policy> &_policy, const std::shared_ptr<payload> &_payload, const security_update_handler_t &_handler); bool remove_security_policy_configuration(uint32_t _uid, uint32_t _gid, const security_update_handler_t &_handler); +#endif + + void add_known_client(client_t _client, const std::string &_client_host); + + void register_message_acceptance_handler( + const message_acceptance_handler_t &_handler); + + void remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port); private: bool offer_service(client_t _client, @@ -307,12 +322,12 @@ private: bool _must_queue); bool deliver_message(const byte_t *_data, length_t _size, - instance_t _instance, bool _reliable, client_t _bound_client, - credentials_t _credentials, + instance_t _instance, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, uint8_t _status_check = 0, bool _is_from_remote = false); bool deliver_notification(service_t _service, instance_t _instance, - const byte_t *_data, length_t _length, bool _reliable, client_t _bound_client, - credentials_t _credentials, + const byte_t *_data, length_t _length, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, uint8_t _status_check = 0, bool _is_from_remote = false); @@ -351,38 +366,49 @@ private: bool handle_local_offer_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major,minor_version_t _minor); - void send_subscribe(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, event_t _event); + void send_subscribe(client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter); void on_net_interface_or_route_state_changed(bool _is_interface, - std::string _if, + const std::string &_if, bool _available); void start_ip_routing(); - void requested_service_add(client_t _client, service_t _service, + void add_requested_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor); - void requested_service_remove(client_t _client, service_t _service, - instance_t _instance); - - void call_sd_endpoint_connected(const boost::system::error_code& _error, - service_t _service, instance_t _instance, - const std::shared_ptr<endpoint>& _endpoint, - std::shared_ptr<boost::asio::steady_timer> _timer); + void remove_requested_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor); + std::vector<std::pair<service_t, instance_t>> get_requested_services(client_t _client); + std::set<client_t> get_requesters(service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor); + std::set<client_t> get_requesters_unlocked(service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor); + bool has_requester_unlocked(service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor); + + void call_sd_endpoint_connected(const boost::system::error_code &_error, + service_t _service, instance_t _instance, + const std::shared_ptr<endpoint> &_endpoint, + std::shared_ptr<boost::asio::steady_timer> _timer); - bool create_placeholder_event_and_subscribe(service_t _service, - instance_t _instance, - eventgroup_t _eventgroup, - event_t _event, - client_t _client); + bool create_placeholder_event_and_subscribe( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter, + client_t _client); void handle_subscription_state(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event); - void memory_log_timer_cbk(boost::system::error_code const & _error); - void status_log_timer_cbk(boost::system::error_code const & _error); + void memory_log_timer_cbk(boost::system::error_code const &_error); + void status_log_timer_cbk(boost::system::error_code const &_error); void send_subscription(const client_t _offering_client, const service_t _service, const instance_t _instance, @@ -416,25 +442,48 @@ private: bool is_last_stop_callback(const uint32_t _callback_id); + std::string get_env(client_t _client) const; + std::string get_env_unlocked(client_t _client) const; + bool insert_event_statistics(service_t _service, instance_t _instance, method_t _method, length_t _length); void statistics_log_timer_cbk(boost::system::error_code const & _error); + bool get_guest(client_t _client, boost::asio::ip::address &_address, + port_t &_port) const; + void add_guest(client_t _client, const boost::asio::ip::address &_address, + port_t _port); + void remove_guest(client_t _client); + void send_suspend() const; + void clear_local_services(); + + bool is_acl_message_allowed(endpoint *_receiver, + service_t _service, instance_t _instance, + const boost::asio::ip::address &_remote_address) const; + private: std::shared_ptr<routing_manager_stub> stub_; std::shared_ptr<sd::service_discovery> discovery_; std::mutex requested_services_mutex_; - std::map<client_t, - std::map<service_t, - std::map<instance_t, - std::set<std::pair<major_version_t, minor_version_t>>>>> requested_services_; + std::map<service_t, + std::map<instance_t, + std::map<major_version_t, + std::map<minor_version_t, std::set<client_t> > + > + > + > requested_services_; std::mutex remote_subscribers_mutex_; - std::map<service_t, std::map<instance_t, std::map<client_t, - std::set<std::shared_ptr<endpoint_definition>>>>> remote_subscribers_; + std::map<service_t, + std::map<instance_t, + std::map<client_t, + std::set<std::shared_ptr<endpoint_definition> > + > + > + > remote_subscribers_; std::shared_ptr<serviceinfo> sd_info_; @@ -446,7 +495,7 @@ private: bool routing_running_; std::mutex pending_sd_offers_mutex_; std::vector<std::pair<service_t, instance_t>> pending_sd_offers_; -#ifndef _WIN32 +#if defined(__linux__) || defined(ANDROID) std::shared_ptr<netlink_connector> netlink_connector_; #endif @@ -503,6 +552,8 @@ private: // synchronize update_remote_subscription() and send_(un)subscription() std::mutex update_remote_subscription_mutex_; + + message_acceptance_handler_t message_acceptance_handler_; }; } // namespace vsomeip_v3 diff --git a/implementation/routing/include/routing_manager_stub.hpp b/implementation/routing/include/routing_manager_stub.hpp index aa5796e..4209eec 100644 --- a/implementation/routing/include/routing_manager_stub.hpp +++ b/implementation/routing/include/routing_manager_stub.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -16,22 +16,34 @@ #include <atomic> #include <unordered_set> -#include <boost/asio/io_service.hpp> +#if VSOMEIP_BOOST_VERSION < 106600 +# include <boost/asio/io_service.hpp> +# define io_context io_service +#else +# include <boost/asio/io_context.hpp> +#endif #include <boost/asio/steady_timer.hpp> #include <vsomeip/handler.hpp> - -#include "../../endpoints/include/endpoint_host.hpp" -#include "../include/routing_host.hpp" +#include <vsomeip/vsomeip_sec.h> #include "types.hpp" +#include "../include/routing_host.hpp" +#include "../../endpoints/include/endpoint_host.hpp" +#include "../../protocol/include/protocol.hpp" +#include "../../protocol/include/routing_info_entry.hpp" namespace vsomeip_v3 { class configuration; -struct policy; +#if defined(__linux__) || defined(ANDROID) +class netlink_connector; +#endif // __linux__ || ANDROID class routing_manager_stub_host; +struct debounce_filter_t; +struct policy; + class routing_manager_stub: public routing_host, public std::enable_shared_from_this<routing_manager_stub> { public: @@ -44,10 +56,9 @@ public: void start(); void stop(); - void on_message(const byte_t *_data, length_t _size, endpoint *_receiver, - const boost::asio::ip::address &_destination, - client_t _bound_client, - credentials_t _credentials, + void on_message(const byte_t *_data, length_t _size, + endpoint *_receiver, bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, const boost::asio::ip::address &_remote_address, std::uint16_t _remote_port); @@ -56,9 +67,11 @@ public: void on_stop_offer_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor); - bool send_subscribe(const std::shared_ptr<endpoint>& _target, - client_t _client, service_t _service, instance_t _instance, - eventgroup_t _eventgroup, major_version_t _major, event_t _event, + bool send_subscribe( + const std::shared_ptr<endpoint> &_target, client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter, remote_subscription_id_t _id); bool send_unsubscribe(const std::shared_ptr<endpoint>& _target, @@ -85,16 +98,18 @@ public: bool send_ping(client_t _client); bool is_registered(client_t _client) const; client_t get_client() const; - void handle_credentials(const client_t _client, std::set<service_data_t>& _requests); - void handle_requests(const client_t _client, std::set<service_data_t>& _requests); + void handle_credentials(const client_t _client, std::set<protocol::service> &_requests); + void handle_requests(const client_t _client, std::set<protocol::service> &_requests); - void update_registration(client_t _client, registration_type_e _type); + void update_registration(client_t _client, registration_type_e _type, + const boost::asio::ip::address &_address, port_t _port); void print_endpoint_status() const; bool send_provided_event_resend_request(client_t _client, pending_remote_offer_id_t _id); +#ifndef VSOMEIP_DISABLE_SECURITY bool update_security_policy_configuration(uint32_t _uid, uint32_t _gid, const std::shared_ptr<policy> &_policy, const std::shared_ptr<payload> &_payload, @@ -119,23 +134,29 @@ public: bool add_requester_policies(uid_t _uid, gid_t _gid, const std::set<std::shared_ptr<policy> > &_policies); void remove_requester_policies(uid_t _uid, gid_t _gid); +#endif // !VSOMEIP_DISABLE_SECURITY + + void add_known_client(client_t _client, const std::string &_client_host); void send_suspend() const; + void remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port); + private: void broadcast(const std::vector<byte_t> &_command) const; void on_register_application(client_t _client); void on_deregister_application(client_t _client); + void on_offered_service_request(client_t _client, offer_type_e _offer_type); + void distribute_credentials(client_t _hoster, service_t _service, instance_t _instance); - void inform_provider(client_t _hoster, service_t _service, - instance_t _instance, major_version_t _major, minor_version_t _minor, - routing_info_entry_e _entry); 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, + minor_version_t _minor, protocol::routing_info_entry_type_e _entry, bool _inform_service); void broadcast_ping() const; @@ -151,27 +172,35 @@ private: (void)_routing_state; }; - 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 create_offered_services_info(const client_t _target); - void insert_offered_services_info(client_t _target, - routing_info_entry_e _entry, - service_t _service, - instance_t _instance, - major_version_t _major, - minor_version_t _minor); - void send_offered_services_info(const client_t _target); - - void create_client_credentials_info(const client_t _target); - void insert_client_credentials_info(client_t _target, std::set<std::pair<uint32_t, uint32_t>> _credentials); - void send_client_credentials_info(const client_t _target); + inline bool is_connected(client_t _source, client_t _sink) const { + + auto find_source = connection_matrix_.find(_source); + if (find_source != connection_matrix_.end()) + return (find_source->second.find(_sink) + != find_source->second.end()); + + return (false); + } + inline void add_connection(client_t _source, client_t _sink) { + + connection_matrix_[_source].insert(_sink); + } + inline void remove_connection(client_t _source, client_t _sink) { + + auto find_source = connection_matrix_.find(_source); + if (find_source != connection_matrix_.end()) + find_source->second.erase(_sink); + } + inline void remove_source(client_t _source) { + + connection_matrix_.erase(_source); + } + + void send_client_routing_info(const client_t _target, + protocol::routing_info_entry &_entry); + void send_client_routing_info(const client_t _target, + std::vector<protocol::routing_info_entry> &&_entries); + void send_client_credentials(client_t _target, std::set<std::pair<uint32_t, uint32_t>> &_credentials); void on_client_id_timer_expired(boost::system::error_code const &_error); @@ -199,13 +228,17 @@ private: void add_pending_security_update_handler( pending_security_update_id_t _id, - security_update_handler_t _handler); + const security_update_handler_t &_handler); void add_pending_security_update_timer( pending_security_update_id_t _id); +#if defined(__linux__) || defined(ANDROID) + void on_net_state_change(bool _is_interface, const std::string &_name, bool _is_available); +#endif + private: routing_manager_stub_host *host_; - boost::asio::io_service &io_; + boost::asio::io_context &io_; std::mutex watchdog_timer_mutex_; boost::asio::steady_timer watchdog_timer_; @@ -213,7 +246,8 @@ private: std::set<client_t> used_client_ids_; std::mutex used_client_ids_mutex_; - std::shared_ptr<endpoint> endpoint_; + std::shared_ptr<endpoint> root_; // Routing manager endpoint + std::shared_ptr<endpoint> local_receiver_; std::mutex local_receiver_mutex_; @@ -229,8 +263,8 @@ private: std::condition_variable client_registration_condition_; std::map<client_t, std::vector<registration_type_e>> pending_client_registrations_; + std::map<client_t, std::pair<boost::asio::ip::address, port_t> > internal_client_ports_; const std::uint32_t max_local_message_size_; - static const std::vector<byte_t> its_ping_; const std::chrono::milliseconds configured_watchdog_timeout_; boost::asio::steady_timer pinged_clients_timer_; std::mutex pinged_clients_mutex_; @@ -239,10 +273,6 @@ private: std::map<client_t, std::map<service_t, std::map<instance_t, std::pair<major_version_t, minor_version_t> > > > service_requests_; std::map<client_t, std::set<client_t>> connection_matrix_; - std::map<client_t, std::vector<byte_t>> client_routing_info_; - std::map<client_t, std::vector<byte_t>> offered_services_info_; - std::map<client_t, std::vector<byte_t>> client_credentials_info_; - std::mutex pending_security_updates_mutex_; pending_security_update_id_t pending_security_update_id_; std::map<pending_security_update_id_t, std::unordered_set<client_t>> pending_security_updates_; @@ -262,6 +292,14 @@ private: std::set<std::shared_ptr<policy> > > > requester_policies_; + + +#if defined(__linux__) || defined(ANDROID) + // netlink connector for internal network + // (replacement for Unix Domain Sockets if configured) + std::shared_ptr<netlink_connector> local_link_connector_; + bool is_local_link_available_; +#endif }; } // namespace vsomeip_v3 diff --git a/implementation/routing/include/routing_manager_stub_host.hpp b/implementation/routing/include/routing_manager_stub_host.hpp index 6ad0ab1..c55dd86 100644 --- a/implementation/routing/include/routing_manager_stub_host.hpp +++ b/implementation/routing/include/routing_manager_stub_host.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -6,9 +6,16 @@ #ifndef VSOMEIP_V3_ROUTING_MANAGER_STUB_HOST_ #define VSOMEIP_V3_ROUTING_MANAGER_STUB_HOST_ -#include <boost/asio/io_service.hpp> +#if VSOMEIP_BOOST_VERSION < 106600 +# include <boost/asio/io_service.hpp> +# define io_context io_service +#else +# include <boost/asio/io_context.hpp> +#endif #include <vsomeip/handler.hpp> +#include <vsomeip/vsomeip_sec.h> + #include "types.hpp" namespace vsomeip_v3 { @@ -28,57 +35,59 @@ public: instance_t _instance, major_version_t _major, minor_version_t _minor, bool _must_queue = true) = 0; - virtual void request_service(client_t _client, - service_t _service, instance_t _instance, - major_version_t _major, minor_version_t _minor) = 0; + virtual void request_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor) = 0; - virtual void release_service(client_t _client, - service_t _service, instance_t _instance) = 0; + virtual void release_service(client_t _client, service_t _service, + instance_t _instance) = 0; - virtual void register_shadow_event(client_t _client, - service_t _service, instance_t _instance, - event_t _notifier, - const std::set<eventgroup_t> &_eventgroups, - event_type_e _type, reliability_type_e _reliability, - bool _is_provided) = 0; + virtual void register_shadow_event(client_t _client, service_t _service, + instance_t _instance, event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, event_type_e _type, + reliability_type_e _reliability, bool _is_provided, + bool _is_cyclic) = 0; virtual void unregister_shadow_event(client_t _client, service_t _service, instance_t _instance, event_t _event, bool _is_provided) = 0; - virtual void subscribe(client_t _client, uid_t _uid, gid_t _gid, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, event_t _event) = 0; + virtual void subscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + major_version_t _major, event_t _event, + const std::shared_ptr<debounce_filter_t> &_filter) = 0; virtual void on_subscribe_nack(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, event_t _event, - remote_subscription_id_t _subscription_id, bool _simulated) = 0; + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + remote_subscription_id_t _subscription_id) = 0; virtual void on_subscribe_ack(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, event_t _event, - remote_subscription_id_t _subscription_id) = 0; + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + remote_subscription_id_t _subscription_id) = 0; - virtual void unsubscribe(client_t _client, uid_t _uid, gid_t _gid, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, event_t _event) = 0; + virtual void unsubscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event) = 0; virtual void on_unsubscribe_ack(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, remote_subscription_id_t _unsubscription_id) = 0; virtual bool on_message(service_t _service, instance_t _instance, - const byte_t *_data, length_t _size, bool _reliable, client_t _bound_client, - credentials_t _credentials, + const byte_t *_data, length_t _size, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, uint8_t _status_check = 0, bool _is_from_remote = false) = 0; - virtual void on_notification(client_t _client, - service_t _service, instance_t _instance, - const byte_t *_data, length_t _size, bool _notify_one = false) = 0; + virtual void on_notification(client_t _client, service_t _service, + instance_t _instance, const byte_t *_data, length_t _size, + bool _notify_one = false) = 0; virtual void on_stop_offer_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) = 0; virtual void on_availability(service_t _service, instance_t _instance, - bool _is_available, major_version_t _major, minor_version_t _minor) = 0; + availability_state_e _state, major_version_t _major, + minor_version_t _minor) = 0; virtual std::shared_ptr<endpoint> find_local(client_t _client) = 0; @@ -86,8 +95,9 @@ public: client_t _client) = 0; virtual void remove_local(client_t _client, bool _remove_local) = 0; - virtual boost::asio::io_service & get_io() = 0; + virtual boost::asio::io_context& get_io() = 0; virtual client_t get_client() const = 0; + virtual const vsomeip_sec_client_t *get_sec_client() const = 0; virtual void on_pong(client_t _client) = 0; @@ -95,14 +105,32 @@ public: virtual std::shared_ptr<endpoint_manager_impl> get_endpoint_manager() const = 0; - virtual void on_resend_provided_events_response(pending_remote_offer_id_t _id) = 0; + virtual void on_resend_provided_events_response( + pending_remote_offer_id_t _id) = 0; + + virtual client_t find_local_client(service_t _service, + instance_t _instance) = 0; + + virtual std::set<client_t> find_local_clients(service_t _service, + instance_t _instance) = 0; + + virtual bool is_subscribe_to_any_event_allowed( + const vsomeip_sec_client_t *_sec_client, + client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup) = 0; + + virtual void add_known_client(client_t _client, + const std::string &_client_host) = 0; - virtual client_t find_local_client(service_t _service, instance_t _instance) = 0; + virtual void set_client_host(const std::string &_client_host) = 0; - virtual std::set<client_t> find_local_clients(service_t _service, instance_t _instance) = 0; + virtual bool get_guest(client_t _client, + boost::asio::ip::address &_address, port_t &_port) const = 0; + virtual void add_guest(client_t _client, + const boost::asio::ip::address &_address, port_t _port) = 0; + virtual void remove_guest(client_t _client) = 0; - virtual bool is_subscribe_to_any_event_allowed(credentials_t _credentials, client_t _client, - service_t _service, instance_t _instance, eventgroup_t _eventgroup) = 0; + virtual void clear_local_services() = 0; }; } // namespace vsomeip_v3 diff --git a/implementation/routing/include/serviceinfo.hpp b/implementation/routing/include/serviceinfo.hpp index a405cf0..5ea4c18 100644 --- a/implementation/routing/include/serviceinfo.hpp +++ b/implementation/routing/include/serviceinfo.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -18,7 +18,6 @@ namespace vsomeip_v3 { class endpoint; -class servicegroup; class serviceinfo { public: @@ -28,9 +27,6 @@ public: VSOMEIP_EXPORT serviceinfo(const serviceinfo& _other); VSOMEIP_EXPORT ~serviceinfo(); - VSOMEIP_EXPORT servicegroup * get_group() const; - VSOMEIP_EXPORT void set_group(servicegroup *_group); - VSOMEIP_EXPORT service_t get_service() const; VSOMEIP_EXPORT instance_t get_instance() const; @@ -57,8 +53,6 @@ public: VSOMEIP_EXPORT void set_is_in_mainphase(bool _in_mainphase); private: - servicegroup *group_; - service_t service_; instance_t instance_; diff --git a/implementation/routing/include/types.hpp b/implementation/routing/include/types.hpp index c301b33..d59015c 100644 --- a/implementation/routing/include/types.hpp +++ b/implementation/routing/include/types.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -18,18 +18,13 @@ namespace vsomeip_v3 { class serviceinfo; class endpoint_definition; - -typedef std::map<service_t, - std::map<instance_t, - std::shared_ptr<serviceinfo> > > services_t; +using services_t = std::map<service_t, std::map<instance_t, std::shared_ptr<serviceinfo>>>; class eventgroupinfo; -typedef std::map<service_t, - std::map<instance_t, - std::map<eventgroup_t, - std::shared_ptr< - eventgroupinfo> > > > eventgroups_t; +using eventgroups_t = + std::map<service_t, + std::map<instance_t, std::map<eventgroup_t, std::shared_ptr<eventgroupinfo>>>>; enum class registration_type_e : std::uint8_t { REGISTER = 0x1, @@ -47,8 +42,7 @@ enum class remote_subscription_state_e : std::uint8_t { SUBSCRIPTION_UNKNOWN = 0xFF }; -typedef std::uint16_t remote_subscription_id_t; -typedef std::uint32_t pending_remote_offer_id_t; +using remote_subscription_id_t = std::uint16_t; struct msg_statistic_t { uint32_t counter_; diff --git a/implementation/routing/src/event.cpp b/implementation/routing/src/event.cpp index b63022c..e4eed17 100644 --- a/implementation/routing/src/event.cpp +++ b/implementation/routing/src/event.cpp @@ -1,10 +1,12 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include <chrono> #include <iomanip> #include <sstream> +#include <thread> #include <vsomeip/constants.hpp> #include <vsomeip/defines.hpp> @@ -21,72 +23,104 @@ namespace vsomeip_v3 { -event::event(routing_manager *_routing, bool _is_shadow) : - routing_(_routing), - message_(runtime::get()->create_notification()), - type_(event_type_e::ET_EVENT), - cycle_timer_(_routing->get_io()), - cycle_(std::chrono::milliseconds::zero()), - change_resets_cycle_(false), - is_updating_on_change_(true), - is_set_(false), - is_provided_(false), - is_shadow_(_is_shadow), - is_cache_placeholder_(false), - epsilon_change_func_(std::bind(&event::compare, this, +event::event(routing_manager *_routing, bool _is_shadow) + : routing_(_routing), + current_(runtime::get()->create_notification()), + update_(runtime::get()->create_notification()), + type_(event_type_e::ET_EVENT), + cycle_timer_(_routing->get_io()), + cycle_(std::chrono::milliseconds::zero()), + change_resets_cycle_(false), + is_updating_on_change_(true), + is_set_(false), + is_provided_(false), + is_shadow_(_is_shadow), + is_cache_placeholder_(false), + epsilon_change_func_(std::bind(&event::has_changed, this, std::placeholders::_1, std::placeholders::_2)), - reliability_(reliability_type_e::RT_UNKNOWN) { + reliability_(reliability_type_e::RT_UNKNOWN) { + } -service_t event::get_service() const { - return (message_->get_service()); +service_t +event::get_service() const { + + return (current_->get_service()); } -void event::set_service(service_t _service) { - message_->set_service(_service); +void +event::set_service(service_t _service) { + + current_->set_service(_service); + update_->set_service(_service); } -instance_t event::get_instance() const { - return (message_->get_instance()); +instance_t +event::get_instance() const { + + return (current_->get_instance()); } -void event::set_instance(instance_t _instance) { - message_->set_instance(_instance); +void +event::set_instance(instance_t _instance) { + + current_->set_instance(_instance); + update_->set_instance(_instance); } -major_version_t event::get_version() const { - return message_->get_interface_version(); +major_version_t +event::get_version() const { + + return current_->get_interface_version(); } -void event::set_version(major_version_t _major) { - message_->set_interface_version(_major); +void +event::set_version(major_version_t _major) { + + current_->set_interface_version(_major); + update_->set_interface_version(_major); } -event_t event::get_event() const { - return (message_->get_method()); +event_t +event::get_event() const { + + return (current_->get_method()); } -void event::set_event(event_t _event) { - message_->set_method(_event); +void +event::set_event(event_t _event) { + + current_->set_method(_event); + update_->set_method(_event); } -event_type_e event::get_type() const { +event_type_e +event::get_type() const { + return (type_); } -void event::set_type(const event_type_e _type) { +void +event::set_type(const event_type_e _type) { + type_ = _type; } -bool event::is_field() const { +bool +event::is_field() const { + return (type_ == event_type_e::ET_FIELD); } -bool event::is_provided() const { +bool +event::is_provided() const { + return (is_provided_); } -void event::set_provided(bool _is_provided) { +void +event::set_provided(bool _is_provided) { + is_provided_ = _is_provided; } @@ -94,122 +128,138 @@ bool event::is_set() const { return is_set_; } -const std::shared_ptr<payload> event::get_payload() const { +std::shared_ptr<payload> +event::get_payload() const { + std::lock_guard<std::mutex> its_lock(mutex_); - return (message_->get_payload()); + return (current_->get_payload()); } -bool event::set_payload_dont_notify(const std::shared_ptr<payload> &_payload) { +void +event::update_payload() { + std::lock_guard<std::mutex> its_lock(mutex_); - if (is_cache_placeholder_) { - reset_payload(_payload); - is_set_ = true; - } else { - if (set_payload_helper(_payload, false)) { - reset_payload(_payload); - } else { - return false; - } - } - return true; + update_payload_unlocked(); +} + +void +event::update_payload_unlocked() { + + current_->set_payload(update_->get_payload()); } -void event::set_payload(const std::shared_ptr<payload> &_payload, bool _force) { +void +event::set_payload(const std::shared_ptr<payload> &_payload, bool _force) { + std::lock_guard<std::mutex> its_lock(mutex_); - if (is_provided_) { - if (set_payload_helper(_payload, _force)) { - reset_payload(_payload); - if (is_updating_on_change_) { - if (change_resets_cycle_) - stop_cycle(); + if (is_provided_ && prepare_update_payload_unlocked(_payload, _force)) { + if (is_updating_on_change_) { + if (change_resets_cycle_) + stop_cycle(); - notify(); + notify(_force); - if (change_resets_cycle_) - start_cycle(); - } + if (change_resets_cycle_) + start_cycle(); + + update_payload_unlocked(); } } else { - VSOMEIP_INFO << "Can't set payload for event " + VSOMEIP_INFO << "Cannot set payload for event [" << std::hex << std::setw(4) << std::setfill('0') - << get_service() << "." << get_instance() << "." << get_event() - << " as it isn't provided"; + << current_->get_service() << "." + << current_->get_instance() << "." + << current_->get_method() + << "]. It isn't provided"; } } -void event::set_payload(const std::shared_ptr<payload> &_payload, client_t _client, +void +event::set_payload(const std::shared_ptr<payload> &_payload, client_t _client, bool _force) { + std::lock_guard<std::mutex> its_lock(mutex_); - if (is_provided_) { - if (set_payload_helper(_payload, _force)) { - reset_payload(_payload); - if (is_updating_on_change_) { - notify_one_unlocked(_client); - } + if (is_provided_ && prepare_update_payload_unlocked(_payload, _force)) { + if (is_updating_on_change_) { + notify_one_unlocked(_client, _force); + update_payload_unlocked(); } } else { - VSOMEIP_INFO << "Can't set payload for event " + VSOMEIP_INFO << "Cannot set payload for event [" << std::hex << std::setw(4) << std::setfill('0') - << get_service() << "." << get_instance() << "." << get_event() - << ". It isn't provided"; + << current_->get_service() << "." + << current_->get_instance() << "." + << current_->get_method() + << "]. It isn't provided"; } } -void event::set_payload(const std::shared_ptr<payload> &_payload, +void +event::set_payload(const std::shared_ptr<payload> &_payload, const client_t _client, - const std::shared_ptr<endpoint_definition>& _target, - bool _force) { + const std::shared_ptr<endpoint_definition> &_target) { + std::lock_guard<std::mutex> its_lock(mutex_); - if (is_provided_) { - if (set_payload_helper(_payload, _force)) { - reset_payload(_payload); - if (is_updating_on_change_) { - notify_one_unlocked(_client, _target); - } + if (is_provided_ && prepare_update_payload_unlocked(_payload, false)) { + if (is_updating_on_change_) { + notify_one_unlocked(_client, _target); + update_payload_unlocked(); } } else { - VSOMEIP_INFO << "Can't set payload for event " + VSOMEIP_INFO << "Cannot set payload for event [" << std::hex << std::setw(4) << std::setfill('0') - << get_service() << "." << get_instance() << "." << get_event() - << ". It isn't provided"; + << current_->get_service() << "." + << current_->get_instance() << "." + << current_->get_method() + << "]. It isn't provided"; } } -bool event::set_payload_notify_pending(const std::shared_ptr<payload> &_payload) { +bool +event::set_payload_notify_pending(const std::shared_ptr<payload> &_payload) { + std::lock_guard<std::mutex> its_lock(mutex_); - if (!is_set_ && is_provided_) { - reset_payload(_payload); + if (is_provided_ && !is_set_) { + + update_->set_payload(_payload); + is_set_ = true; // Send pending initial events. for (const auto &its_target : pending_) { - message_->set_session(routing_->get_session()); + set_session(); routing_->send_to(VSOMEIP_ROUTING_CLIENT, - its_target, message_); + its_target, update_); } pending_.clear(); - return true; + update_payload_unlocked(); + + return (true); } - return false; + return (false); } -void event::unset_payload(bool _force) { +void +event::unset_payload(bool _force) { + std::lock_guard<std::mutex> its_lock(mutex_); if (_force) { is_set_ = false; stop_cycle(); - message_->set_payload(std::make_shared<payload_impl>()); + current_->set_payload(std::make_shared<payload_impl>()); } else { if (is_provided_) { is_set_ = false; stop_cycle(); - message_->set_payload(std::make_shared<payload_impl>()); + current_->set_payload(std::make_shared<payload_impl>()); } } } -void event::set_update_cycle(std::chrono::milliseconds &_cycle) { +void +event::set_update_cycle(std::chrono::milliseconds &_cycle) { + if (is_provided_) { std::lock_guard<std::mutex> its_lock(mutex_); stop_cycle(); @@ -218,24 +268,33 @@ void event::set_update_cycle(std::chrono::milliseconds &_cycle) { } } -void event::set_change_resets_cycle(bool _change_resets_cycle) { +void +event::set_change_resets_cycle(bool _change_resets_cycle) { + change_resets_cycle_ = _change_resets_cycle; } -void event::set_update_on_change(bool _is_active) { +void +event::set_update_on_change(bool _is_active) { + if (is_provided_) { is_updating_on_change_ = _is_active; } } -void event::set_epsilon_change_function(const epsilon_change_func_t &_epsilon_change_func) { +void +event::set_epsilon_change_function( + const epsilon_change_func_t &_epsilon_change_func) { + + std::lock_guard<std::mutex> its_lock(mutex_); if (_epsilon_change_func) { - std::lock_guard<std::mutex> its_lock(mutex_); epsilon_change_func_ = _epsilon_change_func; } } -const std::set<eventgroup_t> event::get_eventgroups() const { +std::set<eventgroup_t> +event::get_eventgroups() const { + std::set<eventgroup_t> its_eventgroups; { std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); @@ -246,7 +305,9 @@ const std::set<eventgroup_t> event::get_eventgroups() const { return its_eventgroups; } -std::set<eventgroup_t> event::get_eventgroups(client_t _client) const { +std::set<eventgroup_t> +event::get_eventgroups(client_t _client) const { + std::set<eventgroup_t> its_eventgroups; std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); @@ -257,23 +318,29 @@ std::set<eventgroup_t> event::get_eventgroups(client_t _client) const { return its_eventgroups; } -void event::add_eventgroup(eventgroup_t _eventgroup) { +void +event::add_eventgroup(eventgroup_t _eventgroup) { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); if (eventgroups_.find(_eventgroup) == eventgroups_.end()) eventgroups_[_eventgroup] = std::set<client_t>(); } -void event::set_eventgroups(const std::set<eventgroup_t> &_eventgroups) { +void +event::set_eventgroups(const std::set<eventgroup_t> &_eventgroups) { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); for (auto e : _eventgroups) eventgroups_[e] = std::set<client_t>(); } -void event::update_cbk(boost::system::error_code const &_error) { +void +event::update_cbk(boost::system::error_code const &_error) { + if (!_error) { std::lock_guard<std::mutex> its_lock(mutex_); cycle_timer_.expires_from_now(cycle_); - notify(); + notify(true); auto its_handler = std::bind(&event::update_cbk, shared_from_this(), std::placeholders::_1); @@ -281,10 +348,12 @@ void event::update_cbk(boost::system::error_code const &_error) { } } -void event::notify() { +void +event::notify(bool _force) { + if (is_set_) { - message_->set_session(routing_->get_session()); - routing_->send(VSOMEIP_ROUTING_CLIENT, message_); + set_session(); + routing_->send(VSOMEIP_ROUTING_CLIENT, update_, _force); } else { VSOMEIP_INFO << __func__ << ": Notifying " @@ -294,8 +363,10 @@ void event::notify() { } } -void event::notify_one(client_t _client, +void +event::notify_one(client_t _client, const std::shared_ptr<endpoint_definition> &_target) { + if (_target) { std::lock_guard<std::mutex> its_lock(mutex_); notify_one_unlocked(_client, _target); @@ -308,12 +379,14 @@ void event::notify_one(client_t _client, } } -void event::notify_one_unlocked(client_t _client, +void +event::notify_one_unlocked(client_t _client, const std::shared_ptr<endpoint_definition> &_target) { + if (_target) { if (is_set_) { - message_->set_session(routing_->get_session()); - routing_->send_to(_client, _target, message_); + set_session(); + routing_->send_to(_client, _target, update_); } else { VSOMEIP_INFO << __func__ << ": Notifying " @@ -331,15 +404,23 @@ void event::notify_one_unlocked(client_t _client, } } -void event::notify_one(client_t _client) { +void +event::notify_one(client_t _client, bool _force) { + std::lock_guard<std::mutex> its_lock(mutex_); - notify_one_unlocked(_client); + notify_one_unlocked(_client, _force); } -void event::notify_one_unlocked(client_t _client) { +void +event::notify_one_unlocked(client_t _client, bool _force) { + if (is_set_) { - message_->set_session(routing_->get_session()); - routing_->send(_client, message_); + set_session(); + { + std::lock_guard<std::mutex> its_last_forwarded_guard(last_forwarded_mutex_); + last_forwarded_[_client] = std::chrono::steady_clock::now(); + } + routing_->send(_client, update_, _force); } else { VSOMEIP_INFO << __func__ << ": Notifying " @@ -350,28 +431,46 @@ void event::notify_one_unlocked(client_t _client) { } } -bool event::set_payload_helper(const std::shared_ptr<payload> &_payload, bool _force) { - std::shared_ptr<payload> its_payload = message_->get_payload(); - bool is_change(type_ != event_type_e::ET_FIELD); - if (!is_change) { - is_change = _force || epsilon_change_func_(its_payload, _payload); - } - return is_change; +bool +event::prepare_update_payload(const std::shared_ptr<payload> &_payload, + bool _force) { + + std::lock_guard<std::mutex> its_lock(mutex_); + return (prepare_update_payload_unlocked(_payload, _force)); } -void event::reset_payload(const std::shared_ptr<payload> &_payload) { - std::shared_ptr<payload> its_new_payload +bool +event::prepare_update_payload_unlocked( + const std::shared_ptr<payload> &_payload, bool _force) { + + // Copy payload to avoid manipulation from the outside + std::shared_ptr<payload> its_payload = runtime::get()->create_payload( - _payload->get_data(), _payload->get_length()); - message_->set_payload(its_new_payload); + _payload->get_data(), _payload->get_length()); + + bool is_change = has_changed(current_->get_payload(), its_payload); + if (!_force + && type_ == event_type_e::ET_FIELD + && cycle_ == std::chrono::milliseconds::zero() + && !is_change) { + + return (false); + } + + if (is_change) + update_->set_payload(its_payload); if (!is_set_) start_cycle(); is_set_ = true; + + return (true); } -void event::add_ref(client_t _client, bool _is_provided) { +void +event::add_ref(client_t _client, bool _is_provided) { + std::lock_guard<std::mutex> its_lock(refs_mutex_); auto its_client = refs_.find(_client); if (its_client == refs_.end()) { @@ -386,7 +485,9 @@ void event::add_ref(client_t _client, bool _is_provided) { } } -void event::remove_ref(client_t _client, bool _is_provided) { +void +event::remove_ref(client_t _client, bool _is_provided) { + std::lock_guard<std::mutex> its_lock(refs_mutex_); auto its_client = refs_.find(_client); if (its_client != refs_.end()) { @@ -403,24 +504,126 @@ void event::remove_ref(client_t _client, bool _is_provided) { } } -bool event::has_ref() { +bool +event::has_ref() { + std::lock_guard<std::mutex> its_lock(refs_mutex_); return refs_.size() != 0; } -bool event::add_subscriber(eventgroup_t _eventgroup, client_t _client, bool _force) { +bool +event::add_subscriber(eventgroup_t _eventgroup, + const std::shared_ptr<debounce_filter_t> &_filter, + client_t _client, bool _force) { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); bool ret = false; if (_force // remote events managed by rm_impl || is_provided_ // events provided by rm_proxies || is_shadow_ // local events managed by rm_impl || is_cache_placeholder_) { + + if (_filter) { + VSOMEIP_WARNING << "Using client [" + << std::hex << std::setw(4) << std::setfill('0') + << _client + << "] specific filter configuration for SOME/IP event " + << get_service() << "." << get_instance() << "." << get_event() << "."; + std::stringstream its_filter_parameters; + its_filter_parameters << "(on_change=" + << std::boolalpha << _filter->on_change_ + << ", interval=" << std::dec << _filter->interval_ + << ", on_change_resets_interval=" + << std::boolalpha << _filter->on_change_resets_interval_ + << ", ignore=[ "; + for (auto i : _filter->ignore_) + its_filter_parameters << "(" << std::dec << i.first << ", " + << std::hex << std::setw(2) << std::setfill('0') + << (int)i.second << ") "; + its_filter_parameters << "])"; + VSOMEIP_INFO << "Filter parameters: " + << its_filter_parameters.str(); + + filters_[_client] = [_filter, _client, this]( + const std::shared_ptr<payload> &_old, + const std::shared_ptr<payload> &_new) { + + bool is_changed(false), is_elapsed(false); + + // Check whether we should forward because of changed data + if (_filter->on_change_) { + length_t its_min_length, its_max_length; + + if (_old->get_length() < _new->get_length()) { + its_min_length = _old->get_length(); + its_max_length = _new->get_length(); + } else { + its_min_length = _new->get_length(); + its_max_length = _old->get_length(); + } + + // Check whether all additional bytes (if any) are excluded + for (length_t i = its_min_length; i < its_max_length; i++) { + auto j = _filter->ignore_.find(i); + // A change is detected when an additional byte is not + // excluded at all or if its exclusion does not cover all + // bits + if (j == _filter->ignore_.end() || j->second != 0xFF) { + is_changed = true; + break; + } + } + + if (!is_changed) { + const byte_t *its_old = _old->get_data(); + const byte_t *its_new = _new->get_data(); + for (length_t i = 0; i < its_min_length; i++) { + auto j = _filter->ignore_.find(i); + if (j == _filter->ignore_.end()) { + if (its_old[i] != its_new[i]) { + is_changed = true; + break; + } + } else if (j->second != 0xFF) { + if ((its_old[i] & ~(j->second)) != (its_new[i] & ~(j->second))) { + is_changed = true; + break; + } + } + } + } + } + + if (_filter->interval_ > -1) { + // Check whether we should forward because of the elapsed time since + // we did last time + std::chrono::steady_clock::time_point its_current + = std::chrono::steady_clock::now(); + + std::lock_guard<std::mutex> its_last_forwarded_guard(last_forwarded_mutex_); + is_elapsed = (last_forwarded_.find(_client) == last_forwarded_.end()); + if (!is_elapsed) { + std::int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( + its_current - last_forwarded_[_client]).count(); + is_elapsed = (elapsed >= _filter->interval_); + } + + if (is_elapsed || (is_changed && _filter->on_change_resets_interval_)) + last_forwarded_[_client] = its_current; + } + + return (is_changed || is_elapsed); + }; + } else { + filters_.erase(_client); + } + ret = eventgroups_[_eventgroup].insert(_client).second; + } else { VSOMEIP_WARNING << __func__ << ": Didnt' insert client " - << std::hex << std::setw(4) << std::setfill('0') - << _client - << " to eventgroup " + << std::hex << std::setw(4) << std::setfill('0') << _client + << " to eventgroup 0x" << std::hex << std::setw(4) << std::setfill('0') << get_service() << "." << get_instance() << "." << _eventgroup; @@ -428,14 +631,21 @@ bool event::add_subscriber(eventgroup_t _eventgroup, client_t _client, bool _for return ret; } -void event::remove_subscriber(eventgroup_t _eventgroup, client_t _client) { +void +event::remove_subscriber(eventgroup_t _eventgroup, client_t _client) { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); auto find_eventgroup = eventgroups_.find(_eventgroup); if (find_eventgroup != eventgroups_.end()) find_eventgroup->second.erase(_client); + + std::lock_guard<std::mutex> its_last_forwarded_guard(last_forwarded_mutex_); + last_forwarded_.erase(_client); } -bool event::has_subscriber(eventgroup_t _eventgroup, client_t _client) { +bool +event::has_subscriber(eventgroup_t _eventgroup, client_t _client) { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); auto find_eventgroup = eventgroups_.find(_eventgroup); if (find_eventgroup != eventgroups_.end()) { @@ -449,7 +659,9 @@ bool event::has_subscriber(eventgroup_t _eventgroup, client_t _client) { return false; } -std::set<client_t> event::get_subscribers() { +std::set<client_t> +event::get_subscribers() { + std::set<client_t> its_subscribers; std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); for (const auto &e : eventgroups_) @@ -457,13 +669,79 @@ std::set<client_t> event::get_subscribers() { return its_subscribers; } -void event::clear_subscribers() { +std::set<client_t> +event::get_filtered_subscribers(bool _force) { + + std::set<client_t> its_subscribers(get_subscribers()); + std::set<client_t> its_filtered_subscribers; + + std::shared_ptr<payload> its_payload, its_payload_update; + { + its_payload = current_->get_payload(); + its_payload_update = update_->get_payload(); + } + + if (filters_.empty()) { + + bool must_forward = (type_ != event_type_e::ET_FIELD + || _force + || epsilon_change_func_(its_payload, its_payload_update)); + + if (must_forward) + return (its_subscribers); + + } else { + byte_t is_allowed(0xff); + + std::lock_guard<std::mutex> its_lock(filters_mutex_); + for (const auto s : its_subscribers) { + + auto its_specific = filters_.find(s); + if (its_specific != filters_.end()) { + if (its_specific->second(its_payload, its_payload_update)) + its_filtered_subscribers.insert(s); + } else { + if (is_allowed == 0xff) { + is_allowed = (type_ != event_type_e::ET_FIELD + || _force + || epsilon_change_func_(its_payload, its_payload_update) + ? 0x01 : 0x00); + } + + if (is_allowed == 0x01) + its_filtered_subscribers.insert(s); + } + } + } + + return (its_filtered_subscribers); +} + +std::set<client_t> +event::update_and_get_filtered_subscribers( + const std::shared_ptr<payload> &_payload, bool _is_from_remote) { + + std::lock_guard<std::mutex> its_lock(mutex_); + + (void)prepare_update_payload_unlocked(_payload, true); + auto its_subscribers = get_filtered_subscribers(!_is_from_remote); + if (_is_from_remote) + update_payload_unlocked(); + + return (its_subscribers); +} + +void +event::clear_subscribers() { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); for (auto &e : eventgroups_) e.second.clear(); } -bool event::has_ref(client_t _client, bool _is_provided) { +bool +event::has_ref(client_t _client, bool _is_provided) { + std::lock_guard<std::mutex> its_lock(refs_mutex_); auto its_client = refs_.find(_client); if (its_client != refs_.end()) { @@ -477,24 +755,35 @@ bool event::has_ref(client_t _client, bool _is_provided) { return false; } -bool event::is_shadow() const { +bool +event::is_shadow() const { + return is_shadow_; } -void event::set_shadow(bool _shadow) { +void +event::set_shadow(bool _shadow) { + is_shadow_ = _shadow; } -bool event::is_cache_placeholder() const { +bool +event::is_cache_placeholder() const { + return is_cache_placeholder_; } -void event::set_cache_placeholder(bool _is_cache_place_holder) { +void +event::set_cache_placeholder(bool _is_cache_place_holder) { + is_cache_placeholder_ = _is_cache_place_holder; } -void event::start_cycle() { - if (std::chrono::milliseconds::zero() != cycle_) { +void +event::start_cycle() { + + if (!is_shadow_ + && std::chrono::milliseconds::zero() != cycle_) { cycle_timer_.expires_from_now(cycle_); auto its_handler = std::bind(&event::update_cbk, shared_from_this(), @@ -503,15 +792,20 @@ void event::start_cycle() { } } -void event::stop_cycle() { - if (std::chrono::milliseconds::zero() != cycle_) { +void +event::stop_cycle() { + + if (!is_shadow_ + && std::chrono::milliseconds::zero() != cycle_) { boost::system::error_code ec; cycle_timer_.cancel(ec); } } -bool event::compare(const std::shared_ptr<payload> &_lhs, +bool +event::has_changed(const std::shared_ptr<payload> &_lhs, const std::shared_ptr<payload> &_rhs) const { + bool is_change = (_lhs->get_length() != _rhs->get_length()); if (!is_change) { std::size_t its_pos = 0; @@ -522,10 +816,12 @@ bool event::compare(const std::shared_ptr<payload> &_lhs, its_pos++; } } - return is_change; + return (is_change); } -std::set<client_t> event::get_subscribers(eventgroup_t _eventgroup) { +std::set<client_t> +event::get_subscribers(eventgroup_t _eventgroup) { + std::set<client_t> its_subscribers; std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); auto found_eventgroup = eventgroups_.find(_eventgroup); @@ -535,7 +831,9 @@ std::set<client_t> event::get_subscribers(eventgroup_t _eventgroup) { return its_subscribers; } -bool event::is_subscribed(client_t _client) { +bool +event::is_subscribed(client_t _client) { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); for (const auto &egp : eventgroups_) { if (egp.second.find(_client) != egp.second.end()) { @@ -547,18 +845,27 @@ bool event::is_subscribed(client_t _client) { reliability_type_e event::get_reliability() const { + return reliability_; } void event::set_reliability(const reliability_type_e _reliability) { + reliability_ = _reliability; } void event::remove_pending(const std::shared_ptr<endpoint_definition> &_target) { + std::lock_guard<std::mutex> its_lock(mutex_); pending_.erase(_target); } +void +event::set_session() { + + update_->set_session(routing_->get_session(false)); +} + } // namespace vsomeip_v3 diff --git a/implementation/routing/src/eventgroupinfo.cpp b/implementation/routing/src/eventgroupinfo.cpp index 50bbdb6..c41f55b 100644 --- a/implementation/routing/src/eventgroupinfo.cpp +++ b/implementation/routing/src/eventgroupinfo.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -119,12 +119,18 @@ void eventgroupinfo::set_multicast(const boost::asio::ip::address &_address, port_ = _port; } -const std::set<std::shared_ptr<event> > eventgroupinfo::get_events() const { +std::set<std::shared_ptr<event> > eventgroupinfo::get_events() const { std::lock_guard<std::mutex> its_lock(events_mutex_); return events_; } void eventgroupinfo::add_event(const std::shared_ptr<event>& _event) { + + if (_event == nullptr) { + VSOMEIP_ERROR << __func__ << ": Received ptr is null"; + return; + } + std::lock_guard<std::mutex> its_lock(events_mutex_); events_.insert(_event); @@ -158,6 +164,12 @@ void eventgroupinfo::add_event(const std::shared_ptr<event>& _event) { } void eventgroupinfo::remove_event(const std::shared_ptr<event>& _event) { + + if (_event == nullptr) { + VSOMEIP_ERROR << __func__ << ": Received ptr is null"; + return; + } + std::lock_guard<std::mutex> its_lock(events_mutex_); events_.erase(_event); } @@ -217,13 +229,19 @@ eventgroupinfo::update_remote_subscription( const bool _is_subscribe) { bool its_result(false); + + if (_subscription == nullptr) { + VSOMEIP_ERROR << __func__ << ": Received ptr is null"; + return (its_result); + } + std::shared_ptr<endpoint_definition> its_subscriber; std::set<std::shared_ptr<event> > its_events; { std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); - for (const auto& its_item : subscriptions_) { + for (const auto &its_item : subscriptions_) { if (its_item.second->equals(_subscription)) { // update existing subscription _changed = its_item.second->update( @@ -231,16 +249,17 @@ eventgroupinfo::update_remote_subscription( _id = its_item.second->get_id(); // Copy acknowledgment states from existing subscription - for (const auto& its_client : _subscription->get_clients()) { - const auto its_state = its_item.second->get_client_state(its_client); - if (_is_subscribe && - its_state == remote_subscription_state_e::SUBSCRIPTION_UNKNOWN) { - _subscription->set_client_state(its_client, - remote_subscription_state_e::SUBSCRIPTION_PENDING); + for (const auto its_client : _subscription->get_clients()) { + auto its_state = its_item.second->get_client_state(its_client); + if (_is_subscribe + && its_state == remote_subscription_state_e::SUBSCRIPTION_UNKNOWN) { + // We met the current subscription object during its + // unsubscribe process. Therefore, trigger a resubscription. + its_state = remote_subscription_state_e::SUBSCRIPTION_PENDING; _changed.insert(its_client); - } else { - _subscription->set_client_state(its_client, its_state); } + + _subscription->set_client_state(its_client, its_state); } if (_is_subscribe) { @@ -295,6 +314,11 @@ eventgroupinfo::is_remote_subscription_limit_reached( const std::shared_ptr<remote_subscription> &_subscription) { bool limit_reached(false); + if (_subscription == nullptr) { + VSOMEIP_ERROR << __func__ << ": Received ptr is null"; + return (limit_reached); + } + if (subscriptions_.size() <= max_remote_subscribers_) { return false; } @@ -321,6 +345,11 @@ eventgroupinfo::is_remote_subscription_limit_reached( remote_subscription_id_t eventgroupinfo::add_remote_subscription( const std::shared_ptr<remote_subscription> &_subscription) { + + if (_subscription == nullptr) { + VSOMEIP_ERROR << __func__ << ": Received ptr is null"; + return id_; + } std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); update_id(); @@ -419,7 +448,6 @@ void eventgroupinfo::send_initial_events( const std::shared_ptr<endpoint_definition> &_reliable, const std::shared_ptr<endpoint_definition> &_unreliable) const { - std::set<std::shared_ptr<event> > its_reliable_events, its_unreliable_events; // Build sets of reliable/unreliable events first to avoid having to @@ -465,11 +493,23 @@ eventgroupinfo::send_initial_events( } // Send events - for (const auto &its_event : its_reliable_events) - its_event->notify_one(VSOMEIP_ROUTING_CLIENT, _reliable); + if (!its_reliable_events.empty()) { + if (_reliable != nullptr) { + for (const auto &its_event : its_reliable_events) + its_event->notify_one(VSOMEIP_ROUTING_CLIENT, _reliable); + } else { + VSOMEIP_ERROR << __func__ << ": Received ptr (_reliable) is null"; + } + } - for (const auto &its_event : its_unreliable_events) - its_event->notify_one(VSOMEIP_ROUTING_CLIENT, _unreliable); + if (!its_unreliable_events.empty()) { + if (_unreliable != nullptr) { + for (const auto &its_event : its_unreliable_events) + its_event->notify_one(VSOMEIP_ROUTING_CLIENT, _unreliable); + } else { + VSOMEIP_ERROR << __func__ << ": Received ptr (_unreliable) is null"; + } + } } uint8_t eventgroupinfo::get_max_remote_subscribers() const { diff --git a/implementation/routing/src/remote_subscription.cpp b/implementation/routing/src/remote_subscription.cpp index cb04d93..3c95108 100644 --- a/implementation/routing/src/remote_subscription.cpp +++ b/implementation/routing/src/remote_subscription.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2018-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -13,7 +13,6 @@ remote_subscription::remote_subscription() : id_(PENDING_SUBSCRIPTION_ID), is_initial_(true), force_initial_events_(false), - major_(DEFAULT_MAJOR), ttl_(DEFAULT_TTL), reserved_(0), counter_(0), diff --git a/implementation/routing/src/routing_manager_base.cpp b/implementation/routing/src/routing_manager_base.cpp index c787a9e..49dcffb 100644 --- a/implementation/routing/src/routing_manager_base.cpp +++ b/implementation/routing/src/routing_manager_base.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -9,8 +9,8 @@ #include <vsomeip/internal/logger.hpp> #include "../include/routing_manager_base.hpp" -#include "../../endpoints/include/local_client_endpoint_impl.hpp" -#include "../../endpoints/include/local_server_endpoint_impl.hpp" +#include "../../protocol/include/send_command.hpp" +#include "../../security/include/policy_manager_impl.hpp" #include "../../security/include/security.hpp" #ifdef USE_DLT #include "../../tracing/include/connector_impl.hpp" @@ -23,9 +23,7 @@ namespace vsomeip_v3 { routing_manager_base::routing_manager_base(routing_manager_host *_host) : host_(_host), io_(host_->get_io()), - client_(host_->get_client()), - configuration_(host_->get_configuration()), - routing_state_(routing_state_e::RS_UNKNOWN) + configuration_(host_->get_configuration()) #ifdef USE_DLT , tc_(trace::connector_impl::get()) #endif @@ -41,29 +39,52 @@ routing_manager_base::routing_manager_base(routing_manager_host *_host) : std::make_shared<deserializer>(its_buffer_shrink_threshold)); } - own_uid_ = ANY_UID; - own_gid_ = ANY_GID; -#ifndef _WIN32 - own_uid_ = getuid(); - own_gid_ = getgid(); -#endif - + if (!configuration_->is_local_routing()) { + auto its_routing_address = configuration_->get_routing_host_address(); + auto its_routing_port = configuration_->get_routing_host_port(); + if (!its_routing_address.is_unspecified() && !its_routing_address.is_multicast()) { + add_guest(VSOMEIP_ROUTING_CLIENT, its_routing_address, its_routing_port); + } + } } -boost::asio::io_service & routing_manager_base::get_io() { +boost::asio::io_context &routing_manager_base::get_io() { + return (io_); } client_t routing_manager_base::get_client() const { - return client_; + + return (host_->get_client()); } void routing_manager_base::set_client(const client_t &_client) { - client_ = _client; + + host_->set_client(_client); } -session_t routing_manager_base::get_session() { - return host_->get_session(); +session_t routing_manager_base::get_session(bool _is_request) { + return host_->get_session(_is_request); +} + +const vsomeip_sec_client_t *routing_manager_base::get_sec_client() const { + + return (host_->get_sec_client()); +} + +std::string routing_manager_base::get_client_host() const { + std::lock_guard<std::mutex> its_env_lock(env_mutex_); + return env_; +} + +void routing_manager_base::set_client_host(const std::string &_client_host) { + + std::lock_guard<std::mutex> its_env_lock(env_mutex_); + env_ = _client_host; +} + +bool routing_manager_base::is_routing_manager() const { + return false; } void routing_manager_base::init(const std::shared_ptr<endpoint_manager_base>& _endpoint_manager) { @@ -218,25 +239,7 @@ void routing_manager_base::register_event(client_t _client, if (its_event) { if (!its_event->is_cache_placeholder()) { if (_type == its_event->get_type() - || its_event->get_type() == event_type_e::ET_UNKNOWN -#ifdef VSOMEIP_ENABLE_COMPAT - || (its_event->get_type() == event_type_e::ET_EVENT - && _type == event_type_e::ET_SELECTIVE_EVENT) - || (its_event->get_type() == event_type_e::ET_SELECTIVE_EVENT - && _type == event_type_e::ET_EVENT && _is_provided) -#endif - ) { -#ifdef VSOMEIP_ENABLE_COMPAT - if (its_event->get_type() == event_type_e::ET_EVENT - && _type == event_type_e::ET_SELECTIVE_EVENT) { - its_event->set_type(_type); - VSOMEIP_INFO << "Event type changed to selective (" - << std::hex << std::setw(4) << std::setfill('0') << _client << ") [" - << std::hex << std::setw(4) << std::setfill('0') << _service << "." - << std::hex << std::setw(4) << std::setfill('0') << _instance << "." - << std::hex << std::setw(4) << std::setfill('0') << _notifier << "]"; - } -#endif + || its_event->get_type() == event_type_e::ET_UNKNOWN) { if (_is_provided) { its_event->set_provided(true); its_event->set_reliability(determine_event_reliability()); @@ -319,8 +322,8 @@ void routing_manager_base::register_event(client_t _client, } if (_is_shadow && !_epsilon_change_func) { - std::shared_ptr<cfg::debounce> its_debounce - = configuration_->get_debounce(_service, _instance, _notifier); + std::shared_ptr<debounce_filter_t> its_debounce + = configuration_->get_debounce(host_->get_name(), _service, _instance, _notifier); if (its_debounce) { VSOMEIP_WARNING << "Using debounce configuration for " << " SOME/IP event " @@ -344,6 +347,9 @@ void routing_manager_base::register_event(client_t _client, _epsilon_change_func = [its_debounce]( const std::shared_ptr<payload> &_old, const std::shared_ptr<payload> &_new) { + + static std::chrono::steady_clock::time_point its_last_forwarded + = std::chrono::steady_clock::time_point::max(); bool is_changed(false), is_elapsed(false); // Check whether we should forward because of changed data @@ -362,8 +368,8 @@ void routing_manager_base::register_event(client_t _client, for (length_t i = its_min_length; i < its_max_length; i++) { auto j = its_debounce->ignore_.find(i); // A change is detected when an additional byte is not - // excluded at all or if its exclusion does not cover - // all its bits. + // excluded at all or if its exclusion does not cover all + // bits if (j == its_debounce->ignore_.end() || j->second != 0xFF) { is_changed = true; break; @@ -396,12 +402,12 @@ void routing_manager_base::register_event(client_t _client, std::chrono::steady_clock::time_point its_current = std::chrono::steady_clock::now(); - long elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( - its_current - its_debounce->last_forwarded_).count(); - is_elapsed = (its_debounce->last_forwarded_ == (std::chrono::steady_clock::time_point::max)() + std::int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( + its_current - its_last_forwarded).count(); + is_elapsed = (its_last_forwarded == std::chrono::steady_clock::time_point::max() || elapsed >= its_debounce->interval_); if (is_elapsed || (is_changed && its_debounce->on_change_resets_interval_)) - its_debounce->last_forwarded_ = its_current; + its_last_forwarded = its_current; } return (is_changed || is_elapsed); }; @@ -440,14 +446,13 @@ void routing_manager_base::register_event(client_t _client, std::set<client_t> its_any_event_subscribers = its_any_event->get_subscribers(eventgroup); for (const client_t subscriber : its_any_event_subscribers) { - its_event->add_subscriber(eventgroup, subscriber, true); + its_event->add_subscriber(eventgroup, nullptr, subscriber, true); } } } } } - - if (!its_event->is_cache_placeholder()) { + if(!_is_cache_placeholder) { its_event->add_ref(_client, _is_provided); } @@ -547,8 +552,8 @@ std::vector<event_t> routing_manager_base::find_events( bool routing_manager_base::is_response_allowed(client_t _sender, service_t _service, instance_t _instance, method_t _method) { - const auto its_security(security::get()); - if (!its_security->is_enabled()) { + if (!configuration_->is_security_enabled() + || !configuration_->is_local_routing()) { return true; } @@ -575,7 +580,7 @@ bool routing_manager_base::is_response_allowed(client_t _sender, service_t _serv // service is now offered by another client // or service is not offered at all std::string security_mode_text = "!"; - if (!its_security->is_audit()) { + if (!configuration_->is_security_audit()) { security_mode_text = ", but will be allowed due to audit mode is active!"; } @@ -586,23 +591,20 @@ bool routing_manager_base::is_response_allowed(client_t _sender, service_t _serv << _service << "/" << _instance << "/" << _method << security_mode_text; - return !its_security->is_audit(); + return !configuration_->is_security_audit(); } -bool routing_manager_base::is_subscribe_to_any_event_allowed(credentials_t _credentials, client_t _client, +bool routing_manager_base::is_subscribe_to_any_event_allowed( + const vsomeip_sec_client_t *_sec_client, client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup) { - const auto its_security(security::get()); - const uid_t its_uid(std::get<0>(_credentials)); - const gid_t its_gid(std::get<1>(_credentials)); - bool is_allowed(true); auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); if (its_eventgroup) { for (const auto& e : its_eventgroup->get_events()) { - if (!its_security->is_client_allowed(its_uid, its_gid, - _client, _service, _instance, e->get_event())) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member( + _sec_client, _service, _instance, e->get_event())) { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << _client << " : routing_manager_base::is_subscribe_to_any_event_allowed: " << "subscribes to service/instance/event " @@ -617,26 +619,64 @@ bool routing_manager_base::is_subscribe_to_any_event_allowed(credentials_t _cred return is_allowed; } -void routing_manager_base::subscribe(client_t _client, uid_t _uid, gid_t _gid, - service_t _service, instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, event_t _event) { +void routing_manager_base::add_known_client(client_t _client, const std::string &_client_host) { +#if !defined(VSOMEIP_DISABLE_SECURITY) && (defined(__linux__) || defined(ANDROID)) + std::lock_guard<std::mutex> lazy_lock(add_known_client_mutex_); + if (configuration_->is_security_enabled()) { + //Ignore if we have already loaded the policy extension + policy_manager_impl::policy_loaded_e policy_loaded + = policy_manager_impl::get()->is_policy_extension_loaded(_client_host); + + if (policy_loaded == policy_manager_impl::policy_loaded_e::POLICY_PATH_FOUND_AND_NOT_LOADED) + { + if (configuration_->lazy_load_security(_client_host)) { + VSOMEIP_INFO << __func__ << " vSomeIP Security: Loaded security policies for host: " + << _client_host + << " at UID/GID: " << std::dec << getuid() << "/" << getgid(); + } + } else if (policy_loaded == policy_manager_impl::policy_loaded_e::POLICY_PATH_INEXISTENT) { + if (configuration_->lazy_load_security(_client_host)) + { + VSOMEIP_INFO << __func__ << " vSomeIP Security: Loaded security policies for host: " + << _client_host + << " at UID/GID: " << std::dec << getuid() << "/" << getgid(); + } else if (configuration_->lazy_load_security(get_client_host())) { //necessary for lazy loading from inside android container + VSOMEIP_INFO << __func__ << " vSomeIP Security: Loaded security policies for host: " + << get_client_host() + << " at UID/GID: " << std::dec << getuid() << "/" << getgid(); + } + } + } +#endif + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + known_clients_[_client] = _client_host; +} + +void routing_manager_base::subscribe(client_t _client, + const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter) { + + (void)_major; + (void)_sec_client; - (void) _major; - (void)_uid; - (void)_gid; std::set<event_t> its_already_subscribed_events; bool inserted = insert_subscription(_service, _instance, _eventgroup, - _event, _client, &its_already_subscribed_events); + _event, _filter, _client, &its_already_subscribed_events); if (inserted) { notify_one_current_value(_client, _service, _instance, _eventgroup, _event, its_already_subscribed_events); } } -void routing_manager_base::unsubscribe(client_t _client, uid_t _uid, gid_t _gid, - service_t _service, instance_t _instance, eventgroup_t _eventgroup,event_t _event) { - (void)_uid; - (void)_gid; +void routing_manager_base::unsubscribe(client_t _client, + const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event) { + + (void)_sec_client; + if (_event != ANY_EVENT) { auto its_event = find_event(_service, _instance, _event); if (its_event) { @@ -653,24 +693,10 @@ void routing_manager_base::unsubscribe(client_t _client, uid_t _uid, gid_t _gid, } } -void -routing_manager_base::unsubscribe_all( - service_t _service, instance_t _instance) { - - std::lock_guard<std::mutex> its_guard(events_mutex_); - auto find_service = events_.find(_service); - if (find_service != events_.end()) { - auto find_instance = find_service->second.find(_instance); - if (find_instance != find_service->second.end()) { - for (auto &e : find_instance->second) - e.second->clear_subscribers(); - } - } -} - void routing_manager_base::notify(service_t _service, instance_t _instance, event_t _event, std::shared_ptr<payload> _payload, bool _force) { + std::shared_ptr<event> its_event = find_event(_service, _instance, _event); if (its_event) { its_event->set_payload(_payload, _force); @@ -843,7 +869,7 @@ void routing_manager_base::notify_one_current_value( if (_event != ANY_EVENT) { std::shared_ptr<event> its_event = find_event(_service, _instance, _event); if (its_event && its_event->is_field()) - its_event->notify_one(_client); + its_event->notify_one(_client, false); } else { auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); if (its_eventgroup) { @@ -852,7 +878,7 @@ void routing_manager_base::notify_one_current_value( if (e->is_field() && _events_to_exclude.find(e->get_event()) == _events_to_exclude.end()) { - e->notify_one(_client); + e->notify_one(_client, false); } } } @@ -860,7 +886,8 @@ void routing_manager_base::notify_one_current_value( } bool routing_manager_base::send(client_t _client, - std::shared_ptr<message> _message) { + std::shared_ptr<message> _message, bool _force) { + bool is_sent(false); if (utility::is_request(_message->get_message_type())) { _message->set_client(_client); @@ -870,7 +897,8 @@ bool routing_manager_base::send(client_t _client, if (its_serializer->serialize(_message.get())) { is_sent = send(_client, its_serializer->get_data(), its_serializer->get_size(), _message->get_instance(), - _message->is_reliable(), get_client(), std::make_pair(ANY_UID, ANY_GID), 0, false); + _message->is_reliable(), get_client(), get_sec_client(), + 0, false, _force); its_serializer->reset(); put_serializer(its_serializer); } else { @@ -1024,18 +1052,20 @@ void routing_manager_base::remove_local(client_t _client, bool _remove_uid) { void routing_manager_base::remove_local(client_t _client, const std::set<std::tuple<service_t, instance_t, eventgroup_t>>& _subscribed_eventgroups, - bool _remove_uid) { + bool _remove_sec_client) { - std::pair<uid_t, gid_t> its_uid_gid(ANY_UID, ANY_GID); - security::get()->get_client_to_uid_gid_mapping(_client, its_uid_gid); + vsomeip_sec_client_t its_sec_client; + policy_manager_impl::get()->get_client_to_sec_client_mapping(_client, its_sec_client); - if (_remove_uid) { - security::get()->remove_client_to_uid_gid_mapping(_client); + if (_remove_sec_client) { + policy_manager_impl::get()->remove_client_to_sec_client_mapping(_client); } for (auto its_subscription : _subscribed_eventgroups) { host_->on_subscription(std::get<0>(its_subscription), std::get<1>(its_subscription), - std::get<2>(its_subscription), _client, its_uid_gid.first, its_uid_gid.second, false, [](const bool _subscription_accepted){ (void)_subscription_accepted; }); - routing_manager_base::unsubscribe(_client, its_uid_gid.first, its_uid_gid.second, std::get<0>(its_subscription), + std::get<2>(its_subscription), _client, + &its_sec_client, get_env(_client), + false, [](const bool _subscription_accepted){ (void)_subscription_accepted; }); + routing_manager_base::unsubscribe(_client, &its_sec_client, std::get<0>(its_subscription), std::get<1>(its_subscription), std::get<2>(its_subscription), ANY_EVENT); } ep_mgr_->remove_local(_client); @@ -1047,7 +1077,7 @@ void routing_manager_base::remove_local(client_t _client, for (auto& i : s.second) { if (std::get<2>(i.second) == _client) { its_services.insert({ s.first, i.first }); - host_->on_availability(s.first, i.first, false, + host_->on_availability(s.first, i.first, availability_state_e::AS_UNAVAILABLE, std::get<0>(i.second), std::get<1>(i.second)); } } @@ -1074,9 +1104,7 @@ void routing_manager_base::remove_local(client_t _client, for (auto& sic : its_clients) { local_services_history_[std::get<0>(sic)][std::get<1>(sic)].erase(std::get<2>(sic)); if (local_services_history_[std::get<0>(sic)][std::get<1>(sic)].size() == 0) { - local_services_history_[std::get<0>(sic)].erase(std::get<1>(sic)); - if (local_services_history_[std::get<0>(sic)].size() == 0) - local_services_history_.erase(std::get<0>(sic)); + local_services_history_.erase(std::get<0>(sic)); } } } @@ -1161,7 +1189,7 @@ void routing_manager_base::remove_eventgroup_info(service_t _service, bool routing_manager_base::send_local_notification(client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, - bool _reliable, uint8_t _status_check) { + bool _reliable, uint8_t _status_check, bool _force) { #ifdef USE_DLT bool has_local(false); #endif @@ -1173,7 +1201,7 @@ bool routing_manager_base::send_local_notification(client_t _client, std::shared_ptr<event> its_event = find_event(its_service, _instance, its_method); if (its_event && !its_event->is_shadow()) { - for (auto its_client : its_event->get_subscribers()) { + for (auto its_client : its_event->get_filtered_subscribers(_force)) { // local if (its_client == VSOMEIP_ROUTING_CLIENT) { @@ -1189,60 +1217,57 @@ bool routing_manager_base::send_local_notification(client_t _client, std::shared_ptr<endpoint> its_local_target = ep_mgr_->find_local(its_client); if (its_local_target) { send_local(its_local_target, _client, _data, _size, - _instance, _reliable, VSOMEIP_SEND, _status_check); + _instance, _reliable, protocol::id_e::SEND_ID, _status_check); } } } #ifdef USE_DLT // Trace the message if a local client but will _not_ be forwarded to the routing manager if (has_local && !has_remote) { - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(nullptr, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); } #endif return has_remote; } bool routing_manager_base::send_local( - std::shared_ptr<endpoint>& _target, client_t _client, + std::shared_ptr<endpoint> &_target, client_t _client, const byte_t *_data, uint32_t _size, instance_t _instance, - bool _reliable, uint8_t _command, uint8_t _status_check) const { - const std::size_t its_complete_size = VSOMEIP_SEND_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE + _size; - const client_t sender = get_client(); - - std::vector<byte_t> its_command_header(VSOMEIP_SEND_COMMAND_SIZE); - its_command_header[VSOMEIP_COMMAND_TYPE_POS] = _command; - std::memcpy(&its_command_header[VSOMEIP_COMMAND_CLIENT_POS], - &sender, sizeof(client_t)); - std::memcpy(&its_command_header[VSOMEIP_COMMAND_SIZE_POS_MIN], - &its_complete_size, sizeof(_size)); - std::memcpy(&its_command_header[VSOMEIP_SEND_COMMAND_INSTANCE_POS_MIN], - &_instance, sizeof(instance_t)); - std::memcpy(&its_command_header[VSOMEIP_SEND_COMMAND_RELIABLE_POS], - &_reliable, sizeof(bool)); - std::memcpy(&its_command_header[VSOMEIP_SEND_COMMAND_CHECK_STATUS_POS], - &_status_check, sizeof(uint8_t)); - // Add target client, only relevant for selective notifications - std::memcpy(&its_command_header[VSOMEIP_SEND_COMMAND_DST_CLIENT_POS_MIN], - &_client, sizeof(client_t)); - - return _target->send(its_command_header, _data, _size); + bool _reliable, protocol::id_e _command, uint8_t _status_check) const { + + bool has_sent(false); + + protocol::send_command its_command(_command); + its_command.set_client(get_client()); + its_command.set_instance(_instance); + its_command.set_reliable(_reliable); + its_command.set_status(_status_check); + its_command.set_target(_client); + its_command.set_message(std::vector<byte_t>(_data, _data + _size)); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + has_sent = _target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + + return (has_sent); } bool routing_manager_base::insert_subscription( service_t _service, instance_t _instance, eventgroup_t _eventgroup, - event_t _event, client_t _client, std::set<event_t> *_already_subscribed_events) { + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter, + client_t _client, std::set<event_t> *_already_subscribed_events) { + bool is_inserted(false); if (_event != ANY_EVENT) { // subscribe to specific event std::shared_ptr<event> its_event = find_event(_service, _instance, _event); if (its_event) { - is_inserted = its_event->add_subscriber(_eventgroup, _client, + is_inserted = its_event->add_subscriber(_eventgroup, _filter, _client, host_->is_routing()); } else { VSOMEIP_WARNING << "routing_manager_base::insert_subscription(" @@ -1255,7 +1280,7 @@ bool routing_manager_base::insert_subscription( << "unoffered) event. Creating placeholder event holding " << "subscription until event is requested/offered."; is_inserted = create_placeholder_event_and_subscribe(_service, - _instance, _eventgroup, _event, _client); + _instance, _eventgroup, _event, _filter, _client); } } else { // subscribe to all events of the eventgroup std::shared_ptr<eventgroupinfo> its_eventgroup @@ -1273,7 +1298,7 @@ bool routing_manager_base::insert_subscription( // eventgroups _already_subscribed_events->insert(e->get_event()); } - is_inserted = e->add_subscriber(_eventgroup, _client, + is_inserted = e->add_subscriber(_eventgroup, _filter, _client, host_->is_routing()) || is_inserted; } } @@ -1291,7 +1316,7 @@ bool routing_manager_base::insert_subscription( << "unoffered) eventgroup. Creating placeholder event holding " << "subscription until event is requested/offered."; is_inserted = create_placeholder_event_and_subscribe(_service, - _instance, _eventgroup, _event, _client); + _instance, _eventgroup, _event, _filter, _client); } } return is_inserted; @@ -1305,7 +1330,8 @@ std::shared_ptr<serializer> routing_manager_base::get_serializer() { << std::hex << std::setw(4) << std::setfill('0') << get_client() << " has no available serializer. Waiting..."; - serializer_condition_.wait(its_lock); + + serializer_condition_.wait(its_lock, [this] { return !serializers_.empty(); }); VSOMEIP_INFO << __func__ << ": Client " << std::hex << std::setw(4) << std::setfill('0') << get_client() @@ -1332,7 +1358,8 @@ std::shared_ptr<deserializer> routing_manager_base::get_deserializer() { while (deserializers_.empty()) { VSOMEIP_INFO << std::hex << "client " << get_client() << "routing_manager_base::get_deserializer ~> all in use!"; - deserializer_condition_.wait(its_lock); + + deserializer_condition_.wait(its_lock, [this] { return !deserializers_.empty(); }); VSOMEIP_INFO << std::hex << "client " << get_client() << "routing_manager_base::get_deserializer ~> wait finished!"; } @@ -1356,8 +1383,8 @@ void routing_manager_base::send_pending_subscriptions(service_t _service, for (auto &ps : pending_subscriptions_) { if (ps.service_ == _service && ps.instance_ == _instance && ps.major_ == _major) { - send_subscribe(client_, ps.service_, ps.instance_, - ps.eventgroup_, ps.major_, ps.event_); + send_subscribe(get_client(), ps.service_, ps.instance_, + ps.eventgroup_, ps.major_, ps.event_, ps.filter_); } } } @@ -1421,6 +1448,47 @@ routing_manager_base::get_subscriptions(const client_t _client) { return result; } +bool +routing_manager_base::get_guest(client_t _client, + boost::asio::ip::address &_address, port_t &_port) const { + + std::lock_guard<std::mutex> its_lock(guests_mutex_); + auto find_guest = guests_.find(_client); + if (find_guest == guests_.end()) + return (false); + + _address = find_guest->second.first; + _port = find_guest->second.second; + + return (true); +} + +void +routing_manager_base::add_guest(client_t _client, + const boost::asio::ip::address &_address, port_t _port) { + + std::lock_guard<std::mutex> its_lock(guests_mutex_); + guests_[_client] = std::make_pair(_address, _port); +} + +void +routing_manager_base::remove_guest(client_t _client) { + + std::lock_guard<std::mutex> its_lock(guests_mutex_); + guests_.erase(_client); +} + +void +routing_manager_base::remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port) { + + (void)_local_port; + (void)_remote_address; + (void)_remote_port; + // dummy method to implement routing_host interface +} + routing_state_e routing_manager_base::get_routing_state() { return routing_state_; diff --git a/implementation/routing/src/routing_manager_client.cpp b/implementation/routing/src/routing_manager_client.cpp new file mode 100644 index 0000000..378ab5d --- /dev/null +++ b/implementation/routing/src/routing_manager_client.cpp @@ -0,0 +1,2890 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#if defined(__linux__) || defined(ANDROID) +#include <unistd.h> +#endif + +#include <climits> +#include <forward_list> +#include <future> +#include <iomanip> +#include <mutex> +#include <thread> +#include <unordered_set> + +#include <vsomeip/constants.hpp> +#include <vsomeip/runtime.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/event.hpp" +#include "../include/routing_manager_host.hpp" +#include "../include/routing_manager_client.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../endpoints/include/netlink_connector.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/message_impl.hpp" +#include "../../message/include/serializer.hpp" +#include "../../protocol/include/assign_client_command.hpp" +#include "../../protocol/include/assign_client_ack_command.hpp" +#include "../../protocol/include/deregister_application_command.hpp" +#include "../../protocol/include/distribute_security_policies_command.hpp" +#include "../../protocol/include/dummy_command.hpp" +#include "../../protocol/include/expire_command.hpp" +#include "../../protocol/include/offer_service_command.hpp" +#include "../../protocol/include/offered_services_request_command.hpp" +#include "../../protocol/include/offered_services_response_command.hpp" +#include "../../protocol/include/ping_command.hpp" +#include "../../protocol/include/pong_command.hpp" +#include "../../protocol/include/register_application_command.hpp" +#include "../../protocol/include/register_events_command.hpp" +#include "../../protocol/include/registered_ack_command.hpp" +#include "../../protocol/include/release_service_command.hpp" +#include "../../protocol/include/remove_security_policy_command.hpp" +#include "../../protocol/include/remove_security_policy_response_command.hpp" +#include "../../protocol/include/request_service_command.hpp" +#include "../../protocol/include/resend_provided_events_command.hpp" +#include "../../protocol/include/routing_info_command.hpp" +#include "../../protocol/include/send_command.hpp" +#include "../../protocol/include/stop_offer_service_command.hpp" +#include "../../protocol/include/subscribe_ack_command.hpp" +#include "../../protocol/include/subscribe_command.hpp" +#include "../../protocol/include/subscribe_nack_command.hpp" +#include "../../protocol/include/unregister_event_command.hpp" +#include "../../protocol/include/unsubscribe_ack_command.hpp" +#include "../../protocol/include/unsubscribe_command.hpp" +#include "../../protocol/include/update_security_credentials_command.hpp" +#include "../../protocol/include/update_security_policy_command.hpp" +#include "../../protocol/include/update_security_policy_response_command.hpp" +#include "../../service_discovery/include/runtime.hpp" +#include "../../security/include/policy.hpp" +#include "../../security/include/policy_manager_impl.hpp" +#include "../../security/include/security.hpp" +#include "../../utility/include/byteorder.hpp" +#include "../../utility/include/utility.hpp" +#ifdef USE_DLT +#include "../../tracing/include/connector_impl.hpp" +#endif + +namespace vsomeip_v3 { + +routing_manager_client::routing_manager_client(routing_manager_host *_host, + bool _client_side_logging, + const std::set<std::tuple<service_t, instance_t> > & _client_side_logging_filter) : + routing_manager_base(_host), + is_connected_(false), + is_started_(false), + state_(inner_state_type_e::ST_DEREGISTERED), + sender_(nullptr), + receiver_(nullptr), + register_application_timer_(io_), + request_debounce_timer_ (io_), + request_debounce_timer_running_(false), + client_side_logging_(_client_side_logging), + client_side_logging_filter_(_client_side_logging_filter) +#if defined(__linux__) || defined(ANDROID) + , is_local_link_available_(false) +#endif // defined(__linux__) || defined(ANDROID) +{ + + char its_hostname[1024]; + if (gethostname(its_hostname, sizeof(its_hostname)) == 0) { + set_client_host(its_hostname); + } +} + +routing_manager_client::~routing_manager_client() { +} + +void routing_manager_client::init() { + routing_manager_base::init(std::make_shared<endpoint_manager_base>(this, io_, configuration_)); + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (configuration_->is_local_routing()) { + sender_ = ep_mgr_->create_local(VSOMEIP_ROUTING_CLIENT); + } else { +#if defined(__linux__) || defined(ANDROID) + auto its_guest_address = configuration_->get_routing_guest_address(); + auto its_host_address = configuration_->get_routing_host_address(); + local_link_connector_ = std::make_shared<netlink_connector>( + io_, its_guest_address, boost::asio::ip::address(), + (its_guest_address != its_host_address)); + // if the guest is in the same node as the routing manager + // it should not require LINK to be UP to communicate + + if (local_link_connector_) { + local_link_connector_->register_net_if_changes_handler( + std::bind(&routing_manager_client::on_net_state_change, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + } +#else + receiver_ = ep_mgr_->create_local_server(shared_from_this()); + sender_ = ep_mgr_->create_local(VSOMEIP_ROUTING_CLIENT); +#endif + } + } +} + +void routing_manager_client::start() { + +#if defined(__linux__) || defined(ANDROID) + if (configuration_->is_local_routing()) { +#else + { +#endif // __linux__ || ANDROID + is_started_ = true; + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (!sender_) { + // application has been stopped and started again + sender_ = ep_mgr_->create_local(VSOMEIP_ROUTING_CLIENT); + } + if (sender_) { + sender_->start(); + } + } +#if defined(__linux__) || defined(ANDROID) + } else { + if (local_link_connector_) + local_link_connector_->start(); +#endif // __linux__ || ANDROID + } +} + +void routing_manager_client::stop() { + std::unique_lock<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERING) { + register_application_timer_.cancel(); + } + + const std::chrono::milliseconds its_timeout(configuration_->get_shutdown_timeout()); + while (state_ == inner_state_type_e::ST_REGISTERING) { + std::cv_status status = state_condition_.wait_for(its_lock, its_timeout); + if (status == std::cv_status::timeout) { + VSOMEIP_WARNING << std::hex << get_client() << " registering timeout on stop"; + break; + } + } + + if (state_ == inner_state_type_e::ST_REGISTERED) { + deregister_application(); + // Waiting de-register acknowledge to synchronize shutdown + while (state_ == inner_state_type_e::ST_REGISTERED) { + std::cv_status status = state_condition_.wait_for(its_lock, its_timeout); + if (status == std::cv_status::timeout) { + VSOMEIP_WARNING << std::hex << get_client() << " couldn't deregister application - timeout"; + break; + } + } + } + is_started_ = false; + its_lock.unlock(); + +#if defined(__linux__) || defined(ANDROID) + if (local_link_connector_) + local_link_connector_->stop(); +#endif + + { + std::lock_guard<std::mutex> its_lock(request_timer_mutex_); + request_debounce_timer_.cancel(); + } + + if (receiver_) { + receiver_->stop(); + } + receiver_ = nullptr; + + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->stop(); + } + // delete the sender + sender_ = nullptr; + } + + for (const auto client : ep_mgr_->get_connected_clients()) { + if (client != VSOMEIP_ROUTING_CLIENT) { + remove_local(client, true); + } + } + + if (configuration_->is_local_routing()) { + std::stringstream its_client; + its_client << utility::get_base_path(configuration_->get_network()) + << std::hex << get_client(); + #ifdef _WIN32 + ::_unlink(its_client.str().c_str()); + #else + + if (-1 == ::unlink(its_client.str().c_str())) { + VSOMEIP_ERROR<< "routing_manager_proxy::stop unlink failed (" + << its_client.str() << "): "<< std::strerror(errno); + } + #endif + } +} + +#if defined(__linux__) || defined(ANDROID) +void +routing_manager_client::on_net_state_change( + bool _is_interface, const std::string &_name, bool _is_available) { + + VSOMEIP_INFO << __func__ + << ": " << std::boolalpha << _is_interface << " " + << _name << " " + << std::boolalpha << _is_available; + + if (_is_interface) { + if (_is_available) { + if (!is_local_link_available_) { + + is_local_link_available_ = true; + + if (!receiver_) + receiver_ = ep_mgr_->create_local_server(shared_from_this()); + receiver_->start(); + is_started_ = true; + + if (!sender_) + sender_ = ep_mgr_->create_local(VSOMEIP_ROUTING_CLIENT); + sender_->start(); + } + } else { + if (is_local_link_available_) { + is_started_ = false; + + state_ = inner_state_type_e::ST_DEREGISTERED; + on_disconnect(sender_); + + sender_->stop(); + + receiver_->stop(); + + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + local_services_.clear(); + } + + is_local_link_available_ = false; + } + } + } +} +#endif // __linux__ || ANDROID + +std::shared_ptr<configuration> routing_manager_client::get_configuration() const { + return host_->get_configuration(); +} + +std::string routing_manager_client::get_env(client_t _client) const { + + std::lock_guard<std::mutex> its_known_clients_lock(known_clients_mutex_); + return get_env_unlocked(_client); +} + +std::string routing_manager_client::get_env_unlocked(client_t _client) const { + + auto find_client = known_clients_.find(_client); + if (find_client != known_clients_.end()) { + return (find_client->second); + } + return ""; +} + +bool routing_manager_client::offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + if (!routing_manager_base::offer_service(_client, _service, _instance, _major, _minor)) { + VSOMEIP_WARNING << "routing_manager_client::offer_service," + << "routing_manager_base::offer_service returned false"; + } + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERED) { + send_offer_service(_client, _service, _instance, _major, _minor); + } + protocol::service offer(_service, _instance, _major, _minor ); + pending_offers_.insert(offer); + } + return true; +} + +void routing_manager_client::send_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + (void)_client; + + protocol::offer_service_command its_offer; + its_offer.set_client(get_client()); + its_offer.set_service(_service); + its_offer.set_instance(_instance); + its_offer.set_major(_major); + its_offer.set_minor(_minor); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_offer.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else { + VSOMEIP_ERROR << __func__ << ": offer_service serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } + +} + +void routing_manager_client::stop_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + (void)_client; + + { + // Hold the mutex to ensure no placeholder event is created inbetween. + std::lock_guard<std::mutex> its_lock(stop_mutex_); + + routing_manager_base::stop_offer_service(_client, _service, _instance, _major, _minor); + clear_remote_subscriber_count(_service, _instance); + + // Note: The last argument does not matter here as a proxy + // does not manage endpoints to the external network. + clear_service_info(_service, _instance, false); + } + + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERED) { + + protocol::stop_offer_service_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_major(_major); + its_command.set_minor(_minor); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else { + VSOMEIP_ERROR << __func__ << ": stop offer serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } + } + auto it = pending_offers_.begin(); + while (it != pending_offers_.end()) { + if (it->service_ == _service + && it->instance_ == _instance) { + break; + } + it++; + } + if (it != pending_offers_.end()) pending_offers_.erase(it); + } +} + +void routing_manager_client::request_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + routing_manager_base::request_service(_client, + _service, _instance, _major, _minor); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + size_t request_debouncing_time = configuration_->get_request_debouncing(host_->get_name()); + protocol::service request = { _service, _instance, _major, _minor }; + if (!request_debouncing_time) { + if (state_ == inner_state_type_e::ST_REGISTERED) { + std::set<protocol::service> requests; + requests.insert(request); + send_request_services(requests); + } + requests_.insert(request); + } else { + requests_to_debounce_.insert(request); + std::lock_guard<std::mutex> 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_client::request_debounce_timeout_cbk, + std::dynamic_pointer_cast<routing_manager_client>(shared_from_this()), + std::placeholders::_1)); + } + } + } +} + +void routing_manager_client::release_service(client_t _client, + service_t _service, instance_t _instance) { + routing_manager_base::release_service(_client, _service, _instance); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + remove_pending_subscription(_service, _instance, 0xFFFF, ANY_EVENT); + + bool pending(false); + auto it = requests_to_debounce_.begin(); + while (it != requests_to_debounce_.end()) { + if (it->service_ == _service + && it->instance_ == _instance) { + pending = true; + } + 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); + } + } +} + + +void routing_manager_client::register_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, const event_type_e _type, + reliability_type_e _reliability, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, + bool _update_on_change, epsilon_change_func_t _epsilon_change_func, + bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) { + + (void)_is_shadow; + (void)_is_cache_placeholder; + + bool is_cyclic(_cycle != std::chrono::milliseconds::zero()); + + const event_data_t registration = { + _service, + _instance, + _notifier, + _type, + _reliability, + _is_provided, + is_cyclic, + _eventgroups + }; + bool is_first(false); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + is_first = pending_event_registrations_.find(registration) + == pending_event_registrations_.end(); +#ifndef VSOMEIP_ENABLE_COMPAT + if (is_first) { + pending_event_registrations_.insert(registration); + } +#else + bool insert = true; + if (is_first) { + for (auto iter = pending_event_registrations_.begin(); + iter != pending_event_registrations_.end();) { + if (iter->service_ == _service + && iter->instance_ == _instance + && iter->notifier_ == _notifier + && iter->is_provided_ == _is_provided + && iter->type_ == event_type_e::ET_EVENT + && _type == event_type_e::ET_SELECTIVE_EVENT) { + iter = pending_event_registrations_.erase(iter); + iter = pending_event_registrations_.insert(registration).first; + is_first = true; + insert = false; + break; + } else { + iter++; + } + } + if (insert) { + pending_event_registrations_.insert(registration); + } + } +#endif + } + if (is_first || _is_provided) { + routing_manager_base::register_event(_client, + _service, _instance, + _notifier, + _eventgroups, _type, _reliability, + _cycle, _change_resets_cycle, _update_on_change, + _epsilon_change_func, + _is_provided); + } + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERED && is_first) { + send_register_event(get_client(), _service, _instance, + _notifier, _eventgroups, _type, _reliability, + _is_provided, is_cyclic); + } + } +} + +void routing_manager_client::unregister_event(client_t _client, + service_t _service, instance_t _instance, event_t _notifier, + bool _is_provided) { + + routing_manager_base::unregister_event(_client, _service, _instance, + _notifier, _is_provided); + + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERED) { + + protocol::unregister_event_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_event(_notifier); + its_command.set_provided(_is_provided); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } + + for (auto iter = pending_event_registrations_.begin(); + iter != pending_event_registrations_.end(); ) { + if (iter->service_ == _service + && iter->instance_ == _instance + && iter->notifier_ == _notifier + && iter->is_provided_ == _is_provided) { + pending_event_registrations_.erase(iter); + break; + } else { + iter++; + } + } + } +} + +bool routing_manager_client::is_field(service_t _service, instance_t _instance, + event_t _event) const { + auto event = find_event(_service, _instance, _event); + if (event && event->is_field()) { + return true; + } + return false; +} + +void routing_manager_client::subscribe( + client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter) { + + (void)_client; + + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERED && is_available(_service, _instance, _major)) { + send_subscribe(get_client(), _service, _instance, _eventgroup, _major, _event, _filter ); + } + subscription_data_t subscription = { + _service, _instance, + _eventgroup, _major, + _event, _filter, + *_sec_client + }; + pending_subscriptions_.insert(subscription); +} + +void routing_manager_client::send_subscribe(client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter) { + + if (_event == ANY_EVENT) { + if (!is_subscribe_to_any_event_allowed(get_sec_client(), _client, _service, _instance, _eventgroup)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << _client + << " : routing_manager_proxy::subscribe: " + << " isn't allowed to subscribe to service/instance/event " + << _service << "/" << _instance << "/ANY_EVENT" + << " which violates the security policy ~> Skip subscribe!"; + return; + } + } else { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member( + get_sec_client(), _service, _instance, _event)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << _client + << " : routing_manager_proxy::subscribe: " + << " isn't allowed to subscribe to service/instance/event " + << _service << "/" << _instance + << "/" << _event; + return; + } + } + + protocol::subscribe_command its_command; + its_command.set_client(_client); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_major(_major); + its_command.set_event(_event); + its_command.set_pending_id(PENDING_SUBSCRIPTION_ID); + its_command.set_filter(_filter); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + client_t its_target_client = find_local_client(_service, _instance); + if (its_target_client != VSOMEIP_ROUTING_CLIENT) { + auto its_target = ep_mgr_->find_or_create_local(its_target_client); + its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else { + VSOMEIP_ERROR << __func__ << ": subscribe command serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } +} + +void routing_manager_client::send_subscribe_nack(client_t _subscriber, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event, remote_subscription_id_t _id) { + + protocol::subscribe_nack_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_subscriber(_subscriber); + its_command.set_event(_event); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + if (_subscriber != VSOMEIP_ROUTING_CLIENT + && _id == PENDING_SUBSCRIPTION_ID) { + auto its_target = ep_mgr_->find_local(_subscriber); + if (its_target) { + its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + return; + } + } + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else { + VSOMEIP_ERROR << __func__ << ": subscribe nack serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } +} + +void routing_manager_client::send_subscribe_ack(client_t _subscriber, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event, remote_subscription_id_t _id) { + + protocol::subscribe_ack_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_subscriber(_subscriber); + its_command.set_event(_event); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + if (_subscriber != VSOMEIP_ROUTING_CLIENT + && _id == PENDING_SUBSCRIPTION_ID) { + auto its_target = ep_mgr_->find_local(_subscriber); + if (its_target) { + its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + return; + } + } + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else { + VSOMEIP_ERROR << __func__ << ": subscribe ack serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } +} + +void routing_manager_client::unsubscribe(client_t _client, + const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { + + (void)_client; + (void)_sec_client; + + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + remove_pending_subscription(_service, _instance, _eventgroup, _event); + + if (state_ == inner_state_type_e::ST_REGISTERED) { + + protocol::unsubscribe_command its_command; + its_command.set_client(_client); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_major(ANY_MAJOR); + its_command.set_event(_event); + its_command.set_pending_id(PENDING_SUBSCRIPTION_ID); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + + auto its_target = ep_mgr_->find_local(_service, _instance); + if (its_target) { + its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else { + + VSOMEIP_ERROR << __func__ + << ": unsubscribe serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } + } + } +} + +bool routing_manager_client::send(client_t _client, const byte_t *_data, + length_t _size, instance_t _instance, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _sent_from_remote, bool _force) { + + (void)_client; + (void)_bound_client; + (void)_sec_client; + (void)_sent_from_remote; + bool is_sent(false); + bool has_remote_subscribers(false); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ != inner_state_type_e::ST_REGISTERED) { + return false; + } + } + if (client_side_logging_) { + if (_size > VSOMEIP_MESSAGE_TYPE_POS) { + service_t its_service = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_SERVICE_POS_MIN], + _data[VSOMEIP_SERVICE_POS_MAX]); + if (client_side_logging_filter_.empty() + || (1 == client_side_logging_filter_.count(std::make_tuple(its_service, ANY_INSTANCE))) + || (1 == client_side_logging_filter_.count(std::make_tuple(its_service, _instance)))) { + method_t its_method = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_METHOD_POS_MIN], + _data[VSOMEIP_METHOD_POS_MAX]); + session_t its_session = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_SESSION_POS_MIN], + _data[VSOMEIP_SESSION_POS_MAX]); + client_t its_client = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_CLIENT_POS_MIN], + _data[VSOMEIP_CLIENT_POS_MAX]); + VSOMEIP_INFO << "routing_manager_client::send: (" + << std::hex << std::setw(4) << std::setfill('0') << get_client() <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_method << ":" + << std::hex << std::setw(4) << std::setfill('0') << its_session << ":" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "] " + << "type=" << std::hex << static_cast<std::uint32_t>(_data[VSOMEIP_MESSAGE_TYPE_POS]) + << " thread=" << std::hex << std::this_thread::get_id(); + } + } else { + VSOMEIP_ERROR << "routing_manager_client::send: (" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + <<"): message too short to log: " << std::dec << _size; + } + } + if (_size > VSOMEIP_MESSAGE_TYPE_POS) { + std::shared_ptr<endpoint> its_target; + if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + // Request + service_t its_service = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_SERVICE_POS_MIN], + _data[VSOMEIP_SERVICE_POS_MAX]); + client_t its_client = find_local_client(its_service, _instance); + if (its_client != VSOMEIP_ROUTING_CLIENT) { + if (is_client_known(its_client)) { + its_target = ep_mgr_->find_or_create_local(its_client); + } + } + } else if (!utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + // Response + client_t its_client = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_CLIENT_POS_MIN], + _data[VSOMEIP_CLIENT_POS_MAX]); + if (its_client != VSOMEIP_ROUTING_CLIENT) { + if (is_client_known(its_client)) { + its_target = ep_mgr_->find_or_create_local(its_client); + } + } + } else if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && + _client == VSOMEIP_ROUTING_CLIENT) { + // notify + has_remote_subscribers = send_local_notification(get_client(), _data, _size, + _instance, _reliable, _status_check, _force); + } else if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && + _client != VSOMEIP_ROUTING_CLIENT) { + // notify_one + its_target = ep_mgr_->find_local(_client); + if (its_target) { +#ifdef USE_DLT + trace::header its_header; + if (its_header.prepare(nullptr, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); +#endif + return send_local(its_target, get_client(), _data, _size, + _instance, _reliable, protocol::id_e::SEND_ID, _status_check); + } + } + // If no direct endpoint could be found + // or for notifications ~> route to routing_manager_stub +#ifdef USE_DLT + bool message_to_stub(false); +#endif + if (!its_target) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + its_target = sender_; +#ifdef USE_DLT + message_to_stub = true; +#endif + } else { + return false; + } + } + + bool send(true); + protocol::id_e its_command(protocol::id_e::SEND_ID); + + if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + if (_client != VSOMEIP_ROUTING_CLIENT) { + its_command = protocol::id_e::NOTIFY_ONE_ID; + } else { + its_command = protocol::id_e::NOTIFY_ID; + // Do we need to deliver a notification to the routing manager? + // Only for services which already have remote clients subscribed to + send = has_remote_subscribers; + } + } +#ifdef USE_DLT + else if (!message_to_stub) { + trace::header its_header; + if (its_header.prepare(nullptr, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); + } +#endif + if (send) { + is_sent = send_local(its_target, + (its_command == protocol::id_e::NOTIFY_ONE_ID ? _client : get_client()), + _data, _size, _instance, _reliable, its_command, _status_check); + } + } + return (is_sent); +} + +bool routing_manager_client::send_to(const client_t _client, + const std::shared_ptr<endpoint_definition> &_target, + std::shared_ptr<message> _message) { + + (void)_client; + (void)_target; + (void)_message; + + return (false); +} + +bool routing_manager_client::send_to( + const std::shared_ptr<endpoint_definition> &_target, + const byte_t *_data, uint32_t _size, instance_t _instance) { + + (void)_target; + (void)_data; + (void)_size; + (void)_instance; + + return (false); +} + +void routing_manager_client::on_connect(const std::shared_ptr<endpoint>& _endpoint) { + + _endpoint->set_connected(true); + _endpoint->set_established(true); + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (_endpoint != sender_) { + return; + } + } + is_connected_ = true; + assign_client(); +} + +void routing_manager_client::on_disconnect(const std::shared_ptr<endpoint>& _endpoint) { + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + is_connected_ = !(_endpoint == sender_); + } + if (!is_connected_) { + VSOMEIP_INFO << "routing_manager_client::on_disconnect: Client 0x" << std::hex + << get_client() << " calling host_->on_state " + << "with DEREGISTERED"; + host_->on_state(state_type_e::ST_DEREGISTERED); + } +} + +void routing_manager_client::on_message( + const byte_t *_data, length_t _size, + endpoint *_receiver, bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port) { + + (void)_receiver; + (void)_is_multicast; + (void)_remote_address; + (void)_remote_port; + +#if 0 + std::stringstream msg; + msg << "rmp::on_message<" << std::hex << get_client() << ">: "; + for (length_t i = 0; i < _size; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + protocol::id_e its_id; + client_t its_client; + service_t its_service; + instance_t its_instance; + eventgroup_t its_eventgroup; + event_t its_event; + major_version_t its_major; + client_t routing_host_id = configuration_->get_id( + configuration_->get_routing_host_name()); + client_t its_subscriber; + remote_subscription_id_t its_pending_id(PENDING_SUBSCRIPTION_ID); + std::uint32_t its_remote_subscriber_count(0); +#ifndef VSOMEIP_DISABLE_SECURITY + bool is_internal_policy_update(false); +#endif // !VSOMEIP_DISABLE_SECURITY + std::vector<byte_t> its_buffer(_data, _data + _size); + protocol::error_e its_error; + + auto its_security = policy_manager_impl::get(); + if (!its_security) + return; + + protocol::dummy_command its_dummy_command; + its_dummy_command.deserialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + its_id = its_dummy_command.get_id(); + its_client = its_dummy_command.get_client(); + + bool is_from_routing(false); + if (configuration_->is_security_enabled()) { + if (configuration_->is_local_routing()) { + // if security is enabled, client ID of routing must be configured + // and credential passing is active. Otherwise bound client is zero by default + is_from_routing = (_bound_client == routing_host_id); + } else { + is_from_routing = (_remote_address == configuration_->get_routing_host_address() + && _remote_port == configuration_->get_routing_host_port() + 1); + } + } else { + is_from_routing = (its_client == routing_host_id); + } + + if (configuration_->is_security_enabled() + && configuration_->is_local_routing() + && !is_from_routing && _bound_client != its_client) { + VSOMEIP_WARNING << std::hex << "Client " + << std::setw(4) << std::setfill('0') << get_client() + << " received a message with command " << int(its_id) + << " from " << std::setw(4) << std::setfill('0') + << its_client << " which doesn't match the bound client " + << std::setw(4) << std::setfill('0') << _bound_client + << " ~> skip message!"; + return; + } + + switch (its_id) { + case protocol::id_e::SEND_ID: + { + protocol::send_command its_send_command(protocol::id_e::SEND_ID); + its_send_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + auto a_deserializer = get_deserializer(); + a_deserializer->set_data(its_send_command.get_message()); + std::shared_ptr<message_impl> its_message(a_deserializer->deserialize_message()); + a_deserializer->reset(); + put_deserializer(a_deserializer); + + if (its_message) { + its_message->set_instance(its_send_command.get_instance()); + its_message->set_reliable(its_send_command.is_reliable()); + its_message->set_check_result(its_send_command.get_status()); + if (_sec_client) + its_message->set_sec_client(*_sec_client); + its_message->set_env(get_env(_bound_client)); + + if (!is_from_routing) { + if (utility::is_notification(its_message->get_message_type())) { + if (!is_response_allowed(_bound_client, its_message->get_service(), + its_message->get_instance(), its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_message: " + << " received a notification from client 0x" << _bound_client + << " which does not offer service/instance/event " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " ~> Skip message!"; + return; + } else { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(get_sec_client(), + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_message: " + << " isn't allowed to receive a notification from service/instance/event " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively from client 0x" << _bound_client + << " ~> Skip message!"; + return; + } + cache_event_payload(its_message); + } + } else if (utility::is_request(its_message->get_message_type())) { + if (configuration_->is_security_enabled() + && configuration_->is_local_routing() + && its_message->get_client() != _bound_client) { + VSOMEIP_WARNING << std::hex << "vSomeIP Security: Client 0x" << std::setw(4) << std::setfill('0') << get_client() + << " received a request from client 0x" << std::setw(4) << std::setfill('0') + << its_message->get_client() << " to service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() << " which doesn't match the bound client 0x" + << std::setw(4) << std::setfill('0') << _bound_client + << " ~> skip message!"; + return; + } + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(_sec_client, + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_message->get_client() + << " : routing_manager_client::on_message: " + << "isn't allowed to send a request to service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " ~> Skip message!"; + return; + } + } else { // response + if (!is_response_allowed(_bound_client, its_message->get_service(), + its_message->get_instance(), its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_message: " + << " received a response from client 0x" << _bound_client + << " which does not offer service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " ~> Skip message!"; + return; + } else { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(get_sec_client(), + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_message: " + << " isn't allowed to receive a response from service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively from client 0x" << _bound_client + << " ~> Skip message!"; + return; + } + } + } + } else { + if (!configuration_->is_remote_access_allowed()) { + // if the message is from routing manager, check if + // policy allows remote requests. + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_message: " + << std::hex << "Security: Remote clients via routing manager with client ID 0x" << its_client + << " are not allowed to communicate with service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively with client 0x" << get_client() + << " ~> Skip message!"; + return; + } else if (utility::is_notification(its_message->get_message_type())) { + // As subscription is sent on eventgroup level, incoming remote event ID's + // need to be checked as well if remote clients are allowed + // and the local policy only allows specific events in the eventgroup to be received. + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(get_sec_client(), + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_message: " + << " isn't allowed to receive a notification from service/instance/event " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively from remote clients via routing manager with client ID 0x" + << routing_host_id + << " ~> Skip message!"; + return; + } + cache_event_payload(its_message); + } + } + #ifdef USE_DLT + if (client_side_logging_ + && (client_side_logging_filter_.empty() + || (1 == client_side_logging_filter_.count(std::make_tuple(its_message->get_service(), ANY_INSTANCE))) + || (1 == client_side_logging_filter_.count(std::make_tuple(its_message->get_service(), its_message->get_instance()))))) { + trace::header its_header; + if (its_header.prepare(nullptr, false, its_send_command.get_instance())) { + uint32_t its_message_size = its_send_command.get_size(); + if (its_message_size >= uint32_t{vsomeip_v3::protocol::SEND_COMMAND_HEADER_SIZE}) + its_message_size -= uint32_t{vsomeip_v3::protocol::SEND_COMMAND_HEADER_SIZE}; + else + its_message_size = 0; + + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + &_data[vsomeip_v3::protocol::SEND_COMMAND_HEADER_SIZE], its_message_size); + } + } + #endif + + host_->on_message(std::move(its_message)); + } else + VSOMEIP_ERROR << "Routing proxy: on_message: " + << "SomeIP-Header deserialization failed!"; + } else + VSOMEIP_ERROR << __func__ + << ": send command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::ASSIGN_CLIENT_ACK_ID: + { + client_t its_assigned_client(VSOMEIP_CLIENT_UNSET); + protocol::assign_client_ack_command its_ack_command; + its_ack_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) + its_assigned_client = its_ack_command.get_assigned(); + + on_client_assign_ack(its_assigned_client); + break; + } + + case protocol::id_e::ROUTING_INFO_ID: + if (!configuration_->is_security_enabled() || is_from_routing) { + on_routing_info(_data, _size); + } else { + VSOMEIP_WARNING << "routing_manager_client::on_message: " + << std::hex << "Security: Client 0x" << get_client() + << " received an routing info from a client which isn't the routing manager" + << " : Skip message!"; + } + break; + + case protocol::id_e::PING_ID: + { + protocol::ping_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + send_pong(); + VSOMEIP_TRACE << "PING(" + << std::hex << std::setw(4) << std::setfill('0') << get_client() << ")"; + } else + VSOMEIP_ERROR << __func__ + << ": ping command deserialization failed (" + << std::dec << int(its_error) << ")"; + break; + } + + case protocol::id_e::SUBSCRIBE_ID: + { + protocol::subscribe_command its_subscribe_command; + its_subscribe_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_service = its_subscribe_command.get_service(); + its_instance = its_subscribe_command.get_instance(); + its_eventgroup = its_subscribe_command.get_eventgroup(); + its_major = its_subscribe_command.get_major(); + its_event = its_subscribe_command.get_event(); + its_pending_id = its_subscribe_command.get_pending_id(); + auto its_filter = its_subscribe_command.get_filter(); + + std::unique_lock<std::recursive_mutex> its_lock(incoming_subscriptions_mutex_); + if (its_pending_id != PENDING_SUBSCRIPTION_ID) { + its_lock.unlock(); +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::set_incoming_subscription_state(its_client, its_service, + its_instance, its_eventgroup, its_event, subscription_state_e::IS_SUBSCRIBING); +#endif + // Remote subscriber: Notify routing manager initially + count subscribes + auto self = shared_from_this(); + host_->on_subscription(its_service, its_instance, its_eventgroup, + its_client, _sec_client, get_env(its_client), true, + [this, self, its_client, its_service, its_instance, + its_eventgroup, its_event, its_filter, its_pending_id, its_major] + (const bool _subscription_accepted) { + + std::uint32_t its_count(0); + if (_subscription_accepted) { + send_subscribe_ack(its_client, its_service, its_instance, + its_eventgroup, its_event, its_pending_id); + std::set<event_t> its_already_subscribed_events; + bool inserted = insert_subscription(its_service, its_instance, its_eventgroup, + its_event, its_filter, VSOMEIP_ROUTING_CLIENT, &its_already_subscribed_events); + if (inserted) { + notify_remote_initially(its_service, its_instance, its_eventgroup, + its_already_subscribed_events); + } + #ifdef VSOMEIP_ENABLE_COMPAT + send_pending_notify_ones(its_service, its_instance, its_eventgroup, its_client, true); + #endif + its_count = get_remote_subscriber_count( + its_service, its_instance, its_eventgroup, true); + } else { + send_subscribe_nack(its_client, its_service, its_instance, + its_eventgroup, its_event, its_pending_id); + } + VSOMEIP_INFO << "SUBSCRIBE(" + << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << ":" + << std::hex << std::setw(4) << std::setfill('0') << its_event << ":" + << std::dec << (uint16_t)its_major << "] " + << std::boolalpha << (its_pending_id != PENDING_SUBSCRIPTION_ID) + << " " + << (_subscription_accepted ? + std::to_string(its_count) + " accepted." : "not accepted."); + +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::erase_incoming_subscription_state(its_client, its_service, + its_instance, its_eventgroup, its_event); +#endif + }); + } else if (is_client_known(its_client)) { + its_lock.unlock(); + if (!is_from_routing) { + if (its_event == ANY_EVENT) { + if (!is_subscribe_to_any_event_allowed(_sec_client, its_client, its_service, its_instance, its_eventgroup)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_client::on_message: " + << " isn't allowed to subscribe to service/instance/event " + << its_service << "/" << its_instance << "/ANY_EVENT" + << " which violates the security policy ~> Skip subscribe!"; + return; + } + } else { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member( + _sec_client, its_service, its_instance, its_event)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_client::on_message: " + << " subscribes to service/instance/event " + << its_service << "/" << its_instance << "/" << its_event + << " which violates the security policy ~> Skip subscribe!"; + return; + } + } + } else { + if (!configuration_->is_remote_access_allowed()) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_client::on_message: " + << std::hex << "Routing manager with client ID 0x" + << its_client + << " isn't allowed to subscribe to service/instance/event " + << its_service << "/" << its_instance + << "/" << its_event + << " respectively to client 0x" << get_client() + << " ~> Skip Subscribe!"; + return; + } + } + + // Local & already known subscriber: create endpoint + send (N)ACK + insert subscription +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::set_incoming_subscription_state(its_client, its_service, + its_instance, its_eventgroup, its_event, subscription_state_e::IS_SUBSCRIBING); +#endif + (void) ep_mgr_->find_or_create_local(its_client); + auto self = shared_from_this(); + auto its_env = get_env(its_client); + host_->on_subscription(its_service, its_instance, + its_eventgroup, its_client, _sec_client, its_env, true, + [this, self, its_client, its_filter, _sec_client, its_env, its_service, + its_instance, its_eventgroup, its_event, its_major] + (const bool _subscription_accepted) { + if (!_subscription_accepted) { + send_subscribe_nack(its_client, its_service, its_instance, + its_eventgroup, its_event, PENDING_SUBSCRIPTION_ID); + } else { + send_subscribe_ack(its_client, its_service, its_instance, + its_eventgroup, its_event, PENDING_SUBSCRIPTION_ID); + routing_manager_base::subscribe(its_client, _sec_client, + its_service, its_instance, its_eventgroup, its_major, its_event, its_filter); +#ifdef VSOMEIP_ENABLE_COMPAT + send_pending_notify_ones(its_service, its_instance, its_eventgroup, its_client); +#endif + } +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::erase_incoming_subscription_state(its_client, its_service, + its_instance, its_eventgroup, its_event); +#endif + }); + } else { + if (_sec_client) { + // Local & not yet known subscriber ~> set pending until subscriber gets known! + subscription_data_t subscription = { + its_service, its_instance, + its_eventgroup, its_major, + its_event, its_filter, + *_sec_client + }; + pending_incoming_subscriptions_[its_client].insert(subscription); + } else { + VSOMEIP_WARNING << __func__ + << ": Local subscription without security info."; + } + } + + if (its_pending_id == PENDING_SUBSCRIPTION_ID) { // local subscription + VSOMEIP_INFO << "SUBSCRIBE(" + << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << ":" + << std::hex << std::setw(4) << std::setfill('0') << its_event << ":" + << std::dec << (uint16_t)its_major << "]"; + } + } else { + VSOMEIP_ERROR << __func__ + << ": subscribe command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } + break; + } + + case protocol::id_e::UNSUBSCRIBE_ID: + { + protocol::unsubscribe_command its_unsubscribe; + its_unsubscribe.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_unsubscribe.get_client(); + its_service = its_unsubscribe.get_service(); + its_instance = its_unsubscribe.get_instance(); + its_eventgroup = its_unsubscribe.get_eventgroup(); + its_event = its_unsubscribe.get_event(); + its_pending_id = its_unsubscribe.get_pending_id(); + + host_->on_subscription(its_service, its_instance, its_eventgroup, + its_client, _sec_client, get_env(its_client), false, + [](const bool _subscription_accepted){ + (void)_subscription_accepted; + } + ); + if (its_pending_id == PENDING_SUBSCRIPTION_ID) { + // Local subscriber: withdraw subscription + routing_manager_base::unsubscribe(its_client, _sec_client, its_service, its_instance, its_eventgroup, its_event); + } else { + // Remote subscriber: withdraw subscription only if no more remote subscriber exists + its_remote_subscriber_count = get_remote_subscriber_count(its_service, + its_instance, its_eventgroup, false); + if (!its_remote_subscriber_count) { + routing_manager_base::unsubscribe(VSOMEIP_ROUTING_CLIENT, nullptr, its_service, + its_instance, its_eventgroup, its_event); + } + send_unsubscribe_ack(its_service, its_instance, its_eventgroup, its_pending_id); + } + VSOMEIP_INFO << "UNSUBSCRIBE(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." + << std::hex << std::setw(4) << std::setfill('0') << its_event << "] " + << (bool)(its_pending_id != PENDING_SUBSCRIPTION_ID) << " " + << std::dec << its_remote_subscriber_count; + } else + VSOMEIP_ERROR << __func__ + << ": unsubscribe command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::EXPIRE_ID: + { + protocol::expire_command its_expire; + its_expire.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_expire.get_client(); + its_service = its_expire.get_service(); + its_instance = its_expire.get_instance(); + its_eventgroup = its_expire.get_eventgroup(); + its_event = its_expire.get_event(); + its_pending_id = its_expire.get_pending_id(); + + host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, + _sec_client, get_env(its_client), false, + [](const bool _subscription_accepted){ (void)_subscription_accepted; }); + if (its_pending_id == PENDING_SUBSCRIPTION_ID) { + // Local subscriber: withdraw subscription + routing_manager_base::unsubscribe(its_client, _sec_client, + its_service, its_instance, its_eventgroup, its_event); + } else { + // Remote subscriber: withdraw subscription only if no more remote subscriber exists + its_remote_subscriber_count = get_remote_subscriber_count(its_service, + its_instance, its_eventgroup, false); + if (!its_remote_subscriber_count) { + routing_manager_base::unsubscribe(VSOMEIP_ROUTING_CLIENT, nullptr, + its_service, its_instance, its_eventgroup, its_event); + } + } + VSOMEIP_INFO << "EXPIRED SUBSCRIPTION(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." + << std::hex << std::setw(4) << std::setfill('0') << its_event << "] " + << (bool)(its_pending_id != PENDING_SUBSCRIPTION_ID) << " " + << std::dec << its_remote_subscriber_count; + } else + VSOMEIP_ERROR << __func__ + << ": expire deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::SUBSCRIBE_NACK_ID: + { + protocol::subscribe_nack_command its_subscribe_nack; + its_subscribe_nack.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_service = its_subscribe_nack.get_service(); + its_instance = its_subscribe_nack.get_instance(); + its_eventgroup = its_subscribe_nack.get_eventgroup(); + its_subscriber = its_subscribe_nack.get_subscriber(); + its_event = its_subscribe_nack.get_event(); + + on_subscribe_nack(its_subscriber, its_service, its_instance, its_eventgroup, its_event); + VSOMEIP_INFO << "SUBSCRIBE NACK(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." + << std::hex << std::setw(4) << std::setfill('0') << its_event << "]"; + } else + VSOMEIP_ERROR << __func__ + << ": subscribe nack command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::SUBSCRIBE_ACK_ID: + { + protocol::subscribe_ack_command its_subscribe_ack; + its_subscribe_ack.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_service = its_subscribe_ack.get_service(); + its_instance = its_subscribe_ack.get_instance(); + its_eventgroup = its_subscribe_ack.get_eventgroup(); + its_subscriber = its_subscribe_ack.get_subscriber(); + its_event = its_subscribe_ack.get_event(); + + on_subscribe_ack(its_subscriber, its_service, its_instance, its_eventgroup, its_event); + VSOMEIP_INFO << "SUBSCRIBE ACK(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." + << std::hex << std::setw(4) << std::setfill('0') << its_event << "]"; + } else + VSOMEIP_ERROR << __func__ + << ": subscribe ack command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::OFFERED_SERVICES_RESPONSE_ID: + { + protocol::offered_services_response_command its_response; + its_response.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + if (!configuration_->is_security_enabled() || is_from_routing) { + on_offered_services_info(its_response); + } else { + VSOMEIP_WARNING << std::hex << "Security: Client 0x" << get_client() + << " received an offered services info from a client which isn't the routing manager" + << " : Skip message!"; + } + } else + VSOMEIP_ERROR << __func__ + << ": offered services response command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + case protocol::id_e::RESEND_PROVIDED_EVENTS_ID: + { + protocol::resend_provided_events_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + resend_provided_event_registrations(); + send_resend_provided_event_response(its_command.get_remote_offer_id()); + + VSOMEIP_INFO << "RESEND_PROVIDED_EVENTS(" + << std::hex << std::setw(4) << std::setfill('0') + << its_command.get_client() << ")"; + } else + VSOMEIP_ERROR << __func__ + << ": resend provided events command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + case protocol::id_e::SUSPEND_ID: + { + on_suspend(); // cleanup remote subscribers + break; + } +#ifndef VSOMEIP_DISABLE_SECURITY + case protocol::id_e::UPDATE_SECURITY_POLICY_INT_ID: + is_internal_policy_update = true; + [[gnu::fallthrough]]; + case protocol::id_e::UPDATE_SECURITY_POLICY_ID: + { + if (!configuration_->is_security_enabled() || is_from_routing) { + protocol::update_security_policy_command its_command(is_internal_policy_update); + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + auto its_policy = its_command.get_policy(); + uint32_t its_uid; + uint32_t its_gid; + if (its_policy->get_uid_gid(its_uid, its_gid)) { + if (is_internal_policy_update + || its_security->is_policy_update_allowed(its_uid, its_policy)) { + its_security->update_security_policy(its_uid, its_gid, its_policy); + send_update_security_policy_response(its_command.get_update_id()); + } + } else { + VSOMEIP_ERROR << "vSomeIP Security: Policy has no valid uid/gid!"; + } + } else { + VSOMEIP_ERROR << "vSomeIP Security: Policy deserialization failed!"; + } + } else { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_message: " + << " received a security policy update from a client which isn't the routing manager" + << " : Skip message!"; + } + break; + } + + case protocol::id_e::REMOVE_SECURITY_POLICY_ID: + { + if (!configuration_->is_security_enabled() || is_from_routing) { + protocol::remove_security_policy_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + uid_t its_uid(its_command.get_uid()); + gid_t its_gid(its_command.get_gid()); + + if (its_security->is_policy_removal_allowed(its_uid)) { + its_security->remove_security_policy(its_uid, its_gid); + send_remove_security_policy_response(its_command.get_update_id()); + } + } else + VSOMEIP_ERROR << __func__ + << ": remove security policy command deserialization failed (" + << static_cast<int>(its_error) + << ")"; + } else + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_message: " + << "received a security policy removal from a client which isn't the routing manager" + << " : Skip message!"; + break; + } + + case protocol::id_e::DISTRIBUTE_SECURITY_POLICIES_ID: + { + if (!configuration_->is_security_enabled() || is_from_routing) { + protocol::distribute_security_policies_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + for (auto p : its_command.get_policies()) { + uid_t its_uid; + gid_t its_gid; + p->get_uid_gid(its_uid, its_gid); + if (its_security->is_policy_update_allowed(its_uid, p)) + its_security->update_security_policy(its_uid, its_gid, p); + } + } else + VSOMEIP_ERROR << __func__ + << ": distribute security policies command deserialization failed (" + << static_cast<int>(its_error) + << ")"; + } else + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_message: " + << " received a security policy distribution command from a client which isn't the routing manager" + << " : Skip message!"; + break; + } + + case protocol::id_e::UPDATE_SECURITY_CREDENTIALS_ID: + { + if (!configuration_->is_security_enabled() || is_from_routing) { + protocol::update_security_credentials_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + on_update_security_credentials(its_command); + } else + VSOMEIP_ERROR << __func__ + << ": update security credentials command deserialization failed (" + << static_cast<int>(its_error) + << ")"; + } else + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_message: " + << "received a security credential update from a client which isn't the routing manager" + << " : Skip message!"; + + break; + } +#endif // !VSOMEIP_DISABLE_SECURITY + default: + break; + } + } else + VSOMEIP_ERROR << __func__ + << ": dummy command deserialization failed (" + << std::dec << static_cast<int>(its_error) + << ")"; +} + +void routing_manager_client::on_routing_info( + const byte_t *_data, uint32_t _size) { +#if 0 + std::stringstream msg; + msg << "rmp::on_routing_info(" << std::hex << get_client() << "): "; + for (uint32_t i = 0; i < _size; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + auto its_security = policy_manager_impl::get(); + if (!its_security) + return; + + std::vector<byte_t> its_buffer(_data, _data + _size); + protocol::error_e its_error; + + protocol::routing_info_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error != protocol::error_e::ERROR_OK) { + VSOMEIP_ERROR << __func__ + << ": deserializing routing info command failed (" + << static_cast<int>(its_error) + << ")"; + return; + } + + for (const auto &e : its_command.get_entries()) { + auto its_client = e.get_client(); + switch (e.get_type()) { + case protocol::routing_info_entry_type_e::RIE_ADD_CLIENT: + { + auto its_address = e.get_address(); + if (!its_address.is_unspecified()) { + add_guest(its_client, its_address, e.get_port()); + add_known_client(its_client, ""); + } + + if (its_client == get_client()) { + VSOMEIP_INFO << std::hex << "Application/Client " << get_client() + << " (" << host_->get_name() << ") is registered."; +#if defined(__linux__) || defined(ANDROID) + if (!its_security->check_credentials(get_client(), get_sec_client())) { + VSOMEIP_ERROR << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_routing_info: RIE_ADD_CLIENT: isn't allowed" + << " to use the server endpoint due to credential check failed!"; + deregister_application(); + host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_DEREGISTERED)); + return; + } +#endif + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERING) { + boost::system::error_code ec; + register_application_timer_.cancel(ec); + send_registered_ack(); + send_pending_commands(); + state_ = inner_state_type_e::ST_REGISTERED; + // Notify stop() call about clean deregistration + state_condition_.notify_one(); + } + } + + // inform host about its own registration state changes + if (state_ == inner_state_type_e::ST_REGISTERED) { + host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_REGISTERED)); + } + } + break; + } + + case protocol::routing_info_entry_type_e::RIE_DELETE_CLIENT: + { + { + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + known_clients_.erase(its_client); + } + if (its_client == get_client()) { + its_security->remove_client_to_sec_client_mapping(its_client); + VSOMEIP_INFO << std::hex << "Application/Client " << get_client() + << " (" << host_->get_name() << ") is deregistered."; + + // inform host about its own registration state changes + host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_DEREGISTERED)); + + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + state_ = inner_state_type_e::ST_DEREGISTERED; + // Notify stop() call about clean deregistration + state_condition_.notify_one(); + } + } else if (its_client != VSOMEIP_ROUTING_CLIENT) { + remove_local(its_client, true); + } + break; + } + + case protocol::routing_info_entry_type_e::RIE_ADD_SERVICE_INSTANCE: + { + auto its_address = e.get_address(); + if (!its_address.is_unspecified()) { + add_guest(its_client, its_address, e.get_port()); + add_known_client(its_client, ""); + } + { + // Add yet unknown clients that offer services. Otherwise, + // the service cannot be used. The entry will be overwritten, + // when the offering clients connects. + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + if (known_clients_.find(its_client) == known_clients_.end()) { + known_clients_[its_client] = ""; + } + } + + for (const auto &s : e.get_services()) { + + const auto its_service(s.service_); + const auto its_instance(s.instance_); + const auto its_major(s.major_); + const auto its_minor(s.minor_); + + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + + // Check whether the service instance is already known. If yes, + // continue with the next service within the routing info. + auto found_service = local_services_.find(its_service); + if (found_service != local_services_.end()) { + if (found_service->second.find(its_instance) != found_service->second.end()) + continue; + } + + local_services_[its_service][its_instance] + = std::make_tuple(its_major, its_minor, its_client); + } + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + send_pending_subscriptions(its_service, its_instance, its_major); + } + host_->on_availability(its_service, its_instance, + availability_state_e::AS_AVAILABLE, its_major, its_minor); + VSOMEIP_INFO << "ON_AVAILABLE(" + << std::hex << std::setw(4) << std::setfill('0') << get_client() <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance + << ":" << std::dec << int(its_major) << "." << std::dec << its_minor << "]"; + } + break; + } + + case protocol::routing_info_entry_type_e::RIE_DELETE_SERVICE_INSTANCE: + { + for (const auto &s : e.get_services()) { + const auto its_service(s.service_); + const auto its_instance(s.instance_); + const auto its_major(s.major_); + const auto its_minor(s.minor_); + + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + auto found_service = local_services_.find(its_service); + if (found_service != local_services_.end()) { + found_service->second.erase(its_instance); + // move previously offering client to history + local_services_history_[its_service][its_instance].insert(its_client); + if (found_service->second.size() == 0) { + local_services_.erase(its_service); + } + } + } + on_stop_offer_service(its_service, its_instance, its_major, its_minor); + host_->on_availability(its_service, its_instance, + availability_state_e::AS_UNAVAILABLE, its_major, its_minor); + VSOMEIP_INFO << "ON_UNAVAILABLE(" + << std::hex << std::setw(4) << std::setfill('0') << get_client() <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance + << ":" << std::dec << int(its_major) << "." << std::dec << its_minor << "]"; + } + break; + } + + default: + VSOMEIP_ERROR << __func__ + << ": Unknown routing info entry type (" + << static_cast<int>(e.get_type()) + << ")"; + break; + } + } + + { + struct subscription_info { + service_t service_id_; + instance_t instance_id_; + eventgroup_t eventgroup_id_; + client_t client_id_; + major_version_t major_; + event_t event_; + std::shared_ptr<debounce_filter_t> filter_; + vsomeip_sec_client_t sec_client_; + std::string env_; + }; + std::lock_guard<std::recursive_mutex> its_lock(incoming_subscriptions_mutex_); + std::forward_list<struct subscription_info> subscription_actions; + if (pending_incoming_subscriptions_.size()) { + { + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + for (const auto &k : known_clients_) { + auto its_client = pending_incoming_subscriptions_.find(k.first); + if (its_client != pending_incoming_subscriptions_.end()) { + for (const auto &subscription : its_client->second) { + subscription_actions.push_front( + { subscription.service_, subscription.instance_, + subscription.eventgroup_, k.first, + subscription.major_, subscription.event_, + subscription.filter_, + subscription.sec_client_, + get_env_unlocked(k.first)}); + } + } + } + } + for (const subscription_info &si : subscription_actions) { +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::set_incoming_subscription_state(si.client_id_, si.service_id_, si.instance_id_, + si.eventgroup_id_, si.event_, subscription_state_e::IS_SUBSCRIBING); +#endif + (void) ep_mgr_->find_or_create_local(si.client_id_); + auto self = shared_from_this(); + host_->on_subscription( + si.service_id_, si.instance_id_, si.eventgroup_id_, + si.client_id_, &si.sec_client_, si.env_, true, + [this, self, si](const bool _subscription_accepted) { + if (!_subscription_accepted) { + send_subscribe_nack(si.client_id_, si.service_id_, + si.instance_id_, si.eventgroup_id_, si.event_, PENDING_SUBSCRIPTION_ID); + } else { + send_subscribe_ack(si.client_id_, si.service_id_, + si.instance_id_, si.eventgroup_id_, si.event_, PENDING_SUBSCRIPTION_ID); + routing_manager_base::subscribe(si.client_id_, &si.sec_client_, + si.service_id_, si.instance_id_, si.eventgroup_id_, + si.major_, si.event_, si.filter_); +#ifdef VSOMEIP_ENABLE_COMPAT + send_pending_notify_ones(si.service_id_, + si.instance_id_, si.eventgroup_id_, si.client_id_); +#endif + } +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::erase_incoming_subscription_state(si.client_id_, si.service_id_, + si.instance_id_, si.eventgroup_id_, si.event_); +#endif + { + std::lock_guard<std::recursive_mutex> its_lock2(incoming_subscriptions_mutex_); + pending_incoming_subscriptions_.erase(si.client_id_); + } + }); + } + } + } +} + +void routing_manager_client::on_offered_services_info( + protocol::offered_services_response_command &_command) { + + std::vector<std::pair<service_t, instance_t>> its_offered_services_info; + + for (const auto &s : _command.get_services()) + its_offered_services_info.push_back(std::make_pair(s.service_, s.instance_)); + + host_->on_offered_services_info(its_offered_services_info); +} + +void routing_manager_client::reconnect(const std::map<client_t, std::string> &_clients) { + auto its_security = policy_manager_impl::get(); + if (!its_security) + return; + + // inform host about its own registration state changes + host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_DEREGISTERED)); + + { + std::lock_guard<std::mutex> 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 &c : _clients) { + if (c.first != VSOMEIP_ROUTING_CLIENT) { + remove_local(c.first, true); + } + } + + VSOMEIP_INFO << std::hex << "Application/Client " << get_client() + <<": Reconnecting to routing manager."; + +#if defined(__linux__) || defined(ANDROID) + if (!its_security->check_credentials(get_client(), get_sec_client())) { + VSOMEIP_ERROR << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::reconnect: isn't allowed" + << " to use the server endpoint due to credential check failed!"; + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->stop(); + } + return; + } +#endif + + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->restart(); + } +} + +void routing_manager_client::assign_client() { + + protocol::assign_client_command its_command; + its_command.set_client(get_client()); + its_command.set_name(host_->get_name()); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error != protocol::error_e::ERROR_OK) { + + VSOMEIP_ERROR << __func__ << ": command creation failed (" + << std::dec << static_cast<int>(its_error) << ")"; + return; + } + + std::lock_guard<std::mutex> its_state_lock(state_mutex_); + if (is_connected_) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + if (state_ != inner_state_type_e::ST_DEREGISTERED) + return; + state_ = inner_state_type_e::ST_ASSIGNING; + + sender_->send(&its_buffer[0], static_cast<uint32_t>(its_buffer.size())); + + boost::system::error_code ec; + register_application_timer_.cancel(ec); + register_application_timer_.expires_from_now(std::chrono::milliseconds(10000)); + register_application_timer_.async_wait( + std::bind( + &routing_manager_client::assign_client_timeout_cbk, + std::dynamic_pointer_cast<routing_manager_client>(shared_from_this()), + std::placeholders::_1)); + } + } +} + +void routing_manager_client::register_application() { + + if (!receiver_) { + VSOMEIP_ERROR << __func__ + << "Cannot register. Local server endpoint does not exist."; + return; + } + + auto its_configuration(get_configuration()); + if (its_configuration->is_local_routing()) { + VSOMEIP_INFO << "Registering to routing manager @ " + << its_configuration->get_network() << "-0"; + } else { + auto its_routing_address(its_configuration->get_routing_host_address()); + auto its_routing_port(its_configuration->get_routing_host_port()); + VSOMEIP_INFO << "Registering to routing manager @ " + << its_routing_address.to_string() << ":" << its_routing_port; + } + + protocol::register_application_command its_command; + its_command.set_client(get_client()); + its_command.set_port(receiver_->get_local_port()); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + if (is_connected_) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + state_ = inner_state_type_e::ST_REGISTERING; + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + + register_application_timer_.cancel(); + register_application_timer_.expires_from_now(std::chrono::milliseconds(1000)); + register_application_timer_.async_wait( + std::bind( + &routing_manager_client::register_application_timeout_cbk, + std::dynamic_pointer_cast<routing_manager_client>(shared_from_this()), + std::placeholders::_1)); + } + } + } else + VSOMEIP_ERROR << __func__ + << ": register application command serialization failed(" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::deregister_application() { + + protocol::deregister_application_command its_command; + its_command.set_client(get_client()); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + if (is_connected_) + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else + VSOMEIP_ERROR << __func__ + << ": deregister application command serialization failed(" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::send_pong() const { + + protocol::pong_command its_command; + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + if (is_connected_) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else + VSOMEIP_ERROR << __func__ + << ": pong command serialization failed(" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::send_request_services(const std::set<protocol::service> &_requests) { + + if (!_requests.size()) { + return; + } + + protocol::request_service_command its_command; + its_command.set_client(get_client()); + its_command.set_services(_requests); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else { + VSOMEIP_ERROR << __func__ << ": request service serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } +} + +void routing_manager_client::send_release_service(client_t _client, service_t _service, + instance_t _instance) { + + (void)_client; + + protocol::release_service_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } +} + +void routing_manager_client::send_pending_event_registrations(client_t _client) { + + protocol::register_events_command its_command; + its_command.set_client(_client); + std::set<vsomeip_v3::routing_manager_client::event_data_t>::iterator it = pending_event_registrations_.begin(); + + while(it != pending_event_registrations_.end()) + { + for(; it!=pending_event_registrations_.end(); it++) { + protocol::register_event reg(it->service_, it->instance_, it->notifier_, it->type_, + it->is_provided_, it->reliability_, it->is_cyclic_ + , (uint16_t)it->eventgroups_.size(), it->eventgroups_); + if(!its_command.add_registration(reg)) {break;} + } + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": register event command serialization failed (" + << std::dec << int(its_error) << ")"; + } +} + +void routing_manager_client::send_register_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, const event_type_e _type, + reliability_type_e _reliability, + bool _is_provided, bool _is_cyclic) { + + (void)_client; + + protocol::register_events_command its_command; + its_command.set_client(get_client()); + + protocol::register_event reg(_service, _instance, _notifier, _type, + _is_provided, _reliability, _is_cyclic, + (uint16_t)_eventgroups.size(), _eventgroups); + + if(!its_command.add_registration(reg)) { + VSOMEIP_ERROR << __func__ << ": register event command is too long."; + } + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + + if (_is_provided) { + VSOMEIP_INFO << "REGISTER EVENT(" + << std::hex << std::setw(4) << std::setfill('0') << get_client() << "): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << _notifier + << ":is_provider=" << std::boolalpha << _is_provided << "]"; + } + } else + VSOMEIP_ERROR << __func__ + << ": register event command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::on_subscribe_ack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { + (void)_client; +#if 0 + VSOMEIP_ERROR << "routing_manager_client::" << __func__ + << "(" << std::hex << host_->get_client() << "):" + << "event=" + << std::hex << _service << "." + << std::hex << _instance << "." + << std::hex << _eventgroup << "." + << std::hex << _event; +#endif + if (_event == ANY_EVENT) { + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + for (const auto& its_event : its_eventgroup->get_events()) { + host_->on_subscription_status(_service, _instance, _eventgroup, its_event->get_event(), 0x0 /*OK*/); + } + } + } else { + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); + } +} + +void routing_manager_client::on_subscribe_nack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { + (void)_client; + if (_event == ANY_EVENT) { + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + for (const auto& its_event : its_eventgroup->get_events()) { + host_->on_subscription_status(_service, _instance, _eventgroup, its_event->get_event(), 0x7 /*Rejected*/); + } + } + } else { + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x7 /*Rejected*/); + } +} + +void routing_manager_client::cache_event_payload( + const std::shared_ptr<message> &_message) { + const service_t its_service(_message->get_service()); + const instance_t its_instance(_message->get_instance()); + const method_t its_method(_message->get_method()); + std::shared_ptr<event> its_event = find_event(its_service, its_instance, its_method); + if (its_event) { + if (its_event->is_field()) { + its_event->prepare_update_payload(_message->get_payload(), true); + its_event->update_payload(); + } + } else { + // we received a event which was not yet requested + std::set<eventgroup_t> its_eventgroups; + // create a placeholder field until someone requests this event with + // full information like eventgroup, field or not etc. + routing_manager_base::register_event(host_->get_client(), + its_service, its_instance, + its_method, + its_eventgroups, event_type_e::ET_UNKNOWN, + reliability_type_e::RT_UNKNOWN, + std::chrono::milliseconds::zero(), false, true, + nullptr, + false, false, true); + std::shared_ptr<event> its_event = find_event(its_service, its_instance, its_method); + if (its_event) { + its_event->prepare_update_payload(_message->get_payload(), true); + its_event->update_payload(); + } + } +} + +void routing_manager_client::on_stop_offer_service(service_t _service, + instance_t _instance, + major_version_t _major, + minor_version_t _minor) { + (void) _major; + (void) _minor; + std::map<event_t, std::shared_ptr<event> > events; + { + std::lock_guard<std::mutex> its_lock(events_mutex_); + auto its_events_service = events_.find(_service); + if (its_events_service != events_.end()) { + auto its_events_instance = its_events_service->second.find(_instance); + if (its_events_instance != its_events_service->second.end()) { + for (auto &e : its_events_instance->second) + events[e.first] = e.second; + } + } + } + for (auto &e : events) { + e.second->unset_payload(); + } +} + +void routing_manager_client::send_pending_commands() { + for (auto &po : pending_offers_) + send_offer_service(get_client(), + po.service_, po.instance_, + po.major_, po.minor_); + + send_pending_event_registrations(get_client()); + + send_request_services(requests_); +} + +void routing_manager_client::init_receiver() { +#if defined(__linux__) || defined(ANDROID) + auto its_security = policy_manager_impl::get(); + if (!its_security) + return; + + its_security->store_client_to_sec_client_mapping(get_client(), get_sec_client()); + its_security->store_sec_client_to_client_mapping(get_sec_client(), get_client()); +#endif + if (!receiver_) { + receiver_ = ep_mgr_->create_local_server(shared_from_this()); + } else { + std::uint16_t its_port = receiver_->get_local_port(); + if (its_port != ILLEGAL_PORT) + VSOMEIP_INFO << "Reusing local server endpoint@" << its_port; + } +} + +void routing_manager_client::notify_remote_initially(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, const std::set<event_t> &_events_to_exclude) { + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + auto service_info = find_service(_service, _instance); + for (const auto &e : its_eventgroup->get_events()) { + if (e->is_field() && e->is_set() + && _events_to_exclude.find(e->get_event()) + == _events_to_exclude.end()) { + std::shared_ptr<message> its_notification + = runtime::get()->create_notification(); + its_notification->set_service(_service); + its_notification->set_instance(_instance); + its_notification->set_method(e->get_event()); + its_notification->set_payload(e->get_payload()); + if (service_info) { + its_notification->set_interface_version(service_info->get_major()); + } + + std::shared_ptr<serializer> its_serializer(get_serializer()); + if (its_serializer->serialize(its_notification.get())) { + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + send_local(sender_, VSOMEIP_ROUTING_CLIENT, + its_serializer->get_data(), its_serializer->get_size(), + _instance, false, protocol::id_e::NOTIFY_ID, 0); + } + } + its_serializer->reset(); + put_serializer(its_serializer); + } else { + VSOMEIP_ERROR << "Failed to serialize message. Check message size!"; + } + } + } + } + +} + +uint32_t routing_manager_client::get_remote_subscriber_count(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, bool _increment) { + std::lock_guard<std::mutex> its_lock(remote_subscriber_count_mutex_); + uint32_t count (0); + bool found(false); + auto found_service = remote_subscriber_count_.find(_service); + if (found_service != remote_subscriber_count_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_group = found_instance->second.find(_eventgroup); + if (found_group != found_instance->second.end()) { + found = true; + if (_increment) { + found_group->second = found_group->second + 1; + } else { + if (found_group->second > 0) { + found_group->second = found_group->second - 1; + } + } + count = found_group->second; + } + } + } + if (!found) { + if (_increment) { + remote_subscriber_count_[_service][_instance][_eventgroup] = 1; + count = 1; + } + } + return count; +} + +void routing_manager_client::clear_remote_subscriber_count( + service_t _service, instance_t _instance) { + std::lock_guard<std::mutex> its_lock(remote_subscriber_count_mutex_); + auto found_service = remote_subscriber_count_.find(_service); + if (found_service != remote_subscriber_count_.end()) { + if (found_service->second.erase(_instance)) { + if (!found_service->second.size()) { + remote_subscriber_count_.erase(found_service); + } + } + } +} + +void +routing_manager_client::assign_client_timeout_cbk( + boost::system::error_code const &_error) { + + if (!_error) { + bool register_again(false); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ != inner_state_type_e::ST_REGISTERED) { + state_ = inner_state_type_e::ST_DEREGISTERED; + register_again = true; + } + } + if (register_again) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + VSOMEIP_WARNING << std::hex << "Client 0x" << get_client() + << " request client timeout! Trying again..."; + + if (sender_) { + sender_->restart(); + } + } + } +} + +void routing_manager_client::register_application_timeout_cbk( + boost::system::error_code const &_error) { + + bool register_again(false); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (!_error && state_ != inner_state_type_e::ST_REGISTERED) { + state_ = inner_state_type_e::ST_DEREGISTERED; + register_again = true; + } + } + if (register_again) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + VSOMEIP_WARNING << std::hex << "Client 0x" << get_client() + << " register timeout! Trying again..."; + + if (sender_) + sender_->restart(); + } +} + +void routing_manager_client::send_registered_ack() { + + protocol::registered_ack_command its_command; + its_command.set_client(get_client()); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": registered ack command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +bool routing_manager_client::is_client_known(client_t _client) { + + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + return (known_clients_.find(_client) != known_clients_.end()); +} + +bool routing_manager_client::create_placeholder_event_and_subscribe( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _notifier, const std::shared_ptr<debounce_filter_t> &_filter, + client_t _client) { + + std::lock_guard<std::mutex> its_lock(stop_mutex_); + + bool is_inserted(false); + + if (find_service(_service, _instance)) { + // We received an event for an existing service which was not yet + // requested/offered. Create a placeholder field until someone + // requests/offers this event with full information like eventgroup, + // field/event, etc. + std::set<eventgroup_t> its_eventgroups({ _eventgroup }); + // routing_manager_client: Always register with own client id and shadow = false + routing_manager_base::register_event(host_->get_client(), + _service, _instance, _notifier, + its_eventgroups, event_type_e::ET_UNKNOWN, reliability_type_e::RT_UNKNOWN, + std::chrono::milliseconds::zero(), false, true, nullptr, false, false, + true); + + std::shared_ptr<event> its_event = find_event(_service, _instance, _notifier); + if (its_event) { + is_inserted = its_event->add_subscriber(_eventgroup, _filter, _client, false); + } + } + + return is_inserted; +} + +void routing_manager_client::request_debounce_timeout_cbk( + boost::system::error_code const &_error) { + + std::lock_guard<std::mutex> 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<std::mutex> 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_client::request_debounce_timeout_cbk, + std::dynamic_pointer_cast<routing_manager_client>(shared_from_this()), + std::placeholders::_1)); + return; + } + } + } + } + { + std::lock_guard<std::mutex> its_lock(request_timer_mutex_); + request_debounce_timer_running_ = false; + } +} + +void routing_manager_client::register_client_error_handler(client_t _client, + const std::shared_ptr<endpoint> &_endpoint) { + + _endpoint->register_error_handler( + std::bind(&routing_manager_client::handle_client_error, this, _client)); +} + +void routing_manager_client::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, true); + } else { + bool should_reconnect(true); + { + std::unique_lock<std::mutex> its_lock(state_mutex_); + should_reconnect = is_started_; + } + if (should_reconnect) { + std::map<client_t, std::string> its_known_clients; + { + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + its_known_clients = known_clients_; + } + reconnect(its_known_clients); + } + } +} + +void routing_manager_client::send_get_offered_services_info(client_t _client, offer_type_e _offer_type) { + + protocol::offered_services_request_command its_command; + its_command.set_client(_client); + its_command.set_offer_type(_offer_type); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": offered service request command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::send_unsubscribe_ack( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + remote_subscription_id_t _id) { + + protocol::unsubscribe_ack_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": unsubscribe ack command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::resend_provided_event_registrations() { + std::lock_guard<std::mutex> its_lock(state_mutex_); + for (const event_data_t& ed : pending_event_registrations_) { + if (ed.is_provided_) { + send_register_event(get_client(), ed.service_, ed.instance_, + ed.notifier_, ed.eventgroups_, ed.type_, ed.reliability_, + ed.is_provided_, ed.is_cyclic_); + } + } +} + +void routing_manager_client::send_resend_provided_event_response(pending_remote_offer_id_t _id) { + + protocol::resend_provided_events_command its_command; + its_command.set_client(get_client()); + its_command.set_remote_offer_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": resend provided event command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +#ifndef VSOMEIP_DISABLE_SECURITY +void routing_manager_client::send_update_security_policy_response( + pending_security_update_id_t _update_id) { + + protocol::update_security_policy_response_command its_command; + its_command.set_client(get_client()); + its_command.set_update_id(_update_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": update security policy response command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::send_remove_security_policy_response( + pending_security_update_id_t _update_id) { + + protocol::remove_security_policy_response_command its_command; + its_command.set_client(get_client()); + its_command.set_update_id(_update_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": update security policy response command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::on_update_security_credentials( + const protocol::update_security_credentials_command &_command) { + + auto its_security = policy_manager_impl::get(); + if (!its_security) + return; + + for (const auto &c : _command.get_credentials()) { + std::shared_ptr<policy> its_policy(std::make_shared<policy>()); + boost::icl::interval_set<uint32_t> its_gid_set; + uid_t its_uid(c.first); + gid_t its_gid(c.second); + + its_gid_set.insert(its_gid); + + its_policy->credentials_ += std::make_pair( + boost::icl::interval<uid_t>::closed(its_uid, its_uid), its_gid_set); + its_policy->allow_who_ = true; + its_policy->allow_what_ = true; + + its_security->add_security_credentials(its_uid, its_gid, its_policy, get_client()); + } +} +#endif + +void routing_manager_client::on_client_assign_ack(const client_t &_client) { + + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_ASSIGNING) { + if (_client != VSOMEIP_CLIENT_UNSET) { + state_ = inner_state_type_e::ST_ASSIGNED; + + boost::system::error_code ec; + register_application_timer_.cancel(ec); + host_->set_client(_client); + + if (is_started_) { + init_receiver(); + if (receiver_) { + receiver_->start(); + + VSOMEIP_INFO << std::hex << "Client " << get_client() + << " (" << host_->get_name() + << ") successfully connected to routing ~> registering.."; + register_application(); + } else { + state_ = inner_state_type_e::ST_DEREGISTERED; + + host_->set_client(VSOMEIP_CLIENT_UNSET); + + sender_->restart(); + } + } + } else { + VSOMEIP_ERROR << "Didn't receive valid clientID! Won't register application."; + } + } else { + VSOMEIP_WARNING << "Client " << std::hex << get_client() + << " received another client identifier (" + << std::hex << _client + << "). Ignoring it. (" + << (int)state_ << ")"; + } +} + +void routing_manager_client::on_suspend() { + + VSOMEIP_INFO << __func__ << ": Application " + << std::hex << std::setw(4) << std::setfill('0') + << host_->get_client(); + + std::lock_guard<std::mutex> its_lock(remote_subscriber_count_mutex_); + + // Unsubscribe everything that is left over. + for (const auto &s : remote_subscriber_count_) { + for (const auto &i : s.second) { + for (const auto &e : i.second) + routing_manager_base::unsubscribe( + VSOMEIP_ROUTING_CLIENT, nullptr, + s.first, i.first, e.first, ANY_EVENT); + } + } + + // Remove all entries. + remote_subscriber_count_.clear(); +} + +} // namespace vsomeip_v3 diff --git a/implementation/routing/src/routing_manager_impl.cpp b/implementation/routing/src/routing_manager_impl.cpp index 07c0740..4ebca55 100644 --- a/implementation/routing/src/routing_manager_impl.cpp +++ b/implementation/routing/src/routing_manager_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -8,8 +8,9 @@ #include <memory> #include <sstream> #include <forward_list> +#include <thread> -#ifndef _WIN32 +#if defined(__linux__) || defined(ANDROID) #include <unistd.h> #include <cstdio> #include <time.h> @@ -30,10 +31,7 @@ #include "../include/routing_manager_stub.hpp" #include "../include/serviceinfo.hpp" #include "../../configuration/include/configuration.hpp" -#include "../../security/include/security.hpp" - #include "../../endpoints/include/endpoint_definition.hpp" -#include "../../endpoints/include/local_client_endpoint_impl.hpp" #include "../../endpoints/include/tcp_client_endpoint_impl.hpp" #include "../../endpoints/include/tcp_server_endpoint_impl.hpp" #include "../../endpoints/include/udp_client_endpoint_impl.hpp" @@ -42,13 +40,15 @@ #include "../../message/include/deserializer.hpp" #include "../../message/include/message_impl.hpp" #include "../../message/include/serializer.hpp" +#include "../../plugin/include/plugin_manager_impl.hpp" +#include "../../protocol/include/protocol.hpp" +#include "../../security/include/security.hpp" #include "../../service_discovery/include/constants.hpp" #include "../../service_discovery/include/defines.hpp" #include "../../service_discovery/include/runtime.hpp" #include "../../service_discovery/include/service_discovery.hpp" #include "../../utility/include/byteorder.hpp" #include "../../utility/include/utility.hpp" -#include "../../plugin/include/plugin_manager_impl.hpp" #ifdef USE_DLT #include "../../tracing/include/connector_impl.hpp" #endif @@ -89,11 +89,11 @@ routing_manager_impl::routing_manager_impl(routing_manager_host *_host) : } routing_manager_impl::~routing_manager_impl() { - utility::remove_lockfile(configuration_); - utility::reset_client_ids(); + utility::remove_lockfile(configuration_->get_network()); + utility::reset_client_ids(configuration_->get_network()); } -boost::asio::io_service & routing_manager_impl::get_io() { +boost::asio::io_context &routing_manager_impl::get_io() { return routing_manager_base::get_io(); } @@ -101,6 +101,34 @@ client_t routing_manager_impl::get_client() const { return routing_manager_base::get_client(); } +const vsomeip_sec_client_t *routing_manager_impl::get_sec_client() const { + + return (routing_manager_base::get_sec_client()); +} + +std::string routing_manager_impl::get_client_host() const { + return routing_manager_base::get_client_host(); +} + +void routing_manager_impl::set_client_host(const std::string &_client_host) { + routing_manager_base::set_client_host(_client_host); +} + +std::string routing_manager_impl::get_env(client_t _client) const { + + std::lock_guard<std::mutex> its_known_clients_lock(known_clients_mutex_); + return get_env_unlocked(_client); +} + +std::string routing_manager_impl::get_env_unlocked(client_t _client) const { + + auto find_client = known_clients_.find(_client); + if (find_client != known_clients_.end()) { + return (find_client->second); + } + return ""; +} + std::set<client_t> routing_manager_impl::find_local_clients(service_t _service, instance_t _instance) { return routing_manager_base::find_local_clients(_service, _instance); } @@ -109,18 +137,31 @@ client_t routing_manager_impl::find_local_client(service_t _service, instance_t return routing_manager_base::find_local_client(_service, _instance); } -bool routing_manager_impl::is_subscribe_to_any_event_allowed(credentials_t _credentials, client_t _client, +bool routing_manager_impl::is_subscribe_to_any_event_allowed( + const vsomeip_sec_client_t *_sec_client, client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup) { - return routing_manager_base::is_subscribe_to_any_event_allowed(_credentials, _client, + + return routing_manager_base::is_subscribe_to_any_event_allowed(_sec_client, _client, _service, _instance, _eventgroup); } +void routing_manager_impl::add_known_client(client_t _client, const std::string &_client_host) { + routing_manager_base::add_known_client(_client, _client_host); +} + +bool routing_manager_impl::is_routing_manager() const { + return true; +} + void routing_manager_impl::init() { routing_manager_base::init(ep_mgr_impl_); - // TODO: Only instantiate the stub if needed - stub_ = std::make_shared<routing_manager_stub>(this, configuration_); - stub_->init(); + if (configuration_->is_routing_enabled()) { + stub_ = std::make_shared<routing_manager_stub>(this, configuration_); + stub_->init(); + } else { + VSOMEIP_INFO << "Internal message routing disabled!"; + } if (configuration_->is_sd_enabled()) { VSOMEIP_INFO<< "Service Discovery enabled. Trying to load module."; @@ -162,7 +203,7 @@ void routing_manager_impl::init() { } void routing_manager_impl::start() { -#ifndef _WIN32 +#if defined(__linux__) || defined(ANDROID) boost::asio::ip::address its_multicast; try { its_multicast = boost::asio::ip::address::from_string(configuration_->get_sd_multicast()); @@ -172,6 +213,20 @@ void routing_manager_impl::start() { << "\". Please check your configuration."; } + std::stringstream its_netmask_or_prefix; + auto its_unicast = configuration_->get_unicast_address(); + if (its_unicast.is_v4()) + its_netmask_or_prefix << "netmask:" << configuration_->get_netmask().to_string(); + else + its_netmask_or_prefix << "prefix:" << configuration_->get_prefix(); + + VSOMEIP_INFO << "Client [" + << std::hex << std::setw(4) << std::setfill('0') + << get_client() + << "] routes unicast:" << its_unicast.to_string() + << ", " + << its_netmask_or_prefix.str(); + netlink_connector_ = std::make_shared<netlink_connector>( host_->get_io(), configuration_->get_unicast_address(), its_multicast); netlink_connector_->register_net_if_changes_handler( @@ -185,7 +240,8 @@ void routing_manager_impl::start() { } #endif - stub_->start(); + if (stub_) + stub_->start(); host_->on_state(state_type_e::ST_REGISTERED); if (configuration_->log_version()) { @@ -195,7 +251,7 @@ void routing_manager_impl::start() { version_log_timer_.async_wait(std::bind(&routing_manager_impl::log_version_timer_cbk, this, std::placeholders::_1)); } -#ifndef _WIN32 +#if defined(__linux__) || defined(ANDROID) if (configuration_->log_memory()) { std::lock_guard<std::mutex> its_lock(memory_log_timer_mutex_); boost::system::error_code ec; @@ -231,7 +287,7 @@ void routing_manager_impl::stop() { std::lock_guard<std::mutex> its_lock(local_services_mutex_); for (const auto& s : local_services_) { for (const auto& i : s.second) { - if (std::get<2>(i.second) == client_) { + if (std::get<2>(i.second) == get_client()) { its_services[s.first][i.first] = i.second; } } @@ -249,7 +305,7 @@ void routing_manager_impl::stop() { std::lock_guard<std::mutex> its_lock(version_log_timer_mutex_); version_log_timer_.cancel(); } -#ifndef _WIN32 +#if defined(__linux__) || defined(ANDROID) { boost::system::error_code ec; std::lock_guard<std::mutex> its_lock(memory_log_timer_mutex_); @@ -276,9 +332,10 @@ void routing_manager_impl::stop() { if (discovery_) discovery_->stop(); - stub_->stop(); + if (stub_) + stub_->stop(); - for (const auto& client : ep_mgr_->get_connected_clients()) { + for (const auto client : ep_mgr_->get_connected_clients()) { if (client != VSOMEIP_ROUTING_CLIENT) { remove_local(client, true); } @@ -317,7 +374,7 @@ bool routing_manager_impl::erase_offer_command(service_t _service, instance_t _i if (!found_service_instance->second.empty()) { // check for other commands to be processed auto its_command = found_service_instance->second.front(); - if (std::get<0>(its_command) == VSOMEIP_OFFER_SERVICE) { + if (std::get<0>(its_command) == uint8_t(protocol::id_e::OFFER_SERVICE_ID)) { io_.post([&, its_command, _service, _instance](){ offer_service(std::get<1>(its_command), _service, _instance, std::get<2>(its_command), std::get<3>(its_command), false); @@ -355,7 +412,8 @@ bool routing_manager_impl::offer_service(client_t _client, // only queue commands if method was NOT called via erase_offer_command() if (_must_queue) { - if (!insert_offer_command(_service, _instance, VSOMEIP_OFFER_SERVICE, + if (!insert_offer_command(_service, _instance, + uint8_t(protocol::id_e::OFFER_SERVICE_ID), _client, _major, _minor)) { return false; } @@ -364,15 +422,8 @@ bool routing_manager_impl::offer_service(client_t _client, // Check if the application hosted by routing manager is allowed to offer // offer_service requests of local proxies are checked in rms::on:message if (_client == get_client()) { -#ifdef _WIN32 - std::uint32_t its_routing_uid = ANY_UID; - std::uint32_t its_routing_gid = ANY_GID; -#else - std::uint32_t its_routing_uid = getuid(); - std::uint32_t its_routing_gid = getgid(); -#endif - if (!security::get()->is_offer_allowed(its_routing_uid, its_routing_gid, - _client, _service, _instance)) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_offer( + get_sec_client(), _service, _instance)) { VSOMEIP_WARNING << "routing_manager_impl::offer_service: " << std::hex << "Security: Client 0x" << _client << " isn't allowed to offer the following service/instance " @@ -412,7 +463,8 @@ bool routing_manager_impl::offer_service(client_t _client, && ps.instance_ == _instance && ps.major_ == _major) { insert_subscription(ps.service_, ps.instance_, - ps.eventgroup_, ps.event_, client_, &its_already_subscribed_events); + ps.eventgroup_, ps.event_, nullptr, + get_client(), &its_already_subscribed_events); #if 0 VSOMEIP_ERROR << __func__ << ": event=" @@ -425,8 +477,9 @@ bool routing_manager_impl::offer_service(client_t _client, send_pending_subscriptions(_service, _instance, _major); } - stub_->on_offer_service(_client, _service, _instance, _major, _minor); - on_availability(_service, _instance, true, _major, _minor); + if (stub_) + stub_->on_offer_service(_client, _service, _instance, _major, _minor); + on_availability(_service, _instance, availability_state_e::AS_AVAILABLE, _major, _minor); erase_offer_command(_service, _instance); return true; } @@ -451,7 +504,8 @@ void routing_manager_impl::stop_offer_service(client_t _client, << " (" << std::boolalpha << _must_queue << ")"; if (_must_queue) { - if (!insert_offer_command(_service, _instance, VSOMEIP_STOP_OFFER_SERVICE, + if (!insert_offer_command(_service, _instance, + uint8_t(protocol::id_e::STOP_OFFER_SERVICE_ID), _client, _major, _minor)) { return; } @@ -476,8 +530,9 @@ void routing_manager_impl::stop_offer_service(client_t _client, } on_stop_offer_service(_client, _service, _instance, _major, _minor); - stub_->on_stop_offer_service(_client, _service, _instance, _major, _minor); - on_availability(_service, _instance, false, _major, _minor); + if (stub_) + stub_->on_stop_offer_service(_client, _service, _instance, _major, _minor); + on_availability(_service, _instance, availability_state_e::AS_UNAVAILABLE, _major, _minor); } else { VSOMEIP_WARNING << __func__ << " received STOP_OFFER(" << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" @@ -503,7 +558,7 @@ void routing_manager_impl::request_service(client_t _client, service_t _service, auto its_info = find_service(_service, _instance); if (!its_info) { - requested_service_add(_client, _service, _instance, _major, _minor); + add_requested_service(_client, _service, _instance, _major, _minor); if (discovery_) { if (!configuration_->is_local_service(_service, _instance)) { // Non local service instance ~> tell SD to find it! @@ -525,7 +580,7 @@ void routing_manager_impl::request_service(client_t _client, service_t _service, || DEFAULT_MINOR == its_info->get_minor() || _minor == ANY_MINOR)) { if(!its_info->is_local()) { - requested_service_add(_client, _service, _instance, _major, _minor); + add_requested_service(_client, _service, _instance, _major, _minor); if (discovery_) { // Non local service instance ~> tell SD to find it! discovery_->request_service(_service, _instance, _major, @@ -538,12 +593,15 @@ void routing_manager_impl::request_service(client_t _client, service_t _service, } if (_client == get_client()) { - stub_->create_local_receiver(); + if (stub_) + stub_->create_local_receiver(); + + protocol::service its_request(_service, _instance, _major, _minor); + std::set<protocol::service> requests; + requests.insert(its_request); - service_data_t request = { _service, _instance, _major, _minor }; - std::set<service_data_t> requests; - requests.insert(request); - stub_->handle_requests(_client, requests); + if (stub_) + stub_->handle_requests(_client, requests); } } @@ -560,7 +618,7 @@ void routing_manager_impl::release_service(client_t _client, service_t _service, remove_pending_subscription(_service, _instance, 0xFFFF, ANY_EVENT); } routing_manager_base::release_service(_client, _service, _instance); - requested_service_remove(_client, _service, _instance); + remove_requested_service(_client, _service, _instance, ANY_MAJOR, ANY_MINOR); std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); if (its_info && !its_info->is_local()) { @@ -582,9 +640,11 @@ void routing_manager_impl::release_service(client_t _client, service_t _service, } } -void routing_manager_impl::subscribe(client_t _client, uid_t _uid, gid_t _gid, - service_t _service, instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, event_t _event) { +void routing_manager_impl::subscribe( + client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter) { VSOMEIP_INFO << "SUBSCRIBE(" << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" @@ -600,21 +660,25 @@ void routing_manager_impl::subscribe(client_t _client, uid_t _uid, gid_t _gid, _eventgroup, _event, subscription_state_e::IS_SUBSCRIBING); #endif auto self = shared_from_this(); - host_->on_subscription(_service, _instance, _eventgroup, _client, _uid, _gid, true, - [this, self, _client, _uid, _gid, _service, _instance, _eventgroup, - _event, _major] + host_->on_subscription(_service, _instance, _eventgroup, _client, + _sec_client, get_env(_client), true, + [this, self, _client, _sec_client, _service, _instance, _eventgroup, + _major, _event, _filter] (const bool _subscription_accepted) { (void) ep_mgr_->find_or_create_local(_client); if (!_subscription_accepted) { - stub_->send_subscribe_nack(_client, _service, _instance, _eventgroup, _event); + if (stub_) + stub_->send_subscribe_nack(_client, _service, _instance, _eventgroup, _event); VSOMEIP_INFO << "Subscription request from client: 0x" << std::hex << _client << std::dec << " for eventgroup: 0x" << _eventgroup << " rejected from application handler."; return; - } else { + } else if (stub_) { stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup, _event); } - routing_manager_base::subscribe(_client, _uid, _gid, _service, _instance, _eventgroup, _major, _event); + routing_manager_base::subscribe(_client, _sec_client, + _service, _instance, _eventgroup, _major, + _event, _filter); #ifdef VSOMEIP_ENABLE_COMPAT send_pending_notify_ones(_service, _instance, _eventgroup, _client); routing_manager_base::erase_incoming_subscription_state(_client, _service, _instance, @@ -631,7 +695,7 @@ void routing_manager_impl::subscribe(client_t _client, uid_t _uid, gid_t _gid, // handle_subscription_state. std::unique_lock<std::mutex> its_critical(remote_subscription_state_mutex_); bool inserted = insert_subscription(_service, _instance, _eventgroup, - _event, _client, &its_already_subscribed_events); + _event, _filter, _client, &its_already_subscribed_events); const bool subscriber_is_rm_host = (get_client() == _client); if (inserted) { if (0 == its_local_client) { @@ -654,17 +718,20 @@ void routing_manager_impl::subscribe(client_t _client, uid_t _uid, gid_t _gid, } } else { its_critical.unlock(); - if (is_available(_service, _instance, _major)) { + if (is_available(_service, _instance, _major) && stub_) { stub_->send_subscribe(ep_mgr_->find_local(_service, _instance), - _client, _service, _instance, _eventgroup, _major, _event, - PENDING_SUBSCRIPTION_ID); + _client, _service, _instance, _eventgroup, _major, + _event, _filter, PENDING_SUBSCRIPTION_ID); } } } if (subscriber_is_rm_host) { std::lock_guard<std::mutex> ist_lock(pending_subscription_mutex_); subscription_data_t subscription = { - _service, _instance, _eventgroup, _major, _event, _uid, _gid + _service, _instance, + _eventgroup, _major, + _event, _filter, + *_sec_client }; pending_subscriptions_.insert(subscription); } @@ -674,8 +741,10 @@ void routing_manager_impl::subscribe(client_t _client, uid_t _uid, gid_t _gid, } } -void routing_manager_impl::unsubscribe(client_t _client, uid_t _uid, gid_t _gid, - service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { +void routing_manager_impl::unsubscribe( + client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event) { VSOMEIP_INFO << "UNSUBSCRIBE(" << std::hex << std::setw(4) << std::setfill('0') << _client << "): [" @@ -702,7 +771,8 @@ void routing_manager_impl::unsubscribe(client_t _client, uid_t _uid, gid_t _gid, } if (discovery_) { - host_->on_subscription(_service, _instance, _eventgroup, _client, _uid, _gid, false, + host_->on_subscription(_service, _instance, _eventgroup, _client, + _sec_client, get_env(_client), false, [](const bool _subscription_accepted){ (void)_subscription_accepted; }); if (0 == find_local_client(_service, _instance)) { if (get_client() == _client) { @@ -728,10 +798,11 @@ void routing_manager_impl::unsubscribe(client_t _client, uid_t _uid, gid_t _gid, if (get_client() == _client) { std::lock_guard<std::mutex> ist_lock(pending_subscription_mutex_); remove_pending_subscription(_service, _instance, _eventgroup, _event); - stub_->send_unsubscribe( - ep_mgr_->find_local(_service, _instance), - _client, _service, _instance, _eventgroup, _event, - PENDING_SUBSCRIPTION_ID); + if (stub_) + stub_->send_unsubscribe( + ep_mgr_->find_local(_service, _instance), + _client, _service, _instance, _eventgroup, _event, + PENDING_SUBSCRIPTION_ID); } } ep_mgr_impl_->clear_multicast_endpoints(_service, _instance); @@ -742,15 +813,16 @@ void routing_manager_impl::unsubscribe(client_t _client, uid_t _uid, gid_t _gid, } bool routing_manager_impl::send(client_t _client, - std::shared_ptr<message> _message) { - return routing_manager_base::send(_client, _message); + std::shared_ptr<message> _message, bool _force) { + + return routing_manager_base::send(_client, _message, _force); } bool routing_manager_impl::send(client_t _client, const byte_t *_data, length_t _size, instance_t _instance, bool _reliable, - client_t _bound_client, - credentials_t _credentials, - uint8_t _status_check, bool _sent_from_remote) { + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _sent_from_remote, bool _force) { + bool is_sent(false); if (_size > VSOMEIP_MESSAGE_TYPE_POS) { std::shared_ptr<endpoint> its_target; @@ -775,15 +847,14 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, } else if (is_notification && _client && !is_service_discovery) { // Selective notifications! if (_client == get_client()) { #ifdef USE_DLT - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); #endif - deliver_message(_data, _size, _instance, _reliable, _bound_client, _credentials, _status_check, _sent_from_remote); + deliver_message(_data, _size, _instance, _reliable, + _bound_client, _sec_client, + _status_check, _sent_from_remote); return true; } its_target = find_local(_client); @@ -794,16 +865,15 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, if ((is_request && its_client == get_client()) || (is_response && find_local_client(its_service, _instance) == get_client()) || (is_notification && find_local_client(its_service, _instance) == VSOMEIP_ROUTING_CLIENT)) { - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); trace::header its_header; if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); } #endif - is_sent = send_local(its_target, get_client(), _data, _size, _instance, _reliable, VSOMEIP_SEND, _status_check); + is_sent = send_local(its_target, get_client(), _data, _size, _instance, + _reliable, protocol::id_e::SEND_ID, _status_check); } else { // Check whether hosting application should get the message // If not, check routes to external @@ -811,7 +881,8 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, || (find_local_client(its_service, _instance) == host_->get_client() && is_request)) { // TODO: Find out how to handle session id here - is_sent = deliver_message(_data, _size, _instance, _reliable, VSOMEIP_ROUTING_CLIENT, _credentials, _status_check); + is_sent = deliver_message(_data, _size, _instance, _reliable, + VSOMEIP_ROUTING_CLIENT, _sec_client, _status_check); } else { e2e_buffer its_buffer; @@ -844,13 +915,10 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, its_service, _instance, _reliable); if (its_target) { #ifdef USE_DLT - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); #endif is_sent = its_target->send(_data, _size); } else { @@ -868,7 +936,8 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, std::shared_ptr<serviceinfo> its_info(find_service(its_service, _instance)); if (its_info || is_service_discovery) { if (is_notification && !is_service_discovery) { - send_local_notification(get_client(), _data, _size, _instance, _reliable, _status_check); + (void)send_local_notification(get_client(), _data, _size, _instance, + _reliable, _status_check, _force); method_t its_method = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN], _data[VSOMEIP_METHOD_POS_MAX]); std::shared_ptr<event> its_event = find_event(its_service, _instance, its_method); @@ -930,13 +999,10 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, } #ifdef USE_DLT if (has_sent) { - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(nullptr, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); } #endif } @@ -962,13 +1028,10 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, (sd_info_ ? sd_info_->get_endpoint(false) : nullptr) : its_info->get_endpoint(_reliable); if (its_target) { #ifdef USE_DLT - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_target, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); #endif is_sent = its_target->send(_data, _size); } else { @@ -1009,6 +1072,7 @@ bool routing_manager_impl::send_to( const client_t _client, const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message> _message) { + bool is_sent(false); std::shared_ptr<serializer> its_serializer(get_serializer()); @@ -1050,19 +1114,17 @@ bool routing_manager_impl::send_to( bool routing_manager_impl::send_to( const std::shared_ptr<endpoint_definition> &_target, const byte_t *_data, uint32_t _size, instance_t _instance) { + std::shared_ptr<endpoint> its_endpoint = ep_mgr_impl_->find_server_endpoint( _target->get_remote_port(), _target->is_reliable()); if (its_endpoint) { #ifdef USE_DLT - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_endpoint, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); #else (void) _instance; #endif @@ -1081,13 +1143,10 @@ bool routing_manager_impl::send_via_sd( if (its_endpoint) { #ifdef USE_DLT if (tc_->is_sd_enabled()) { - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_endpoint, true, 0x0)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); } #endif @@ -1136,13 +1195,15 @@ void routing_manager_impl::register_shadow_event(client_t _client, service_t _service, instance_t _instance, event_t _notifier, const std::set<eventgroup_t> &_eventgroups, event_type_e _type, - reliability_type_e _reliability, bool _is_provided) { + reliability_type_e _reliability, bool _is_provided, bool _is_cyclic) { + routing_manager_base::register_event(_client, _service, _instance, _notifier, _eventgroups, _type, _reliability, - std::chrono::milliseconds::zero(), false, true, - nullptr, + (_is_cyclic ? std::chrono::milliseconds(1) + : std::chrono::milliseconds::zero()), + false, true, nullptr, _is_provided, true); } @@ -1172,7 +1233,7 @@ void routing_manager_impl::notify_one(service_t _service, instance_t _instance, if (its_event) { std::set<std::shared_ptr<endpoint_definition> > its_targets; const auto its_reliability = its_event->get_reliability(); - for (const auto& g : its_event->get_eventgroups()) { + for (const auto g : its_event->get_eventgroups()) { const auto its_eventgroup = find_eventgroup(_service, _instance, g); if (its_eventgroup) { const auto its_subscriptions = its_eventgroup->get_remote_subscriptions(); @@ -1197,7 +1258,7 @@ void routing_manager_impl::notify_one(service_t _service, instance_t _instance, if (its_targets.size() > 0) { for (const auto &its_target : its_targets) { - its_event->set_payload(_payload, _client, its_target, _force); + its_event->set_payload(_payload, _client, its_target); } } } else { @@ -1209,11 +1270,11 @@ void routing_manager_impl::notify_one(service_t _service, instance_t _instance, } void routing_manager_impl::on_availability(service_t _service, instance_t _instance, - bool _is_available, major_version_t _major, minor_version_t _minor) { + availability_state_e _state, major_version_t _major, minor_version_t _minor) { // insert subscriptions of routing manager into service discovery // to send SubscribeEventgroup after StopOffer / Offer was received - if (_is_available) { + if (_state == availability_state_e::AS_AVAILABLE) { if (discovery_) { const client_t its_local_client = find_local_client(_service, _instance); // remote service @@ -1241,7 +1302,7 @@ void routing_manager_impl::on_availability(service_t _service, instance_t _insta } } } - host_->on_availability(_service, _instance, _is_available, _major, _minor); + host_->on_availability(_service, _instance, _state, _major, _minor); } @@ -1273,7 +1334,7 @@ bool routing_manager_impl::offer_service_remotely(service_t _service, << "]"; ret = false; } else { - if (!stub_->send_provided_event_resend_request(its_offering_client, + if (stub_ && !stub_->send_provided_event_resend_request(its_offering_client, pending_remote_offer_add(_service, _instance))) { VSOMEIP_ERROR << __func__ << ": Couldn't send event resend" << "request to client 0x" << std::hex << std::setw(4) @@ -1332,7 +1393,7 @@ bool routing_manager_impl::stop_offer_service_remotely(service_t _service, clear_remote_subscriber(_service, _instance); if (discovery_ && its_info) { - discovery_->stop_offer_service(its_info); + discovery_->stop_offer_service(its_info, true); its_info->set_endpoint(std::shared_ptr<endpoint>(), _reliable); } } else { @@ -1344,7 +1405,7 @@ bool routing_manager_impl::stop_offer_service_remotely(service_t _service, // ensure to not send StopOffer for endpoint on which the service is // still offered its_copied_info->set_endpoint(std::shared_ptr<endpoint>(), !_reliable); - discovery_->stop_offer_service(its_copied_info); + discovery_->stop_offer_service(its_copied_info, true); } } @@ -1353,8 +1414,8 @@ bool routing_manager_impl::stop_offer_service_remotely(service_t _service, } void routing_manager_impl::on_message(const byte_t *_data, length_t _size, - endpoint *_receiver, const boost::asio::ip::address &_destination, - client_t _bound_client, credentials_t _credentials, + endpoint *_receiver, bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, const boost::asio::ip::address &_remote_address, std::uint16_t _remote_port) { #if 0 @@ -1369,10 +1430,12 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, method_t its_method; uint8_t its_check_status = e2e::profile_interface::generic_check_status::E2E_OK; instance_t its_instance(0x0); + message_type_e its_message_type; #ifdef USE_DLT bool is_forwarded(true); #endif if (_size >= VSOMEIP_SOMEIP_HEADER_SIZE) { + its_message_type = static_cast<message_type_e>(_data[VSOMEIP_MESSAGE_TYPE_POS]); its_service = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_SERVICE_POS_MIN], _data[VSOMEIP_SERVICE_POS_MAX]); if (its_service == VSOMEIP_SD_SERVICE) { @@ -1381,7 +1444,11 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, if (discovery_ && its_method == sd::method) { if (configuration_->get_sd_port() == _remote_port) { if (!_remote_address.is_unspecified()) { - discovery_->on_message(_data, _size, _remote_address, _destination); + // ACL check SD message + if(!is_acl_message_allowed(_receiver, its_service, ANY_INSTANCE, _remote_address)) { + return; + } + discovery_->on_message(_data, _size, _remote_address, _is_multicast); } else { VSOMEIP_ERROR << "Ignored SD message from unknown address."; } @@ -1391,7 +1458,7 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, } } } else { - if(_destination.is_multicast()) { + if (_is_multicast) { its_instance = ep_mgr_impl_->find_instance_multicast(its_service, _remote_address); } else { its_instance = ep_mgr_impl_->find_instance(its_service, _receiver); @@ -1417,7 +1484,7 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, } //Ignore messages with invalid message type if(_size >= VSOMEIP_MESSAGE_TYPE_POS) { - if(!utility::is_valid_message_type(static_cast<message_type_e>(_data[VSOMEIP_MESSAGE_TYPE_POS]))) { + if(!utility::is_valid_message_type(its_message_type)) { VSOMEIP_ERROR << "Ignored SomeIP message with invalid message type."; return; } @@ -1436,7 +1503,7 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, } // Security checks if enabled! - if (security::get()->is_enabled()) { + if (configuration_->is_security_enabled()) { if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) { client_t requester = VSOMEIP_BYTES_TO_WORD( _data[VSOMEIP_CLIENT_POS_MIN], @@ -1456,7 +1523,7 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, << " which is already used locally ~> Skip message!"; return; } - if (!security::get()->is_remote_client_allowed()) { + if (!configuration_->is_remote_access_allowed()) { // check if policy allows remote requests. VSOMEIP_WARNING << "routing_manager_impl::on_message: " << std::hex << "Security: Remote client with client ID 0x" << requester @@ -1485,19 +1552,22 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, } #endif } + + // ACL check message + if(!is_acl_message_allowed(_receiver, its_service, its_instance, _remote_address)) { + return; + } + // Common way of message handling #ifdef USE_DLT is_forwarded = #endif on_message(its_service, its_instance, _data, _size, _receiver->is_reliable(), - _bound_client, _credentials, its_check_status, true); + _bound_client, _sec_client, its_check_status, true); } } #ifdef USE_DLT if (is_forwarded) { - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; const boost::asio::ip::address_v4 its_remote_address = _remote_address.is_v4() ? _remote_address.to_v4() : @@ -1508,19 +1578,16 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, trace::protocol_e::udp; its_header.prepare(its_remote_address, _remote_port, its_protocol, false, its_instance); - tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, - its_data_size); + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); } #endif } -bool routing_manager_impl::on_message( - service_t _service, instance_t _instance, - const byte_t *_data, length_t _size, - bool _reliable, client_t _bound_client, - credentials_t _credentials, - uint8_t _check_status, - bool _is_from_remote) { +bool routing_manager_impl::on_message(service_t _service, instance_t _instance, + const byte_t *_data, length_t _size, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _check_status, bool _is_from_remote) { #if 0 std::stringstream msg; msg << "rmi::on_message(" @@ -1541,15 +1608,29 @@ bool routing_manager_impl::on_message( _data[VSOMEIP_CLIENT_POS_MAX]); } +#if 0 + // ACL message check for local test purpouse + std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); + if (its_info) { + std::shared_ptr<endpoint> _receiver = its_info->get_endpoint(_reliable); + if (_receiver && _receiver.get()) { + if(!is_acl_message_allowed(_receiver.get(), _service, _instance, + boost::asio::ip::address_v4::from_string("127.0.0.1"))) { + return false; + } + } + } +#endif + if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { is_forwarded = deliver_notification(_service, _instance, _data, _size, - _reliable, _bound_client, _credentials, _check_status, _is_from_remote); + _reliable, _bound_client, _sec_client, _check_status, _is_from_remote); } else if (its_client == host_->get_client()) { deliver_message(_data, _size, _instance, - _reliable, _bound_client, _credentials, _check_status, _is_from_remote); + _reliable, _bound_client, _sec_client, _check_status, _is_from_remote); } else { send(its_client, _data, _size, _instance, _reliable, - _bound_client, _credentials, _check_status, _is_from_remote); //send to proxy + _bound_client, _sec_client, _check_status, _is_from_remote, false); //send to proxy } return is_forwarded; } @@ -1689,7 +1770,7 @@ void routing_manager_impl::on_stop_offer_service(client_t _client, service_t _se if (discovery_) { if (its_info->get_major() == _major && its_info->get_minor() == _minor) { - discovery_->stop_offer_service(its_info); + discovery_->stop_offer_service(its_info, true); } } del_routing_info(_service, _instance, (its_reliable_endpoint != nullptr), @@ -1782,11 +1863,11 @@ void routing_manager_impl::on_stop_offer_service(client_t _client, service_t _se } bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, - instance_t _instance, bool _reliable, client_t _bound_client, credentials_t _credentials, + instance_t _instance, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, uint8_t _status_check, bool _is_from_remote) { + bool is_delivered(false); - std::uint32_t its_sender_uid = std::get<0>(_credentials); - std::uint32_t its_sender_gid = std::get<1>(_credentials); auto its_deserializer = get_deserializer(); its_deserializer->set_data(_data, _size); @@ -1798,8 +1879,9 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, its_message->set_instance(_instance); its_message->set_reliable(_reliable); its_message->set_check_result(_status_check); - its_message->set_uid(std::get<0>(_credentials)); - its_message->set_gid(std::get<1>(_credentials)); + if (_sec_client) + its_message->set_sec_client(*_sec_client); + its_message->set_env(get_env(_bound_client)); if (!_is_from_remote) { if (utility::is_notification(its_message->get_message_type())) { @@ -1814,9 +1896,9 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, << " ~> Skip message!"; return false; } else { - if (!security::get()->is_client_allowed(own_uid_, own_gid_, - get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(get_sec_client(), + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() << " : routing_manager_impl::deliver_message: " << " isn't allowed to receive a notification from service/instance/event " @@ -1828,7 +1910,8 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, } } } else if (utility::is_request(its_message->get_message_type())) { - if (security::get()->is_enabled() + if (configuration_->is_security_enabled() + && configuration_->is_local_routing() && its_message->get_client() != _bound_client) { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() << " : routing_manager_impl::deliver_message:" @@ -1841,9 +1924,9 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, return false; } - if (!security::get()->is_client_allowed(its_sender_uid, its_sender_gid, - its_message->get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(_sec_client, + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() << " : routing_manager_impl::deliver_message: " << " isn't allowed to send a request to service/instance/method " @@ -1864,9 +1947,9 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, << " ~> Skip message!"; return false; } else { - if (!security::get()->is_client_allowed(own_uid_, own_gid_, - get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(get_sec_client(), + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() << " : routing_manager_impl::deliver_message: " << " isn't allowed to receive a response from service/instance/method " @@ -1879,7 +1962,7 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, } } } else { - if (!security::get()->is_remote_client_allowed()) { + if (!configuration_->is_remote_access_allowed()) { // if the message is from remote, check if // policy allows remote requests. VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() @@ -1892,9 +1975,9 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, << " ~> Skip message!"; return false; } else if (utility::is_notification(its_message->get_message_type())) { - if (!security::get()->is_client_allowed(own_uid_, own_gid_, - get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member(get_sec_client(), + its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() << " : routing_manager_impl::deliver_message: " << " isn't allowed to receive a notification from service/instance/event " @@ -1918,10 +2001,10 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, bool routing_manager_impl::deliver_notification( service_t _service, instance_t _instance, - const byte_t *_data, length_t _length, - bool _reliable, client_t _bound_client, - credentials_t _credentials, + const byte_t *_data, length_t _length, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, uint8_t _status_check, bool _is_from_remote) { + event_t its_event_id = VSOMEIP_BYTES_TO_WORD( _data[VSOMEIP_METHOD_POS_MIN], _data[VSOMEIP_METHOD_POS_MAX]); client_t its_client_id = VSOMEIP_BYTES_TO_WORD( @@ -1934,7 +2017,7 @@ bool routing_manager_impl::deliver_notification( // no subscribers for this specific event / check subscriptions // to other events of the event's eventgroups bool cache_event = false; - for (const auto& eg : its_event->get_eventgroups()) { + for (const auto eg : its_event->get_eventgroups()) { std::shared_ptr<eventgroupinfo> egi = find_eventgroup(_service, _instance, eg); if (egi) { for (const auto &e : egi->get_events()) { @@ -1957,37 +2040,30 @@ bool routing_manager_impl::deliver_notification( return true; // as there is nothing to do } } - const uint32_t its_length(utility::get_payload_size(_data, _length)); - if (its_length != _length - VSOMEIP_FULL_HEADER_SIZE) { - VSOMEIP_ERROR << "Message length mismatch, dropping message!"; - return false; - } - std::shared_ptr<payload> its_payload - = runtime::get()->create_payload(&_data[VSOMEIP_PAYLOAD_POS], - its_length); - if (!its_event->set_payload_dont_notify(its_payload)) { - // do not forward the notification as it was filtered - return false; - } } + auto its_length = utility::get_payload_size(_data, _length); + auto its_payload = runtime::get()->create_payload( + &_data[VSOMEIP_PAYLOAD_POS], its_length); + // incoming events statistics (void) insert_event_statistics( - _service, - _instance, - its_event_id, - utility::get_payload_size(_data, _length)); + _service, _instance, its_event_id, its_length); + // Ignore the filter for messages coming from other local clients + // as the filter was already applied there. + auto its_subscribers + = its_event->update_and_get_filtered_subscribers(its_payload, _is_from_remote); if (its_event->get_type() != event_type_e::ET_SELECTIVE_EVENT) { - for (const auto& its_local_client : its_event->get_subscribers()) { + for (const auto its_local_client : its_subscribers) { if (its_local_client == host_->get_client()) { deliver_message(_data, _length, _instance, _reliable, - _bound_client, _credentials, _status_check, _is_from_remote); + _bound_client, _sec_client, _status_check, _is_from_remote); } else { std::shared_ptr<endpoint> its_local_target = find_local(its_local_client); if (its_local_target) { send_local(its_local_target, VSOMEIP_ROUTING_CLIENT, - _data, _length, _instance, _reliable, VSOMEIP_SEND, _status_check); + _data, _length, _instance, _reliable, protocol::id_e::SEND_ID, _status_check); } } } @@ -1998,20 +2074,20 @@ bool routing_manager_impl::deliver_notification( if (its_client_id == VSOMEIP_ROUTING_CLIENT) its_client_id = get_client(); - auto its_subscribers = its_event->get_subscribers(); if (its_subscribers.find(its_client_id) != its_subscribers.end()) { if (its_client_id == host_->get_client()) { deliver_message(_data, _length, _instance, _reliable, - _bound_client, _credentials, _status_check, _is_from_remote); + _bound_client, _sec_client, _status_check, _is_from_remote); } else { std::shared_ptr<endpoint> its_local_target = find_local(its_client_id); if (its_local_target) { send_local(its_local_target, VSOMEIP_ROUTING_CLIENT, - _data, _length, _instance, _reliable, VSOMEIP_SEND, _status_check); + _data, _length, _instance, _reliable, protocol::id_e::SEND_ID, _status_check); } } } } + } else { VSOMEIP_WARNING << __func__ << ": Event [" << std::hex << std::setw(4) << std::setfill('0') << _service << "." @@ -2048,10 +2124,10 @@ std::shared_ptr<endpoint> routing_manager_impl::create_service_discovery_endpoin its_service_endpoint->add_default_target(VSOMEIP_SD_SERVICE, _address, _port); if (!_reliable) { - auto its_udp_server_endpoint_impl = std::dynamic_pointer_cast< + auto its_server_endpoint = std::dynamic_pointer_cast< udp_server_endpoint_impl>(its_service_endpoint); - if (its_udp_server_endpoint_impl) - its_udp_server_endpoint_impl->join(_address); + if (its_server_endpoint) + its_server_endpoint->join(_address); } } else { VSOMEIP_ERROR<< "Service Discovery endpoint could not be created. " @@ -2102,6 +2178,37 @@ routing_manager_impl::get_offered_service_instances(service_t _service) const { return its_instances; } +bool routing_manager_impl::is_acl_message_allowed(endpoint *_receiver, + service_t _service, instance_t _instance, + const boost::asio::ip::address &_remote_address) const { + if (message_acceptance_handler_ && _receiver) { + // Check the ACL whitelist rules if shall accepts the message + + message_acceptance_t message_acceptance { +#if VSOMEIP_BOOST_VERSION < 106600 + static_cast<uint32_t>(_remote_address.to_v4().to_ulong()), _receiver->get_local_port(), +#else + _remote_address.to_v4().to_uint(), _receiver->get_local_port(), +#endif + _receiver->is_local(), _service, _instance + }; + if (!message_acceptance_handler_(message_acceptance)) { + VSOMEIP_WARNING << "Message from " << _remote_address.to_string() + << std::hex << " with service/instance " << _instance << "/" + << _instance << " was rejected by the ACL check."; + return false; + } +#if 0 + else { + VSOMEIP_INFO << "Message from " << _remote_address.to_string() + << std::hex << " with service/instance " << _instance << "/" + << _instance << " was accepted by the ACL check."; + } +#endif + } + return true; +} + /////////////////////////////////////////////////////////////////////////////// // PRIVATE /////////////////////////////////////////////////////////////////////////////// @@ -2166,20 +2273,7 @@ void routing_manager_impl::remove_local(client_t _client, bool _remove_uid) { } routing_manager_base::remove_local(_client, clients_subscriptions, _remove_uid); - std::forward_list<std::pair<service_t, instance_t>> services_to_release_; - { - std::lock_guard<std::mutex> its_lock(requested_services_mutex_); - auto its_client = requested_services_.find(_client); - if (its_client != requested_services_.end()) { - for (const auto& its_service : its_client->second) { - for (const auto& its_instance : its_service.second) { - services_to_release_.push_front( - { its_service.first, its_instance.first }); - } - } - } - } - for (const auto &s : services_to_release_) { + for (const auto &s : get_requested_services(_client)) { release_service(_client, s.first, s.second); } } @@ -2210,7 +2304,7 @@ void routing_manager_impl::add_routing_info( std::lock_guard<std::mutex> its_lock(routing_state_mutex_); if (routing_state_ == routing_state_e::RS_SUSPENDED) { - VSOMEIP_INFO << "rmi::" << __func__ << " We are suspened --> do nothing."; + VSOMEIP_INFO << "rmi::" << __func__ << " We are suspended --> do nothing."; return; } @@ -2280,89 +2374,63 @@ void routing_manager_impl::add_routing_info( { bool connected(false); std::lock_guard<std::mutex> its_lock(requested_services_mutex_); - for(const auto &client_id : requested_services_) { - auto found_service = client_id.second.find(_service); - if (found_service != client_id.second.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - for (const auto &major_minor_pair : found_instance->second) { - if ((major_minor_pair.first == _major - || _major == DEFAULT_MAJOR - || major_minor_pair.first == ANY_MAJOR) - && (major_minor_pair.second <= _minor - || _minor == DEFAULT_MINOR - || major_minor_pair.second == ANY_MINOR)) { - // SWS_SD_00376 establish TCP connection to service - // service is marked as available later in on_connect() - if(!connected) { - if (udp_inserted) { - // atomically create reliable and unreliable endpoint - ep_mgr_impl_->find_or_create_remote_client( - _service, _instance); - } else { - ep_mgr_impl_->find_or_create_remote_client( - _service, _instance, true); - } - connected = true; - } - its_info->add_client(client_id.first); - break; - } - } + for (const client_t its_client : get_requesters_unlocked( + _service, _instance, _major, _minor)) { + // SWS_SD_00376 establish TCP connection to service + // service is marked as available later in on_connect() + if (!connected) { + if (udp_inserted) { + // atomically create reliable and unreliable endpoint + ep_mgr_impl_->find_or_create_remote_client( + _service, _instance); + } else { + ep_mgr_impl_->find_or_create_remote_client( + _service, _instance, true); } + connected = true; } + its_info->add_client(its_client); } } } else if (_reliable_port != ILLEGAL_PORT && is_reliable_known) { std::lock_guard<std::mutex> its_lock(requested_services_mutex_); - bool connected(false); - for(const auto &client_id : requested_services_) { - auto found_service = client_id.second.find(_service); - if (found_service != client_id.second.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - for (const auto &major_minor_pair : found_instance->second) { - if ((major_minor_pair.first == _major - || _major == DEFAULT_MAJOR - || major_minor_pair.first == ANY_MAJOR) - && (major_minor_pair.second <= _minor - || _minor == DEFAULT_MINOR - || major_minor_pair.second == ANY_MINOR)) { - std::shared_ptr<endpoint> ep = its_info->get_endpoint(true); - if (ep) { - if (ep->is_established() && - !stub_->contained_in_routing_info( - VSOMEIP_ROUTING_CLIENT, _service, _instance, - its_info->get_major(), - its_info->get_minor())) { - on_availability(_service, _instance, - true, its_info->get_major(), its_info->get_minor()); - stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, - _service, _instance, - its_info->get_major(), - its_info->get_minor()); - if (discovery_) { - discovery_->on_endpoint_connected( - _service, _instance, ep); - } - } - } else { - // no endpoint yet, but requested -> create one - - // SWS_SD_00376 establish TCP connection to service - // service is marked as available later in on_connect() - if (!connected) { - ep_mgr_impl_->find_or_create_remote_client( - _service, _instance, true); - connected = true; - } - its_info->add_client(client_id.first); - } - break; - } + if (has_requester_unlocked(_service, _instance, _major, _minor)) { + std::shared_ptr<endpoint> ep = its_info->get_endpoint(true); + if (ep) { + if (ep->is_established() && + stub_ && + !stub_->contained_in_routing_info( + VSOMEIP_ROUTING_CLIENT, _service, _instance, + its_info->get_major(), + its_info->get_minor())) { + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, + its_info->get_major(), its_info->get_minor()); + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, + _service, _instance, + its_info->get_major(), + its_info->get_minor()); + if (discovery_) { + discovery_->on_endpoint_connected( + _service, _instance, ep); } } + } else { + // no endpoint yet, but requested -> create one + + // SWS_SD_00376 establish TCP connection to service + // service is marked as available later in on_connect() + ep_mgr_impl_->find_or_create_remote_client( + _service, _instance, true); + for (const client_t its_client : get_requesters_unlocked( + _service, _instance, _major, _minor)) { + its_info->add_client(its_client); + } } + } else { + on_availability(_service, _instance, + availability_state_e::AS_OFFERED, + its_info->get_major(), its_info->get_minor()); } } @@ -2375,38 +2443,28 @@ void routing_manager_impl::add_routing_info( { bool connected(false); std::lock_guard<std::mutex> its_lock(requested_services_mutex_); - for (const auto &client_id : requested_services_) { - const auto found_service = client_id.second.find(_service); - if (found_service != client_id.second.end()) { - const auto found_instance = found_service->second.find( - _instance); - if (found_instance != found_service->second.end()) { - for (const auto &major_minor_pair : found_instance->second) { - if ((major_minor_pair.first == _major - || _major == DEFAULT_MAJOR - || major_minor_pair.first == ANY_MAJOR) - && (major_minor_pair.second <= _minor - || _minor == DEFAULT_MINOR - || major_minor_pair.second - == ANY_MINOR)) { - if(!connected) { - ep_mgr_impl_->find_or_create_remote_client(_service, _instance, - false); - connected = true; - } - its_info->add_client(client_id.first); - break; - } - } - } + for (const client_t its_client : get_requesters_unlocked( + _service, _instance, _major, _minor)) { + if (!connected) { + ep_mgr_impl_->find_or_create_remote_client(_service, _instance, + false); + connected = true; } + its_info->add_client(its_client); } } } if (!is_reliable_known && !tcp_inserted) { // UDP only service can be marked as available instantly - on_availability(_service, _instance, true, _major, _minor); - stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, _major, _minor); + if (has_requester_unlocked(_service, _instance, _major, _minor)) { + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, _major, _minor); + if (stub_) + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, _major, _minor); + } else { + on_availability(_service, _instance, + availability_state_e::AS_OFFERED, _major, _minor); + } } if (discovery_) { std::shared_ptr<endpoint> ep = its_info->get_endpoint(false); @@ -2416,43 +2474,32 @@ void routing_manager_impl::add_routing_info( } } else if (_unreliable_port != ILLEGAL_PORT && is_unreliable_known) { std::lock_guard<std::mutex> its_lock(requested_services_mutex_); - for(const auto &client_id : requested_services_) { - auto found_service = client_id.second.find(_service); - if (found_service != client_id.second.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - for (const auto &major_minor_pair : found_instance->second) { - if ((major_minor_pair.first == _major - || _major == DEFAULT_MAJOR - || major_minor_pair.first == ANY_MAJOR) - && (major_minor_pair.second <= _minor - || _minor == DEFAULT_MINOR - || major_minor_pair.second == ANY_MINOR)) { - if (_reliable_port == ILLEGAL_PORT && !is_reliable_known && - !stub_->contained_in_routing_info( - VSOMEIP_ROUTING_CLIENT, _service, _instance, - its_info->get_major(), - its_info->get_minor())) { - on_availability(_service, _instance, - true, its_info->get_major(), its_info->get_minor()); - stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, - _service, _instance, - its_info->get_major(), - its_info->get_minor()); - if (discovery_) { - std::shared_ptr<endpoint> ep = its_info->get_endpoint(false); - if (ep && ep->is_established()) { - discovery_->on_endpoint_connected( - _service, _instance, - ep); - } - } - } - break; - } + if (has_requester_unlocked(_service, _instance, _major, _minor)) { + if (_reliable_port == ILLEGAL_PORT && !is_reliable_known && + stub_ && + !stub_->contained_in_routing_info( + VSOMEIP_ROUTING_CLIENT, _service, _instance, + its_info->get_major(), + its_info->get_minor())) { + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, + its_info->get_major(), its_info->get_minor()); + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, + _service, _instance, + its_info->get_major(), + its_info->get_minor()); + if (discovery_) { + std::shared_ptr<endpoint> ep = its_info->get_endpoint(false); + if (ep && ep->is_established()) { + discovery_->on_endpoint_connected( + _service, _instance, + ep); } } } + } else { + on_availability(_service, _instance, + availability_state_e::AS_OFFERED, _major, _minor); } } } @@ -2464,10 +2511,12 @@ void routing_manager_impl::del_routing_info(service_t _service, instance_t _inst if(!its_info) return; - on_availability(_service, _instance, false, - its_info->get_major(), its_info->get_minor()); - stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + on_availability(_service, _instance, + availability_state_e::AS_UNAVAILABLE, its_info->get_major(), its_info->get_minor()); + if (stub_) + stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + its_info->get_major(), its_info->get_minor()); // Implicit unsubscribe std::vector<std::shared_ptr<event>> its_events; @@ -2482,7 +2531,7 @@ void routing_manager_impl::del_routing_info(service_t _service, instance_t _inst // do no longer exist and the last received payload is no // longer valid. for (auto &its_event : its_eventgroup.second->get_events()) { - const auto& its_subscribers = its_event->get_subscribers(); + const auto its_subscribers = its_event->get_subscribers(); for (const auto its_subscriber : its_subscribers) { if (its_subscriber != get_client()) { its_event->remove_subscriber( @@ -2747,24 +2796,12 @@ void routing_manager_impl::init_routing_info() { = configuration_->get_reliable_port(i.first, i.second); uint16_t its_unreliable_port = configuration_->get_unreliable_port(i.first, i.second); - major_version_t its_major - = configuration_->get_major_version(i.first, i.second); - minor_version_t its_minor - = configuration_->get_minor_version(i.first, i.second); - ttl_t its_ttl - = configuration_->get_ttl(i.first, i.second); if (its_reliable_port != ILLEGAL_PORT || its_unreliable_port != ILLEGAL_PORT) { - VSOMEIP_INFO << "Adding static remote service [" - << std::hex << std::setw(4) << std::setfill('0') - << i.first << "." << i.second - << std::dec << ":" << +its_major << "." << its_minor - << "]"; - add_routing_info(i.first, i.second, - its_major, its_minor, its_ttl, + DEFAULT_MAJOR, DEFAULT_MINOR, DEFAULT_TTL, its_address, its_reliable_port, its_address, its_unreliable_port); @@ -3009,7 +3046,7 @@ void routing_manager_impl::on_subscribe_ack(client_t _client, host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); } - } else { + } else if (stub_) { stub_->send_subscribe_ack(its_subscriber, _service, _instance, _eventgroup, _event); } @@ -3025,20 +3062,13 @@ std::shared_ptr<endpoint> routing_manager_impl::find_or_create_remote_client( void routing_manager_impl::on_subscribe_nack(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - event_t _event, remote_subscription_id_t _id, bool _simulated) { + event_t _event, remote_subscription_id_t _id) { (void)_event; // TODO: Remove completely? auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); if (its_eventgroup) { auto its_subscription = its_eventgroup->get_remote_subscription(_id); if (its_subscription) { - if (_simulated) { - // method was called because a subscription for unoffered - // service was received. Therefore, remove the remote_subscription - // from the eventgroupinfo to ensure subsequent similar - // subscriptions are handled like a new/unknown subscription - its_eventgroup->remove_remote_subscription(_id); - } its_subscription->set_client_state(_client, remote_subscription_state_e::SUBSCRIPTION_NACKED); @@ -3167,13 +3197,10 @@ void routing_manager_impl::send_error(return_code_e _return_code, its_endpoint_def->is_reliable()); if (its_endpoint) { #ifdef USE_DLT - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - trace::header its_header; if (its_header.prepare(its_endpoint, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); + _data, _size); #else (void) _instance; #endif @@ -3233,6 +3260,14 @@ routing_manager_impl::expire_subscriptions(bool _force) { auto its_subscriptions = its_eventgroup.second->get_remote_subscriptions(); for (auto &s : its_subscriptions) { + if(!s) { + VSOMEIP_ERROR << __func__ + << ": Remote subscription is NULL for eventgroup [" + << std::hex << std::setw(4) << std::setfill('0') << its_service.first << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance.first << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup.first << "]"; + continue; + } for (auto its_client : s->get_clients()) { if (_force) { its_expired_subscriptions[s].insert(its_client); @@ -3429,13 +3464,10 @@ bool routing_manager_impl::handle_local_offer_service(client_t _client, service_ } if (!already_pinged) { // find out endpoint of previously offering application - std::shared_ptr<local_client_endpoint_base_impl> - its_old_endpoint - = std::dynamic_pointer_cast<local_client_endpoint_base_impl>( - find_local(its_stored_client)); + auto its_old_endpoint = find_local(its_stored_client); if (its_old_endpoint) { std::lock_guard<std::mutex> its_lock(pending_offers_mutex_); - if(stub_->send_ping(its_stored_client)) { + if (stub_ && stub_->send_ping(its_stored_client)) { pending_offers_[_service][_instance] = std::make_tuple(_major, _minor, _client, its_stored_client); @@ -3557,10 +3589,11 @@ void routing_manager_impl::register_client_error_handler(client_t _client, } void routing_manager_impl::handle_client_error(client_t _client) { - VSOMEIP_INFO << "Client 0x" << std::hex << get_client() + VSOMEIP_INFO << "routing_manager_impl::" << __func__ << " Client 0x" << std::hex << get_client() << " handles a client error(" << std::hex << _client << ")"; if (stub_) - stub_->update_registration(_client, registration_type_e::DEREGISTER_ON_ERROR); + stub_->update_registration(_client, registration_type_e::DEREGISTER_ON_ERROR, + boost::asio::ip::address(), 0); std::forward_list<std::tuple<client_t, service_t, instance_t, major_version_t, minor_version_t>> its_offers; @@ -3619,17 +3652,18 @@ std::shared_ptr<endpoint_manager_impl> routing_manager_impl::get_endpoint_manage void routing_manager_impl::send_subscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, - event_t _event) { + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter) { auto endpoint = ep_mgr_->find_local(_service, _instance); - if (endpoint) { + if (endpoint && stub_) { stub_->send_subscribe(endpoint, _client, - _service, _instance, _eventgroup, _major, _event, PENDING_SUBSCRIPTION_ID); + _service, _instance, + _eventgroup, _major, + _event, _filter, + PENDING_SUBSCRIPTION_ID); } } void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { - - // Ignore setting to the current routing state { std::lock_guard<std::mutex> its_lock(routing_state_mutex_); if (routing_state_ == _routing_state) { @@ -3640,7 +3674,7 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { routing_state_ = _routing_state; } - if(discovery_) { + if (discovery_) { switch (_routing_state) { case routing_state_e::RS_SUSPENDED: { @@ -3656,6 +3690,7 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { // remove all remote subscriptions to remotely offered services on this node expire_subscriptions(true); + std::vector<std::shared_ptr<serviceinfo>> _service_infos; // send StopOffer messages for remotely offered services on this node for (const auto &its_service : get_offered_services()) { for (const auto &its_instance : its_service.second) { @@ -3666,9 +3701,16 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { << std::hex << std::setw(4) << std::setfill('0') << its_instance.first << " still offered by " << std::hex << std::setw(4) << std::setfill('0') << its_client; } - discovery_->stop_offer_service(its_instance.second); + // collect stop offers to be sent out + if (discovery_->stop_offer_service(its_instance.second, false)) { + _service_infos.push_back(its_instance.second); + } } } + // send collected stop offers packed together in one ore multiple SD messages + discovery_->send_collected_stop_offers(_service_infos); + _service_infos.clear(); + { std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); remote_subscription_state_.clear(); @@ -3746,7 +3788,7 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { for (const auto &its_instance : its_service.second) { if (host_->get_configuration()->is_someip( its_service.first, its_instance.first)) { - discovery_->stop_offer_service(its_instance.second); + discovery_->stop_offer_service(its_instance.second, true); } } } @@ -3791,7 +3833,7 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { } void routing_manager_impl::on_net_interface_or_route_state_changed( - bool _is_interface, std::string _if, bool _available) { + bool _is_interface, const std::string &_if, bool _available) { std::lock_guard<std::mutex> its_lock(pending_sd_offers_mutex_); auto log_change_message = [&_if, _available, _is_interface](bool _warning) { std::stringstream ss; @@ -3864,36 +3906,184 @@ void routing_manager_impl::start_ip_routing() { VSOMEIP_INFO << VSOMEIP_ROUTING_READY_MESSAGE; } -void routing_manager_impl::requested_service_add(client_t _client, - service_t _service, - instance_t _instance, - major_version_t _major, - minor_version_t _minor) { +void +routing_manager_impl::add_requested_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); - requested_services_[_client][_service][_instance].insert({ _major, _minor }); + requested_services_[_service][_instance][_major][_minor].insert(_client); } -void routing_manager_impl::requested_service_remove(client_t _client, - service_t _service, - instance_t _instance) { +void +routing_manager_impl::remove_requested_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); - auto found_client = requested_services_.find(_client); - if (found_client != requested_services_.end()) { - auto found_service = found_client->second.find(_service); - if (found_service != found_client->second.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - // delete all requested major/minor versions - found_service->second.erase(_instance); - if (!found_service->second.size()) { - found_client->second.erase(_service); - if (!found_client->second.size()) { - requested_services_.erase(_client); + + using minor_map_t = std::map<minor_version_t, std::set<client_t> >; + using major_map_t = std::map<major_version_t, minor_map_t>; + using instance_map_t = std::map<instance_t, major_map_t>; + + auto delete_client = [&_client]( + minor_map_t::iterator& _minor_iter, + const major_map_t::iterator& _parent_major_iter) { + if (_minor_iter->second.erase(_client)) { // client was requester + if (_minor_iter->second.empty()) { + // client was last requester of this minor version + _minor_iter = _parent_major_iter->second.erase(_minor_iter); + } else { // there are still other requesters of this minor version + ++_minor_iter; + } + } else { // client wasn't requester + ++_minor_iter; + } + }; + + auto handle_minor = [&_minor, &delete_client]( + major_map_t::iterator& _major_iter, + const instance_map_t::iterator& _parent_instance_iter) { + if (_minor == ANY_MINOR) { + for (auto minor_iter = _major_iter->second.begin(); + minor_iter != _major_iter->second.end(); ) { + delete_client(minor_iter, _major_iter); + } + } else { + auto found_minor = _major_iter->second.find(_minor); + if (found_minor != _major_iter->second.end()) { + delete_client(found_minor, _major_iter); + } + } + if (_major_iter->second.empty()) { + // client was last requester of this major version + _major_iter = _parent_instance_iter->second.erase(_major_iter); + } else { + ++_major_iter; + } + }; + + auto found_service = requested_services_.find(_service); + if (found_service != requested_services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + if (_major == ANY_MAJOR) { + for (auto major_iter = found_instance->second.begin(); + major_iter != found_instance->second.end();) { + handle_minor(major_iter, found_instance); + } + } else { + auto found_major = found_instance->second.find(_major); + if (found_major != found_instance->second.end()) { + handle_minor(found_major, found_instance); + } + } + if (found_instance->second.empty()) { + // client was last requester of this instance + found_service->second.erase(found_instance); + if (found_service->second.empty()) { + // client was last requester of this service + requested_services_.erase(found_service); + } + } + } + } +} + +std::vector<std::pair<service_t, instance_t> > +routing_manager_impl::get_requested_services(client_t _client) { + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); + std::vector<std::pair<service_t, instance_t>> its_requests; + for (const auto& service : requested_services_) { + for (const auto& instance : service.second) { + bool requested = false; + for (const auto& major : instance.second) { + for (const auto& minor : major.second) { + if (minor.second.find(_client) != minor.second.end()) { + requested = true; + break; + } + } + if (requested) { + break; + } + } + if (requested) { + its_requests.push_back( + std::make_pair(service.first, instance.first)); + break; + } + } + } + return (its_requests); +} + +std::set<client_t> +routing_manager_impl::get_requesters(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); + return (get_requesters_unlocked(_service, _instance, _major, _minor)); +} + +std::set<client_t> +routing_manager_impl::get_requesters_unlocked( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + std::set<client_t> its_requesters; + + auto found_service = requested_services_.find(_service); + if (found_service != requested_services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto& its_major : found_instance->second) { + if (its_major.first == _major || _major == DEFAULT_MAJOR + || its_major.first == ANY_MAJOR) { + for (const auto &its_minor : its_major.second) { + if (its_minor.first <= _minor + || _minor == DEFAULT_MINOR + || its_minor.first == ANY_MINOR) { + if (its_requesters.empty()) { + its_requesters = its_minor.second; + } else { + its_requesters.insert(its_minor.second.cbegin(), + its_minor.second.cend()); + } + } } } } } } + return (its_requesters); +} + +bool +routing_manager_impl::has_requester_unlocked( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + auto found_service = requested_services_.find(_service); + if (found_service != requested_services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto& its_major : found_instance->second) { + if (its_major.first == _major || _major == DEFAULT_MAJOR + || its_major.first == ANY_MAJOR) { + for (const auto &its_minor : its_major.second) { + if (its_minor.first <= _minor + || _minor == DEFAULT_MINOR + || its_minor.first == ANY_MINOR) { + + return (true); + } + } + } + } + } + } + return (false); } std::set<eventgroup_t> @@ -3934,7 +4124,7 @@ void routing_manager_impl::clear_targets_and_pending_sub_from_eventgroups( // longer valid. for (auto &its_event : its_eventgroup.second->get_events()) { const auto its_subscribers = its_event->get_subscribers(); - for (const auto& its_subscriber : its_subscribers) { + for (const auto its_subscriber : its_subscribers) { if (its_subscriber != get_client()) { its_event->remove_subscriber( its_eventgroup.first, its_subscriber); @@ -3994,7 +4184,9 @@ void routing_manager_impl::call_sd_endpoint_connected( bool routing_manager_impl::create_placeholder_event_and_subscribe( service_t _service, instance_t _instance, eventgroup_t _eventgroup, - event_t _event, client_t _client) { + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter, + client_t _client) { + bool is_inserted(false); // we received a event which was not yet requested/offered // create a placeholder field until someone requests/offers this event with @@ -4047,7 +4239,8 @@ bool routing_manager_impl::create_placeholder_event_and_subscribe( std::shared_ptr<event> its_event = find_event(_service, _instance, _event); if (its_event) { - is_inserted = its_event->add_subscriber(_eventgroup, _client, false); + is_inserted = its_event->add_subscriber( + _eventgroup, _filter, _client, false); } return is_inserted; } @@ -4097,7 +4290,7 @@ void routing_manager_impl::handle_subscription_state( // Subscription already acknowledged! if (_client == get_client()) { host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); - } else { + } else if (stub_) { stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup, _event); } } @@ -4140,11 +4333,10 @@ void routing_manager_impl::memory_log_timer_cbk( if (_error) { return; } -#ifndef _WIN32 + +#if defined(__linux__) || defined(ANDROID) static const std::uint32_t its_pagesize = static_cast<std::uint32_t>(getpagesize() / 1024); -#else - static const std::uint32_t its_pagesize = 4096 / 1024; -#endif + std::FILE *its_file = std::fopen("/proc/self/statm", "r"); if (!its_file) { VSOMEIP_ERROR << "memory_log_timer_cbk: couldn't open:" @@ -4166,11 +4358,10 @@ void routing_manager_impl::memory_log_timer_cbk( << std::string(std::strerror(errno)); } std::fclose(its_file); -#ifndef _WIN32 + struct timespec cputs, monots; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &cputs); clock_gettime(CLOCK_MONOTONIC, &monots); -#endif VSOMEIP_INFO << "memory usage: " << "VmSize " << std::dec << its_size * its_pagesize << " kB, " @@ -4178,12 +4369,11 @@ void routing_manager_impl::memory_log_timer_cbk( << "shared pages " << std::dec << its_sharedpages * its_pagesize << " kB, " << "text " << std::dec << its_text * its_pagesize << " kB, " << "data " << std::dec << its_data * its_pagesize << " kB " -#ifndef _WIN32 << "| monotonic time: " << std::dec << monots.tv_sec << "." << std::dec << monots.tv_nsec << " cpu time: " << std::dec << cputs.tv_sec << "." << std::dec << cputs.tv_nsec -#endif ; +#endif { std::lock_guard<std::mutex> its_lock(memory_log_timer_mutex_); @@ -4278,8 +4468,9 @@ void routing_manager_impl::send_subscription( const remote_subscription_id_t _id) { if (host_->get_client() == _offering_client) { auto self = shared_from_this(); - for (const auto& its_client : _clients) { - host_->on_subscription(_service, _instance, _eventgroup, its_client, own_uid_, own_gid_, true, + for (const auto its_client : _clients) { + host_->on_subscription(_service, _instance, _eventgroup, its_client, + get_sec_client(), get_env(its_client), true, [this, self, _service, _instance, _eventgroup, its_client, _id] (const bool _is_accepted) { try { @@ -4288,7 +4479,7 @@ void routing_manager_impl::send_subscription( &routing_manager_stub_host::on_subscribe_nack, std::dynamic_pointer_cast<routing_manager_stub_host>(shared_from_this()), its_client, _service, _instance, - _eventgroup, ANY_EVENT, _id, false); + _eventgroup, ANY_EVENT, _id); io_.post(its_callback); } else { const auto its_callback = std::bind( @@ -4304,15 +4495,15 @@ void routing_manager_impl::send_subscription( }); } } else { // service hosted by local client - for (const auto& its_client : _clients) { - if (!stub_->send_subscribe(find_local(_offering_client), its_client, - _service, _instance, _eventgroup, _major, ANY_EVENT, _id)) { + for (const auto its_client : _clients) { + if (stub_ && !stub_->send_subscribe(find_local(_offering_client), its_client, + _service, _instance, _eventgroup, _major, ANY_EVENT, nullptr, _id)) { try { const auto its_callback = std::bind( &routing_manager_stub_host::on_subscribe_nack, std::dynamic_pointer_cast<routing_manager_stub_host>(shared_from_this()), its_client, _service, _instance, _eventgroup, - ANY_EVENT, _id, true); + ANY_EVENT, _id); io_.post(its_callback); } catch (const std::exception &e) { VSOMEIP_ERROR << __func__ << e.what(); @@ -4378,7 +4569,8 @@ void routing_manager_impl::on_resend_provided_events_response( } void routing_manager_impl::print_stub_status() const { - stub_->print_endpoint_status(); + if (stub_) + stub_->print_endpoint_status(); } void routing_manager_impl::service_endpoint_connected( @@ -4389,9 +4581,12 @@ void routing_manager_impl::service_endpoint_connected( if (!_unreliable_only) { // Mark only TCP-only and TCP+UDP services available here // UDP-only services are already marked as available in add_routing_info - on_availability(_service, _instance, true, _major, _minor); - stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, _major, _minor); + if (stub_) + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + _major, _minor); } std::shared_ptr<boost::asio::steady_timer> its_timer = @@ -4413,9 +4608,12 @@ void routing_manager_impl::service_endpoint_disconnected( service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, const std::shared_ptr<endpoint>& _endpoint) { (void)_endpoint; - on_availability(_service, _instance, false, _major, _minor); - stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + on_availability(_service, _instance, + availability_state_e::AS_UNAVAILABLE, _major, _minor); + if (stub_) + stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + _major, _minor); VSOMEIP_WARNING << __func__ << ": lost connection to remote service: [" << std::hex << std::setw(4) << std::setfill('0') << _service << "." << std::hex << std::setw(4) << std::setfill('0') << _instance << "]"; @@ -4432,9 +4630,9 @@ routing_manager_impl::send_unsubscription(client_t _offering_client, if (host_->get_client() == _offering_client) { auto self = shared_from_this(); - for (const auto& its_client : _removed) { - host_->on_subscription(_service, _instance, - _eventgroup, its_client, own_uid_, own_gid_, false, + for (const auto its_client : _removed) { + host_->on_subscription(_service, _instance, _eventgroup, + its_client, get_sec_client(), get_env(its_client),false, [this, self, _service, _instance, _eventgroup, its_client, _id] (const bool _is_accepted) { @@ -4452,8 +4650,8 @@ routing_manager_impl::send_unsubscription(client_t _offering_client, ); } } else { - for (const auto& its_client : _removed) { - if (!stub_->send_unsubscribe(find_local(_offering_client), its_client, + for (const auto its_client : _removed) { + if (stub_ && !stub_->send_unsubscribe(find_local(_offering_client), its_client, _service, _instance, _eventgroup, ANY_EVENT, _id)) { try { const auto its_callback = std::bind( @@ -4480,19 +4678,21 @@ routing_manager_impl::send_expired_subscription(client_t _offering_client, auto self = shared_from_this(); for (const auto its_client : _removed) { host_->on_subscription(_service, _instance, - _eventgroup, its_client, own_uid_, own_gid_, false, + _eventgroup, its_client, get_sec_client(), get_env(its_client), false, [] (const bool _subscription_accepted){ (void)_subscription_accepted; }); } } else { for (const auto its_client : _removed) { - stub_->send_expired_subscription(find_local(_offering_client), its_client, - _service, _instance, _eventgroup, ANY_EVENT, _id); + if (stub_) + stub_->send_expired_subscription(find_local(_offering_client), its_client, + _service, _instance, _eventgroup, ANY_EVENT, _id); } } } +#ifndef VSOMEIP_DISABLE_SECURITY bool routing_manager_impl::update_security_policy_configuration( uint32_t _uid, uint32_t _gid, @@ -4518,6 +4718,7 @@ routing_manager_impl::remove_security_policy_configuration( return (false); } +#endif // !VSOMEIP_DISABLE_SECURITY bool routing_manager_impl::insert_event_statistics(service_t _service, instance_t _instance, method_t _method, length_t _length) { @@ -4527,7 +4728,7 @@ bool routing_manager_impl::insert_event_statistics(service_t _service, instance_ const auto its_tuple = std::make_tuple(_service, _instance, _method); const auto its_main_s = message_statistics_.find(its_tuple); if (its_main_s != message_statistics_.end()) { - // increase counter and calculate moving avergae for payload length + // increase counter and calculate moving average for payload length its_main_s->second.avg_length_ = (its_main_s->second.avg_length_ * its_main_s->second.counter_ + _length) / (its_main_s->second.counter_ + 1); @@ -4537,10 +4738,10 @@ bool routing_manager_impl::insert_event_statistics(service_t _service, instance_ // check list for entry with least counter value uint32_t its_min_count(0xFFFFFFFF); auto its_tuple_to_discard = std::make_tuple(0xFFFF, 0xFFFF, 0xFFFF); - for (const auto &it : message_statistics_) { - if (it.second.counter_ < its_min_count) { - its_min_count = it.second.counter_; - its_tuple_to_discard = it.first; + for (const auto &s : message_statistics_) { + if (s.second.counter_ < its_min_count) { + its_min_count = s.second.counter_; + its_tuple_to_discard = s.first; } } if (its_min_count != 0xFFFF @@ -4580,7 +4781,7 @@ void routing_manager_impl::statistics_log_timer_cbk(boost::system::error_code co { std::lock_guard<std::mutex> its_lock(message_statistics_mutex_); for (const auto &s : message_statistics_) { - if (s.second.counter_ / (its_interval / 1000) >= its_min_freq) { + if (s.second.counter_ / (its_interval / 1000) > its_min_freq) { uint16_t its_subscribed(0); std::shared_ptr<event> its_event = find_event(std::get<0>(s.first), std::get<1>(s.first), std::get<2>(s.first)); if (its_event) { @@ -4621,9 +4822,86 @@ void routing_manager_impl::statistics_log_timer_cbk(boost::system::error_code co } } +bool +routing_manager_impl::get_guest(client_t _client, + boost::asio::ip::address &_address, port_t &_port) const { + + return (routing_manager_base::get_guest(_client, _address, _port)); +} + +void +routing_manager_impl::add_guest(client_t _client, + const boost::asio::ip::address &_address, port_t _port) { + + routing_manager_base::add_guest(_client, _address, _port); +} + +void +routing_manager_impl::remove_guest(client_t _client) { + + routing_manager_base::remove_guest(_client); +} + void routing_manager_impl::send_suspend() const { + if (stub_) + stub_->send_suspend(); +} + +void routing_manager_impl::clear_local_services() { + + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + local_services_.clear(); +} + +void routing_manager_impl::register_message_acceptance_handler( + const message_acceptance_handler_t& _handler) { + message_acceptance_handler_ = _handler; +} + +void +routing_manager_impl::remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port) { + + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::shared_ptr<eventgroupinfo> > > >its_eventgroups; + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + its_eventgroups = eventgroups_; + } + for (const auto &its_service : its_eventgroups) { + for (const auto &its_instance : its_service.second) { + for (const auto &its_eventgroup : its_instance.second) { + const auto its_info = its_eventgroup.second; + for (auto its_subscription + : its_info->get_remote_subscriptions()) { + auto its_definition = its_subscription->get_reliable(); + if (its_definition + && its_definition->get_address() == _remote_address + && its_definition->get_port() == _remote_port + && its_definition->get_remote_port() == _local_port) { + + VSOMEIP_INFO << __func__ + << ": Removing subscription to [" + << std::hex << std::setw(4) << std::setfill('0') + << its_info->get_service() << "." + << std::hex << std::setw(4) << std::setfill('0') + << its_info->get_instance() << "." + << std::hex << std::setw(4) << std::setfill('0') + << its_info->get_eventgroup() + << "] from target " + << its_definition->get_address() << ":" + << std::dec << its_definition->get_port() + << " reliable=true"; - stub_->send_suspend(); + on_remote_unsubscribe(its_subscription); + } + } + } + } + } } } // namespace vsomeip_v3 diff --git a/implementation/routing/src/routing_manager_proxy.cpp b/implementation/routing/src/routing_manager_proxy.cpp deleted file mode 100644 index 06573a5..0000000 --- a/implementation/routing/src/routing_manager_proxy.cpp +++ /dev/null @@ -1,2734 +0,0 @@ -// Copyright (C) 2014-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 <climits> -#include <iomanip> -#include <mutex> -#include <unordered_set> -#include <future> -#include <forward_list> - -#include <vsomeip/constants.hpp> -#include <vsomeip/runtime.hpp> -#include <vsomeip/internal/logger.hpp> - -#include "../include/event.hpp" -#include "../include/routing_manager_host.hpp" -#include "../include/routing_manager_proxy.hpp" -#include "../../configuration/include/configuration.hpp" -#include "../../security/include/policy.hpp" -#include "../../security/include/security_impl.hpp" - -#include "../../endpoints/include/local_client_endpoint_impl.hpp" -#include "../../endpoints/include/local_server_endpoint_impl.hpp" -#include "../../message/include/deserializer.hpp" -#include "../../message/include/message_impl.hpp" -#include "../../message/include/serializer.hpp" -#include "../../service_discovery/include/runtime.hpp" -#include "../../utility/include/byteorder.hpp" -#include "../../utility/include/utility.hpp" -#ifdef USE_DLT -#include "../../tracing/include/connector_impl.hpp" -#endif - -namespace vsomeip_v3 { - -routing_manager_proxy::routing_manager_proxy(routing_manager_host *_host, - bool _client_side_logging, - const std::set<std::tuple<service_t, instance_t> > & _client_side_logging_filter) : - routing_manager_base(_host), - is_connected_(false), - is_started_(false), - state_(inner_state_type_e::ST_DEREGISTERED), - sender_(nullptr), - receiver_(nullptr), - register_application_timer_(io_), - request_debounce_timer_ (io_), - request_debounce_timer_running_(false), - client_side_logging_(_client_side_logging), - client_side_logging_filter_(_client_side_logging_filter) -{ -} - -routing_manager_proxy::~routing_manager_proxy() { -} - -void routing_manager_proxy::init() { - routing_manager_base::init(std::make_shared<endpoint_manager_base>(this, io_, configuration_)); - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - sender_ = ep_mgr_->create_local(VSOMEIP_ROUTING_CLIENT); - } -} - -void routing_manager_proxy::start() { - is_started_ = true; - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (!sender_) { - // application has been stopped and started again - sender_ = ep_mgr_->create_local(VSOMEIP_ROUTING_CLIENT); - } - if (sender_) { - sender_->start(); - } - } -} - -void routing_manager_proxy::stop() { - std::unique_lock<std::mutex> its_lock(state_mutex_); - if (state_ == inner_state_type_e::ST_REGISTERING) { - register_application_timer_.cancel(); - } - - const std::chrono::milliseconds its_timeout(configuration_->get_shutdown_timeout()); - while (state_ == inner_state_type_e::ST_REGISTERING) { - std::cv_status status = state_condition_.wait_for(its_lock, its_timeout); - if (status == std::cv_status::timeout) { - VSOMEIP_WARNING << std::hex << client_ << " registering timeout on stop"; - break; - } - } - - if (state_ == inner_state_type_e::ST_REGISTERED) { - deregister_application(); - // Waiting de-register acknowledge to synchronize shutdown - while (state_ == inner_state_type_e::ST_REGISTERED) { - std::cv_status status = state_condition_.wait_for(its_lock, its_timeout); - if (status == std::cv_status::timeout) { - VSOMEIP_WARNING << std::hex << client_ << " couldn't deregister application - timeout"; - break; - } - } - } - is_started_ = false; - its_lock.unlock(); - - { - std::lock_guard<std::mutex> its_lock(request_timer_mutex_); - request_debounce_timer_.cancel(); - } - - if (receiver_) { - receiver_->stop(); - } - receiver_ = nullptr; - - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->stop(); - } - // delete the sender - sender_ = nullptr; - } - - for (const auto& client : ep_mgr_->get_connected_clients()) { - if (client != VSOMEIP_ROUTING_CLIENT) { - remove_local(client, true); - } - } - - std::stringstream its_client; - its_client << utility::get_base_path(configuration_) << std::hex << client_; -#ifdef _WIN32 - ::_unlink(its_client.str().c_str()); -#else - if (-1 == ::unlink(its_client.str().c_str())) { - VSOMEIP_ERROR<< "routing_manager_proxy::stop unlink failed (" - << its_client.str() << "): "<< std::strerror(errno); - } -#endif -} - -std::shared_ptr<configuration> routing_manager_proxy::get_configuration() const { - return host_->get_configuration(); -} - -bool routing_manager_proxy::offer_service(client_t _client, - service_t _service, instance_t _instance, - major_version_t _major, minor_version_t _minor) { - - if(!routing_manager_base::offer_service(_client, _service, _instance, _major, _minor)) { - VSOMEIP_WARNING << "routing_manager_proxy::offer_service," - << "routing_manager_base::offer_service returned false"; - return false; - } - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - if (state_ == inner_state_type_e::ST_REGISTERED) { - send_offer_service(_client, _service, _instance, _major, _minor); - } - service_data_t offer = { _service, _instance, _major, _minor }; - pending_offers_.insert(offer); - } - return true; -} - -void routing_manager_proxy::send_offer_service(client_t _client, - service_t _service, instance_t _instance, - major_version_t _major, minor_version_t _minor) { - (void)_client; - - byte_t its_command[VSOMEIP_OFFER_SERVICE_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_OFFER_SERVICE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_OFFER_SERVICE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, - sizeof(client_)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4] = _major; - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5], &_minor, - sizeof(_minor)); - - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } -} - -void routing_manager_proxy::stop_offer_service(client_t _client, - service_t _service, instance_t _instance, - major_version_t _major, minor_version_t _minor) { - - (void)_client; - - { - // Hold the mutex to ensure no placeholder event is created inbetween. - std::lock_guard<std::mutex> its_lock(stop_mutex_); - - routing_manager_base::stop_offer_service(_client, _service, _instance, _major, _minor); - clear_remote_subscriber_count(_service, _instance); - - // Note: The last argument does not matter here as a proxy - // does not manage endpoints to the external network. - clear_service_info(_service, _instance, false); - } - - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - if (state_ == inner_state_type_e::ST_REGISTERED) { - byte_t its_command[VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_STOP_OFFER_SERVICE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, - sizeof(client_)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4] = _major; - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5], &_minor, - sizeof(_minor)); - - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } - } - auto it = pending_offers_.begin(); - while (it != pending_offers_.end()) { - if (it->service_ == _service - && it->instance_ == _instance) { - break; - } - it++; - } - if (it != pending_offers_.end()) pending_offers_.erase(it); - } -} - -void routing_manager_proxy::request_service(client_t _client, - service_t _service, instance_t _instance, - major_version_t _major, minor_version_t _minor) { - routing_manager_base::request_service(_client, - _service, _instance, _major, _minor); - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - size_t request_debouncing_time = configuration_->get_request_debouncing(host_->get_name()); - service_data_t request = { _service, _instance, _major, _minor }; - if (!request_debouncing_time) { - if (state_ == inner_state_type_e::ST_REGISTERED) { - std::set<service_data_t> requests; - requests.insert(request); - send_request_services(requests); - } - requests_.insert(request); - } else { - requests_to_debounce_.insert(request); - std::lock_guard<std::mutex> 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<routing_manager_proxy>(shared_from_this()), - std::placeholders::_1)); - } - } - } -} - -void routing_manager_proxy::release_service(client_t _client, - service_t _service, instance_t _instance) { - routing_manager_base::release_service(_client, _service, _instance); - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - remove_pending_subscription(_service, _instance, 0xFFFF, ANY_EVENT); - - auto it = requests_to_debounce_.begin(); - while (it != requests_to_debounce_.end()) { - if (it->service_ == _service - && it->instance_ == _instance) { - break; - } - it++; - } - if (it != requests_to_debounce_.end()) { - requests_to_debounce_.erase(it); - } else if (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); - } - } -} - -void routing_manager_proxy::register_event(client_t _client, - service_t _service, instance_t _instance, - event_t _notifier, - const std::set<eventgroup_t> &_eventgroups, const event_type_e _type, - reliability_type_e _reliability, - std::chrono::milliseconds _cycle, bool _change_resets_cycle, - bool _update_on_change, epsilon_change_func_t _epsilon_change_func, - bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) { - (void)_is_shadow; - (void)_is_cache_placeholder; - - const event_data_t registration = { - _service, - _instance, - _notifier, - _type, - _reliability, - _is_provided, - _eventgroups - }; - bool is_first(false); - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - is_first = pending_event_registrations_.find(registration) - == pending_event_registrations_.end(); -#ifndef VSOMEIP_ENABLE_COMPAT - if (is_first) { - pending_event_registrations_.insert(registration); - } -#else - bool insert = true; - if (is_first) { - for (auto iter = pending_event_registrations_.begin(); - iter != pending_event_registrations_.end();) { - if (iter->service_ == _service - && iter->instance_ == _instance - && iter->notifier_ == _notifier - && iter->is_provided_ == _is_provided - && iter->type_ == event_type_e::ET_EVENT - && _type == event_type_e::ET_SELECTIVE_EVENT) { - iter = pending_event_registrations_.erase(iter); - iter = pending_event_registrations_.insert(registration).first; - is_first = true; - insert = false; - break; - } else { - iter++; - } - } - if (insert) { - pending_event_registrations_.insert(registration); - } - } -#endif - } - if (is_first || _is_provided) { - routing_manager_base::register_event(_client, - _service, _instance, - _notifier, - _eventgroups, _type, _reliability, - _cycle, _change_resets_cycle, _update_on_change, - _epsilon_change_func, - _is_provided); - } - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - if (state_ == inner_state_type_e::ST_REGISTERED && is_first) { - send_register_event(client_, _service, _instance, - _notifier, _eventgroups, _type, _reliability, _is_provided); - } - } -} - -void routing_manager_proxy::unregister_event(client_t _client, - service_t _service, instance_t _instance, event_t _notifier, - bool _is_provided) { - - routing_manager_base::unregister_event(_client, _service, _instance, - _notifier, _is_provided); - - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - if (state_ == inner_state_type_e::ST_REGISTERED) { - byte_t its_command[VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNREGISTER_EVENT; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, - sizeof(client_)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_notifier, - sizeof(_notifier)); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] - = static_cast<byte_t>(_is_provided); - - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } - } - - for (auto iter = pending_event_registrations_.begin(); - iter != pending_event_registrations_.end(); ) { - if (iter->service_ == _service - && iter->instance_ == _instance - && iter->notifier_ == _notifier - && iter->is_provided_ == _is_provided) { - pending_event_registrations_.erase(iter); - break; - } else { - iter++; - } - } - } -} - -bool routing_manager_proxy::is_field(service_t _service, instance_t _instance, - event_t _event) const { - auto event = find_event(_service, _instance, _event); - if (event && event->is_field()) { - return true; - } - return false; -} - -void routing_manager_proxy::subscribe(client_t _client, uid_t _uid, gid_t _gid, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, - event_t _event) { - (void)_uid; - (void)_gid; - { - credentials_t its_credentials = std::make_pair(own_uid_, own_gid_); - if (_event == ANY_EVENT) { - if (!is_subscribe_to_any_event_allowed(its_credentials, _client, _service, _instance, _eventgroup)) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << _client - << " : routing_manager_proxy::subscribe: " - << " isn't allowed to subscribe to service/instance/event " - << _service << "/" << _instance << "/ANY_EVENT" - << " which violates the security policy ~> Skip subscribe!"; - return; - } - } else { - auto its_security = security_impl::get(); - if (!its_security) - return; - if (!its_security->is_client_allowed(own_uid_, own_gid_, - _client, _service, _instance, _event)) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << _client - << " : routing_manager_proxy::subscribe: " - << " isn't allowed to subscribe to service/instance/event " - << _service << "/" << _instance - << "/" << _event; - return; - } - } - - std::lock_guard<std::mutex> its_lock(state_mutex_); - if (state_ == inner_state_type_e::ST_REGISTERED && is_available(_service, _instance, _major)) { - send_subscribe(client_, _service, _instance, _eventgroup, _major, _event ); - } - subscription_data_t subscription = { _service, _instance, _eventgroup, _major, _event, _uid, _gid}; - pending_subscriptions_.insert(subscription); - } -} - -void routing_manager_proxy::send_subscribe(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, - event_t _event) { - (void)_client; - - byte_t its_command[VSOMEIP_SUBSCRIBE_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_SUBSCRIBE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, - sizeof(_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] = _major; - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7], &_event, - sizeof(_event)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 9], - &PENDING_SUBSCRIPTION_ID, sizeof(PENDING_SUBSCRIPTION_ID)); - - client_t target_client = find_local_client(_service, _instance); - if (target_client != VSOMEIP_ROUTING_CLIENT) { - auto its_target = ep_mgr_->find_or_create_local(target_client); - its_target->send(its_command, sizeof(its_command)); - } else { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } -} - -void routing_manager_proxy::send_subscribe_nack(client_t _subscriber, - service_t _service, instance_t _instance, eventgroup_t _eventgroup, - event_t _event, remote_subscription_id_t _id) { - byte_t its_command[VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - client_t its_client = get_client(); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_NACK; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &its_client, - sizeof(its_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], &_subscriber, - sizeof(_subscriber)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_event, - sizeof(_event)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 10], &_id, - sizeof(_id)); - - if (_subscriber != VSOMEIP_ROUTING_CLIENT - && _id == PENDING_SUBSCRIPTION_ID) { - auto its_target = ep_mgr_->find_local(_subscriber); - if (its_target) { - its_target->send(its_command, sizeof(its_command)); - return; - } - } - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } -} - -void routing_manager_proxy::send_subscribe_ack(client_t _subscriber, - service_t _service, instance_t _instance, eventgroup_t _eventgroup, - event_t _event, remote_subscription_id_t _id) { - byte_t its_command[VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - client_t its_client = get_client(); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_ACK; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &its_client, - sizeof(its_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], &_subscriber, - sizeof(_subscriber)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_event, - sizeof(_event)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 10], &_id, - sizeof(_id)); - - if (_subscriber != VSOMEIP_ROUTING_CLIENT - && _id == PENDING_SUBSCRIPTION_ID) { - auto its_target = ep_mgr_->find_local(_subscriber); - if (its_target) { - its_target->send(its_command, sizeof(its_command)); - return; - } - } - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } -} - -void routing_manager_proxy::unsubscribe(client_t _client, uid_t _uid, gid_t _gid, - service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { - (void)_client; - (void)_uid; - (void)_gid; - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - remove_pending_subscription(_service, _instance, _eventgroup, _event); - - if (state_ == inner_state_type_e::ST_REGISTERED) { - byte_t its_command[VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNSUBSCRIBE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, - sizeof(_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], &_event, - sizeof(_event)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], - &PENDING_SUBSCRIPTION_ID, sizeof(PENDING_SUBSCRIPTION_ID)); - - auto its_target = ep_mgr_->find_local(_service, _instance); - if (its_target) { - its_target->send(its_command, sizeof(its_command)); - } else { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } - } - } -} - -bool routing_manager_proxy::send(client_t _client, const byte_t *_data, - length_t _size, instance_t _instance, - bool _reliable, - client_t _bound_client, - credentials_t _credentials, - uint8_t _status_check, - bool _sent_from_remote) { - (void)_client; - (void)_bound_client; - (void)_credentials; - (void)_sent_from_remote; - bool is_sent(false); - bool has_remote_subscribers(false); - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - if (state_ != inner_state_type_e::ST_REGISTERED) { - return false; - } - } - if (client_side_logging_) { - if (_size > VSOMEIP_MESSAGE_TYPE_POS) { - service_t its_service = VSOMEIP_BYTES_TO_WORD( - _data[VSOMEIP_SERVICE_POS_MIN], - _data[VSOMEIP_SERVICE_POS_MAX]); - if (client_side_logging_filter_.empty() - || (1 == client_side_logging_filter_.count(std::make_tuple(its_service, ANY_INSTANCE))) - || (1 == client_side_logging_filter_.count(std::make_tuple(its_service, _instance)))) { - method_t its_method = VSOMEIP_BYTES_TO_WORD( - _data[VSOMEIP_METHOD_POS_MIN], - _data[VSOMEIP_METHOD_POS_MAX]); - session_t its_session = VSOMEIP_BYTES_TO_WORD( - _data[VSOMEIP_SESSION_POS_MIN], - _data[VSOMEIP_SESSION_POS_MAX]); - client_t its_client = VSOMEIP_BYTES_TO_WORD( - _data[VSOMEIP_CLIENT_POS_MIN], - _data[VSOMEIP_CLIENT_POS_MAX]); - VSOMEIP_INFO << "routing_manager_proxy::send: (" - << std::hex << std::setw(4) << std::setfill('0') << client_ <<"): [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << _instance << "." - << std::hex << std::setw(4) << std::setfill('0') << its_method << ":" - << std::hex << std::setw(4) << std::setfill('0') << its_session << ":" - << std::hex << std::setw(4) << std::setfill('0') << its_client << "] " - << "type=" << std::hex << static_cast<std::uint32_t>(_data[VSOMEIP_MESSAGE_TYPE_POS]) - << " thread=" << std::hex << std::this_thread::get_id(); - } - } else { - VSOMEIP_ERROR << "routing_manager_proxy::send: (" - << std::hex << std::setw(4) << std::setfill('0') << client_ - <<"): message too short to log: " << std::dec << _size; - } - } - if (_size > VSOMEIP_MESSAGE_TYPE_POS) { - std::shared_ptr<endpoint> its_target; - if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) { - // Request - service_t its_service = VSOMEIP_BYTES_TO_WORD( - _data[VSOMEIP_SERVICE_POS_MIN], - _data[VSOMEIP_SERVICE_POS_MAX]); - client_t its_client = find_local_client(its_service, _instance); - if (its_client != VSOMEIP_ROUTING_CLIENT) { - if (is_client_known(its_client)) { - its_target = ep_mgr_->find_or_create_local(its_client); - } - } - } else if (!utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { - // Response - client_t its_client = VSOMEIP_BYTES_TO_WORD( - _data[VSOMEIP_CLIENT_POS_MIN], - _data[VSOMEIP_CLIENT_POS_MAX]); - if (its_client != VSOMEIP_ROUTING_CLIENT) { - if (is_client_known(its_client)) { - its_target = ep_mgr_->find_or_create_local(its_client); - } - } - } else if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && - _client == VSOMEIP_ROUTING_CLIENT) { - // notify - has_remote_subscribers = send_local_notification(get_client(), _data, _size, - _instance, _reliable, _status_check); - } else if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && - _client != VSOMEIP_ROUTING_CLIENT) { - // notify_one - its_target = ep_mgr_->find_local(_client); - if (its_target) { -#ifdef USE_DLT - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - - trace::header its_header; - if (its_header.prepare(nullptr, true, _instance)) - tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); -#endif - return send_local(its_target, get_client(), _data, _size, - _instance, _reliable, VSOMEIP_SEND, _status_check); - } - } - // If no direct endpoint could be found - // or for notifications ~> route to routing_manager_stub -#ifdef USE_DLT - bool message_to_stub(false); -#endif - if (!its_target) { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - its_target = sender_; -#ifdef USE_DLT - message_to_stub = true; -#endif - } else { - return false; - } - } - - bool send(true); - uint8_t command = VSOMEIP_SEND; - - if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { - if (_client != VSOMEIP_ROUTING_CLIENT) { - command = VSOMEIP_NOTIFY_ONE; - } else { - command = VSOMEIP_NOTIFY; - // Do we need to deliver a notification to the routing manager? - // Only for services which already have remote clients subscribed to - send = has_remote_subscribers; - } - } -#ifdef USE_DLT - else if (!message_to_stub) { - const uint16_t its_data_size - = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - - trace::header its_header; - if (its_header.prepare(nullptr, true, _instance)) - tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - _data, its_data_size); - } -#endif - if (send) { - is_sent = send_local(its_target, - (command == VSOMEIP_NOTIFY_ONE ? _client : get_client()), - _data, _size, _instance, _reliable, command, _status_check); - } - } - return (is_sent); -} - -bool routing_manager_proxy::send_to(const client_t _client, - const std::shared_ptr<endpoint_definition> &_target, - std::shared_ptr<message> _message) { - (void)_client; - (void)_target; - (void)_message; - return (false); -} - -bool routing_manager_proxy::send_to( - const std::shared_ptr<endpoint_definition> &_target, - const byte_t *_data, uint32_t _size, instance_t _instance) { - (void)_target; - (void)_data; - (void)_size; - (void)_instance; - return (false); -} - -void routing_manager_proxy::on_connect(const std::shared_ptr<endpoint>& _endpoint) { - _endpoint->set_connected(true); - _endpoint->set_established(true); - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (_endpoint != sender_) { - return; - } - } - is_connected_ = true; - assign_client(); -} - -void routing_manager_proxy::on_disconnect(const std::shared_ptr<endpoint>& _endpoint) { - - bool is_disconnected((_endpoint == sender_)); - if (is_disconnected) { - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - is_connected_ = false; - } - - VSOMEIP_INFO << "routing_manager_proxy::on_disconnect: Client 0x" << std::hex - << get_client() << " calling host_->on_state " - << "with DEREGISTERED"; - host_->on_state(state_type_e::ST_DEREGISTERED); - } -} - -void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, - endpoint *_receiver, const boost::asio::ip::address &_destination, - client_t _bound_client, - credentials_t _credentials, - const boost::asio::ip::address &_remote_address, - std::uint16_t _remote_port) { - (void)_receiver; - (void)_destination; - (void)_remote_address; - (void)_remote_port; -#if 0 - std::stringstream msg; - msg << "rmp::on_message: "; - for (length_t i = 0; i < _size; ++i) - msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; - VSOMEIP_INFO << msg.str(); -#endif - byte_t its_command; - client_t its_client; - length_t its_length; - service_t its_service; - instance_t its_instance; - eventgroup_t its_eventgroup; - event_t its_event; - major_version_t its_major; - client_t routing_host_id = configuration_->get_id(configuration_->get_routing_host()); - client_t its_subscriber; - remote_subscription_id_t its_subscription_id(PENDING_SUBSCRIPTION_ID); - std::uint32_t its_remote_subscriber_count(0); - bool is_internal_policy_update(false); - - std::uint32_t its_sender_uid = std::get<0>(_credentials); - std::uint32_t its_sender_gid = std::get<1>(_credentials); - - auto its_security = security_impl::get(); - if (!its_security) - return; - - if (_size > VSOMEIP_COMMAND_SIZE_POS_MAX) { - its_command = _data[VSOMEIP_COMMAND_TYPE_POS]; - std::memcpy(&its_client, &_data[VSOMEIP_COMMAND_CLIENT_POS], - sizeof(its_client)); - std::memcpy(&its_length, &_data[VSOMEIP_COMMAND_SIZE_POS_MIN], - sizeof(its_length)); - - bool message_from_routing(false); - if (its_security->is_enabled()) { - // if security is enabled, client ID of routing must be configured - // and credential passing is active. Otherwise bound client is zero by default - message_from_routing = (_bound_client == routing_host_id); - } else { - message_from_routing = (its_client == routing_host_id); - } - - if (its_security->is_enabled() && !message_from_routing && - _bound_client != its_client) { - VSOMEIP_WARNING << std::hex << "Client " << std::setw(4) << std::setfill('0') << get_client() - << " received a message with command " << (uint32_t)its_command - << " from " << std::setw(4) << std::setfill('0') - << its_client << " which doesn't match the bound client " - << std::setw(4) << std::setfill('0') << _bound_client - << " ~> skip message!"; - return; - } - - switch (its_command) { - case VSOMEIP_SEND: { - if (_size < VSOMEIP_SEND_COMMAND_SIZE + VSOMEIP_FULL_HEADER_SIZE) { - VSOMEIP_WARNING << "Received a SEND command with too small size -> skip!"; - break; - } - instance_t its_instance; - bool its_reliable; - uint8_t its_check_status; - std::memcpy(&its_instance,&_data[VSOMEIP_SEND_COMMAND_INSTANCE_POS_MIN], - sizeof(instance_t)); - std::memcpy(&its_reliable, &_data[VSOMEIP_SEND_COMMAND_RELIABLE_POS], - sizeof(its_reliable)); - std::memcpy(&its_check_status, &_data[VSOMEIP_SEND_COMMAND_CHECK_STATUS_POS], - sizeof(its_check_status)); - - // reduce by size of instance, flush, reliable, client and is_valid_crc flag - const std::uint32_t its_message_size = its_length - - (VSOMEIP_SEND_COMMAND_SIZE - VSOMEIP_COMMAND_HEADER_SIZE); - - if (its_message_size != - VSOMEIP_BYTES_TO_LONG(_data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 1], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 2], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 3]) - + VSOMEIP_SOMEIP_HEADER_SIZE) { - VSOMEIP_WARNING << "Received a SEND command containing message with invalid size -> skip!"; - break; - } - - auto a_deserializer = get_deserializer(); - a_deserializer->set_data(&_data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS], - its_message_size); - std::shared_ptr<message_impl> its_message(a_deserializer->deserialize_message()); - a_deserializer->reset(); - put_deserializer(a_deserializer); - - if (its_message) { - its_message->set_instance(its_instance); - its_message->set_reliable(its_reliable); - its_message->set_check_result(its_check_status); - its_message->set_uid(std::get<0>(_credentials)); - its_message->set_gid(std::get<1>(_credentials)); - - if (!message_from_routing) { - if (utility::is_notification(its_message->get_message_type())) { - if (!is_response_allowed(_bound_client, its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::on_message: " - << " received a notification from client 0x" << _bound_client - << " which does not offer service/instance/event " - << its_message->get_service() << "/" << its_message->get_instance() - << "/" << its_message->get_method() - << " ~> Skip message!"; - return; - } else { - if (!its_security->is_client_allowed(own_uid_, own_gid_, - get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::on_message: " - << " isn't allowed to receive a notification from service/instance/event " - << its_message->get_service() << "/" << its_message->get_instance() - << "/" << its_message->get_method() - << " respectively from client 0x" << _bound_client - << " ~> Skip message!"; - return; - } - cache_event_payload(its_message); - } - } else if (utility::is_request(its_message->get_message_type())) { - if (its_security->is_enabled() - && its_message->get_client() != _bound_client) { - VSOMEIP_WARNING << std::hex << "vSomeIP Security: Client 0x" << std::setw(4) << std::setfill('0') << get_client() - << " received a request from client 0x" << std::setw(4) << std::setfill('0') - << its_message->get_client() << " to service/instance/method " - << its_message->get_service() << "/" << its_message->get_instance() - << "/" << its_message->get_method() << " which doesn't match the bound client 0x" - << std::setw(4) << std::setfill('0') << _bound_client - << " ~> skip message!"; - return; - } - - if (!its_security->is_client_allowed(its_sender_uid, its_sender_gid, - its_message->get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_message->get_client() - << " : routing_manager_proxy::on_message: " - << "isn't allowed to send a request to service/instance/method " - << its_message->get_service() << "/" << its_message->get_instance() - << "/" << its_message->get_method() - << " ~> Skip message!"; - return; - } - } else { // response - if (!is_response_allowed(_bound_client, its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::on_message: " - << " received a response from client 0x" << _bound_client - << " which does not offer service/instance/method " - << its_message->get_service() << "/" << its_message->get_instance() - << "/" << its_message->get_method() - << " ~> Skip message!"; - return; - } else { - if (!its_security->is_client_allowed(own_uid_, own_gid_, - get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::on_message: " - << " isn't allowed to receive a response from service/instance/method " - << its_message->get_service() << "/" << its_message->get_instance() - << "/" << its_message->get_method() - << " respectively from client 0x" << _bound_client - << " ~> Skip message!"; - return; - } - } - } - } else { - if (!its_security->is_remote_client_allowed()) { - // if the message is from routing manager, check if - // policy allows remote requests. - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::on_message: " - << std::hex << "Security: Remote clients via routing manager with client ID 0x" << its_client - << " are not allowed to communicate with service/instance/method " - << its_message->get_service() << "/" << its_message->get_instance() - << "/" << its_message->get_method() - << " respectively with client 0x" << get_client() - << " ~> Skip message!"; - return; - } else if (utility::is_notification(its_message->get_message_type())) { - // As subscription is sent on eventgroup level, incoming remote event ID's - // need to be checked as well if remote clients are allowed - // and the local policy only allows specific events in the eventgroup to be received. - if (!its_security->is_client_allowed(own_uid_, own_gid_, - get_client(), its_message->get_service(), - its_message->get_instance(), its_message->get_method())) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::on_message: " - << " isn't allowed to receive a notification from service/instance/event " - << its_message->get_service() << "/" << its_message->get_instance() - << "/" << its_message->get_method() - << " respectively from remote clients via routing manager with client ID 0x" - << routing_host_id - << " ~> Skip message!"; - return; - } - cache_event_payload(its_message); - } - } -#ifdef USE_DLT - if (client_side_logging_ - && (client_side_logging_filter_.empty() - || (1 == client_side_logging_filter_.count(std::make_tuple(its_message->get_service(), ANY_INSTANCE))) - || (1 == client_side_logging_filter_.count(std::make_tuple(its_message->get_service(), its_message->get_instance()))))) { - trace::header its_header; - if (its_header.prepare(nullptr, false, its_instance)) - tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - &_data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS], - static_cast<std::uint16_t>(its_message_size)); - } -#endif - - host_->on_message(std::move(its_message)); - } else { - VSOMEIP_ERROR << "Routing proxy: on_message: " - << "SomeIP-Header deserialization failed!"; - } - break; - } - - case VSOMEIP_ASSIGN_CLIENT_ACK: { - if (_size != VSOMEIP_ASSIGN_CLIENT_ACK_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a VSOMEIP_ASSIGN_CLIENT_ACK command with wrong size ~> skip!"; - break; - } - client_t its_assigned_client(VSOMEIP_CLIENT_UNSET); - std::memcpy(&its_assigned_client, - &_data[VSOMEIP_COMMAND_PAYLOAD_POS], sizeof(client_)); - on_client_assign_ack(its_assigned_client); - break; - } - case VSOMEIP_ROUTING_INFO: - if (_size - VSOMEIP_COMMAND_HEADER_SIZE != its_length) { - VSOMEIP_WARNING << "Received a ROUTING_INFO command with invalid size -> skip!"; - break; - } - if (!its_security->is_enabled() || message_from_routing) { - on_routing_info(&_data[VSOMEIP_COMMAND_PAYLOAD_POS], its_length); - } else { - VSOMEIP_WARNING << "routing_manager_proxy::on_message: " - << std::hex << "Security: Client 0x" << get_client() - << " received an routing info from a client which isn't the routing manager" - << " : Skip message!"; - } - break; - - case VSOMEIP_PING: - if (_size != VSOMEIP_PING_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a PING command with wrong size ~> skip!"; - break; - } - send_pong(); - VSOMEIP_TRACE << "PING(" - << std::hex << std::setw(4) << std::setfill('0') << client_ << ")"; - break; - - case VSOMEIP_SUBSCRIBE: - if (_size != VSOMEIP_SUBSCRIBE_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a SUBSCRIBE 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_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_eventgroup)); - std::memcpy(&its_major, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(its_major)); - std::memcpy(&its_event, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7], - sizeof(its_event)); - std::memcpy(&its_subscription_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 9], - sizeof(its_subscription_id)); - { - std::unique_lock<std::recursive_mutex> its_lock(incoming_subscriptions_mutex_); - if (its_subscription_id != PENDING_SUBSCRIPTION_ID) { - its_lock.unlock(); -#ifdef VSOMEIP_ENABLE_COMPAT - routing_manager_base::set_incoming_subscription_state(its_client, its_service, - its_instance, its_eventgroup, its_event, subscription_state_e::IS_SUBSCRIBING); -#endif - // Remote subscriber: Notify routing manager initially + count subscribes - auto self = shared_from_this(); - host_->on_subscription(its_service, its_instance, its_eventgroup, - its_client, its_sender_uid, its_sender_gid, true, - [this, self, its_client, its_service, its_instance, - its_eventgroup, its_event, its_subscription_id, its_major] - (const bool _subscription_accepted){ - std::uint32_t its_count = 0; - if(_subscription_accepted) { - send_subscribe_ack(its_client, its_service, its_instance, - its_eventgroup, its_event, its_subscription_id); - std::set<event_t> its_already_subscribed_events; - bool inserted = insert_subscription(its_service, its_instance, its_eventgroup, - its_event, VSOMEIP_ROUTING_CLIENT, &its_already_subscribed_events); - if (inserted) { - notify_remote_initially(its_service, its_instance, its_eventgroup, - its_already_subscribed_events); - } -#ifdef VSOMEIP_ENABLE_COMPAT - send_pending_notify_ones(its_service, its_instance, its_eventgroup, its_client, true); -#endif - its_count = get_remote_subscriber_count(its_service, its_instance, its_eventgroup, true); - } else { - send_subscribe_nack(its_client, its_service, its_instance, - its_eventgroup, its_event, its_subscription_id); - } - VSOMEIP_INFO << "SUBSCRIBE(" - << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." - << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << ":" - << std::hex << std::setw(4) << std::setfill('0') << its_event << ":" - << std::dec << (uint16_t)its_major << "] " - << (bool)(its_subscription_id != PENDING_SUBSCRIPTION_ID) << " " - << (_subscription_accepted ? std::to_string(its_count) : "-") - << (_subscription_accepted ? " ACCEPTED" : " NOT ACCEPTED"); -#ifdef VSOMEIP_ENABLE_COMPAT - routing_manager_base::erase_incoming_subscription_state(its_client, its_service, - its_instance, its_eventgroup, its_event); -#endif - }); - } else if (is_client_known(its_client)) { - its_lock.unlock(); - if (!message_from_routing) { - if (its_event == ANY_EVENT) { - if (!is_subscribe_to_any_event_allowed(_credentials, its_client, its_service, its_instance, its_eventgroup)) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client - << " : routing_manager_proxy::on_message: " - << " isn't allowed to subscribe to service/instance/event " - << its_service << "/" << its_instance << "/ANY_EVENT" - << " which violates the security policy ~> Skip subscribe!"; - return; - } - } else { - if (!its_security->is_client_allowed(its_sender_uid, its_sender_gid, - its_client, its_service, its_instance, its_event)) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client - << " : routing_manager_proxy::on_message: " - << " subscribes to service/instance/event " - << its_service << "/" << its_instance << "/" << its_event - << " which violates the security policy ~> Skip subscribe!"; - return; - } - } - } else { - if (!its_security->is_remote_client_allowed()) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client - << " : routing_manager_proxy::on_message: " - << std::hex << "Routing manager with client ID 0x" - << its_client - << " isn't allowed to subscribe to service/instance/event " - << its_service << "/" << its_instance - << "/" << its_event - << " respectively to client 0x" << get_client() - << " ~> Skip Subscribe!"; - return; - } - } - - // Local & already known subscriber: create endpoint + send (N)ACK + insert subscription -#ifdef VSOMEIP_ENABLE_COMPAT - routing_manager_base::set_incoming_subscription_state(its_client, its_service, - its_instance, its_eventgroup, its_event, subscription_state_e::IS_SUBSCRIBING); -#endif - (void) ep_mgr_->find_or_create_local(its_client); - auto self = shared_from_this(); - host_->on_subscription(its_service, its_instance, - its_eventgroup, its_client, its_sender_uid, its_sender_gid, true, - [this, self, its_client, its_sender_uid, its_sender_gid, its_service, - its_instance, its_eventgroup, its_event, its_major] - (const bool _subscription_accepted) { - if (!_subscription_accepted) { - send_subscribe_nack(its_client, its_service, its_instance, - its_eventgroup, its_event, PENDING_SUBSCRIPTION_ID); - } else { - send_subscribe_ack(its_client, its_service, its_instance, - its_eventgroup, its_event, PENDING_SUBSCRIPTION_ID); - routing_manager_base::subscribe(its_client, its_sender_uid, its_sender_gid, - its_service, its_instance, its_eventgroup, its_major, its_event); -#ifdef VSOMEIP_ENABLE_COMPAT - send_pending_notify_ones(its_service, its_instance, its_eventgroup, its_client); -#endif - } -#ifdef VSOMEIP_ENABLE_COMPAT - routing_manager_base::erase_incoming_subscription_state(its_client, its_service, - its_instance, its_eventgroup, its_event); -#endif - }); - } else { - // Local & not yet known subscriber ~> set pending until subscriber gets known! - subscription_data_t subscription = { its_service, its_instance, - its_eventgroup, its_major, its_event, its_sender_uid, its_sender_gid }; - pending_incoming_subscripitons_[its_client].insert(subscription); - } - } - if (its_subscription_id == PENDING_SUBSCRIPTION_ID) { // local subscription - VSOMEIP_INFO << "SUBSCRIBE(" - << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." - << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << ":" - << std::hex << std::setw(4) << std::setfill('0') << its_event << ":" - << std::dec << (uint16_t)its_major << "]"; - } - break; - - case VSOMEIP_UNSUBSCRIBE: - if (_size != VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received an UNSUBSCRIBE 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_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_eventgroup)); - std::memcpy(&its_event, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(its_event)); - std::memcpy(&its_subscription_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], - sizeof(its_subscription_id)); - host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, its_sender_uid, its_sender_gid, false, [](const bool _subscription_accepted){ (void)_subscription_accepted; }); - if (its_subscription_id == PENDING_SUBSCRIPTION_ID) { - // Local subscriber: withdraw subscription - routing_manager_base::unsubscribe(its_client, its_sender_uid, its_sender_gid, its_service, its_instance, its_eventgroup, its_event); - } else { - // Remote subscriber: withdraw subscription only if no more remote subscriber exists - its_remote_subscriber_count = get_remote_subscriber_count(its_service, - its_instance, its_eventgroup, false); - if (!its_remote_subscriber_count) { - routing_manager_base::unsubscribe(VSOMEIP_ROUTING_CLIENT, ANY_UID, ANY_GID, its_service, - its_instance, its_eventgroup, its_event); - } - send_unsubscribe_ack(its_service, its_instance, its_eventgroup, - its_subscription_id); - } - VSOMEIP_INFO << "UNSUBSCRIBE(" - << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." - << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." - << std::hex << std::setw(4) << std::setfill('0') << its_event << "] " - << (bool)(its_subscription_id != PENDING_SUBSCRIPTION_ID) << " " - << std::dec << its_remote_subscriber_count; - break; - - case VSOMEIP_EXPIRED_SUBSCRIPTION: - if (_size != VSOMEIP_EXPIRED_SUBSCRIPTION_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received an VSOMEIP_EXPIRED_SUBSCRIPTION 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_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_eventgroup)); - std::memcpy(&its_event, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(its_event)); - std::memcpy(&its_subscription_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], - sizeof(its_subscription_id)); - host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, its_sender_uid, its_sender_gid, false, [](const bool _subscription_accepted){ (void)_subscription_accepted; }); - if (its_subscription_id == PENDING_SUBSCRIPTION_ID) { - // Local subscriber: withdraw subscription - routing_manager_base::unsubscribe(its_client, its_sender_uid, its_sender_gid, its_service, its_instance, its_eventgroup, its_event); - } else { - // Remote subscriber: withdraw subscription only if no more remote subscriber exists - its_remote_subscriber_count = get_remote_subscriber_count(its_service, - its_instance, its_eventgroup, false); - if (!its_remote_subscriber_count) { - routing_manager_base::unsubscribe(VSOMEIP_ROUTING_CLIENT, ANY_UID, ANY_GID, its_service, - its_instance, its_eventgroup, its_event); - } - } - VSOMEIP_INFO << "UNSUBSCRIBE EXPIRED SUBSCRIPTION(" - << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." - << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." - << std::hex << std::setw(4) << std::setfill('0') << its_event << "] " - << (bool)(its_subscription_id != PENDING_SUBSCRIPTION_ID) << " " - << std::dec << its_remote_subscriber_count; - break; - - case VSOMEIP_SUBSCRIBE_NACK: - if (_size != VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a VSOMEIP_SUBSCRIBE_NACK 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_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_eventgroup)); - std::memcpy(&its_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(its_subscriber)); - std::memcpy(&its_event, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], - sizeof(its_event)); - - on_subscribe_nack(its_subscriber, its_service, its_instance, its_eventgroup, its_event); - VSOMEIP_INFO << "SUBSCRIBE NACK(" - << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." - << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." - << std::hex << std::setw(4) << std::setfill('0') << its_event << "]"; - break; - - case VSOMEIP_SUBSCRIBE_ACK: - if (_size != VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a VSOMEIP_SUBSCRIBE_ACK 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_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_eventgroup)); - std::memcpy(&its_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(its_subscriber)); - std::memcpy(&its_event, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], - sizeof(its_event)); - - on_subscribe_ack(its_subscriber, its_service, its_instance, its_eventgroup, its_event); - VSOMEIP_INFO << "SUBSCRIBE ACK(" - << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." - << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." - << std::hex << std::setw(4) << std::setfill('0') << its_event << "]"; - break; - - case VSOMEIP_OFFERED_SERVICES_RESPONSE: - if (_size - VSOMEIP_COMMAND_HEADER_SIZE != its_length) { - VSOMEIP_WARNING << "Received a VSOMEIP_OFFERED_SERVICES_RESPONSE command with invalid size -> skip!"; - break; - } - if (!its_security->is_enabled() || message_from_routing) { - on_offered_services_info(&_data[VSOMEIP_COMMAND_PAYLOAD_POS], its_length); - } else { - VSOMEIP_WARNING << std::hex << "Security: Client 0x" << get_client() - << " received an offered services info from a client which isn't the routing manager" - << " : Skip message!"; - } - break; - case VSOMEIP_RESEND_PROVIDED_EVENTS: { - if (_size != VSOMEIP_RESEND_PROVIDED_EVENTS_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a RESEND_PROVIDED_EVENTS command with wrong size ~> skip!"; - break; - } - pending_remote_offer_id_t its_pending_remote_offer_id(0); - std::memcpy(&its_pending_remote_offer_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], - sizeof(pending_remote_offer_id_t)); - resend_provided_event_registrations(); - send_resend_provided_event_response(its_pending_remote_offer_id); - VSOMEIP_INFO << "RESEND_PROVIDED_EVENTS(" - << std::hex << std::setw(4) << std::setfill('0') - << its_client << ")"; - break; - } - case VSOMEIP_UPDATE_SECURITY_POLICY_INT: - is_internal_policy_update = true; - /* Fallthrough */ - case VSOMEIP_UPDATE_SECURITY_POLICY: { - if (_size < VSOMEIP_COMMAND_HEADER_SIZE + sizeof(pending_security_update_id_t) || - _size - VSOMEIP_COMMAND_HEADER_SIZE != its_length) { - VSOMEIP_WARNING << "vSomeIP Security: Received a VSOMEIP_UPDATE_SECURITY_POLICY command with wrong size -> skip!"; - break; - } - if (!its_security->is_enabled() || message_from_routing) { - pending_security_update_id_t its_update_id(0); - - std::memcpy(&its_update_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], - sizeof(pending_security_update_id_t)); - - std::shared_ptr<policy> its_policy(std::make_shared<policy>()); - const byte_t *its_policy_data = _data + (VSOMEIP_COMMAND_PAYLOAD_POS + - sizeof(pending_security_update_id_t)); - - uint32_t its_policy_size = uint32_t(_size - (VSOMEIP_COMMAND_PAYLOAD_POS - + sizeof(pending_security_update_id_t))); - - bool is_valid = its_policy->deserialize(its_policy_data, its_policy_size); - if (is_valid) { - uint32_t its_uid; - uint32_t its_gid; - is_valid = its_policy->get_uid_gid(its_uid, its_gid); - if (is_valid) { - if (is_internal_policy_update - || its_security->is_policy_update_allowed(its_uid, its_policy)) { - its_security->update_security_policy(its_uid, its_gid, its_policy); - send_update_security_policy_response(its_update_id); - } - } else { - VSOMEIP_ERROR << "vSomeIP Security: Policy has no valid uid/gid!"; - } - } else { - VSOMEIP_ERROR << "vSomeIP Security: Policy deserialization failed!"; - } - } else { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::on_message: " - << " received a security policy update from a client which isn't the routing manager" - << " : Skip message!"; - } - break; - } - case VSOMEIP_REMOVE_SECURITY_POLICY: { - if (_size != VSOMEIP_REMOVE_SECURITY_POLICY_COMMAND_SIZE) { - VSOMEIP_WARNING << "vSomeIP Security: Received a VSOMEIP_REMOVE_SECURITY_POLICY command with wrong size ~> skip!"; - break; - } - if (!its_security->is_enabled() || message_from_routing) { - pending_security_update_id_t its_update_id(0); - uint32_t its_uid(ANY_UID); - uint32_t its_gid(ANY_GID); - - std::memcpy(&its_update_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], - sizeof(pending_security_update_id_t)); - std::memcpy(&its_uid, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(uint32_t)); - std::memcpy(&its_gid, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], - sizeof(uint32_t)); - if (its_security->is_policy_removal_allowed(its_uid)) { - its_security->remove_security_policy(its_uid, its_gid); - send_remove_security_policy_response(its_update_id); - } - } else { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::on_message: " - << "received a security policy removal from a client which isn't the routing manager" - << " : Skip message!"; - } - break; - } - case VSOMEIP_DISTRIBUTE_SECURITY_POLICIES: { - if (_size < VSOMEIP_COMMAND_HEADER_SIZE || - _size - VSOMEIP_COMMAND_HEADER_SIZE != its_length) { - VSOMEIP_WARNING << "vSomeIP Security: Received a VSOMEIP_DISTRIBUTE_SECURITY_POLICIES command with wrong size -> skip!"; - break; - } - if (!its_security->is_enabled() || message_from_routing) { - uint32_t its_policy_count(0); - uint32_t its_policy_size(0); - const byte_t* buffer_ptr = 0; - - if (VSOMEIP_COMMAND_PAYLOAD_POS + sizeof(uint32_t) * 2 <= _size) { - std::memcpy(&its_policy_count, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], - sizeof(uint32_t)); - - // skip policy count field - buffer_ptr = _data + (VSOMEIP_COMMAND_PAYLOAD_POS + - sizeof(uint32_t)); - - for (uint32_t i = 0; i < its_policy_count; i++) { - uint32_t its_uid(0); - uint32_t its_gid(0); - std::shared_ptr<policy> its_policy(std::make_shared<policy>()); - // length field of next (UID/GID + policy) - if (buffer_ptr + sizeof(uint32_t) <= _data + _size) { - std::memcpy(&its_policy_size, buffer_ptr, - sizeof(uint32_t)); - buffer_ptr += sizeof(uint32_t); - - if (buffer_ptr + its_policy_size <= _data + _size) { - if (its_security->parse_policy(buffer_ptr, its_policy_size, its_uid, its_gid, its_policy)) { - if (its_security->is_policy_update_allowed(its_uid, its_policy)) { - its_security->update_security_policy(its_uid, its_gid, its_policy); - } - } else { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() << " could not parse policy!"; - } - } - } - } - } - } else { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::on_message: " - << " received a security policy distribution command from a client which isn't the routing manager" - << " : Skip message!"; - } - break; - } - case VSOMEIP_UPDATE_SECURITY_CREDENTIALS: { - if (_size < VSOMEIP_COMMAND_HEADER_SIZE || - _size - VSOMEIP_COMMAND_HEADER_SIZE != its_length) { - VSOMEIP_WARNING << "vSomeIP Security: Received a VSOMEIP_UPDATE_SECURITY_CREDENTIALS command with wrong size -> skip!"; - break; - } - if (!its_security->is_enabled() || message_from_routing) { - on_update_security_credentials(&_data[VSOMEIP_COMMAND_PAYLOAD_POS], its_length); - } else { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::on_message: " - << "received a security credential update from a client which isn't the routing manager" - << " : Skip message!"; - } - break; - } - - case VSOMEIP_SUSPEND: - on_suspend(); // cleanup remote subscribers - break; - - default: - break; - } - } -} - -void routing_manager_proxy::on_routing_info(const byte_t *_data, - uint32_t _size) { -#if 0 - std::stringstream msg; - msg << "rmp::on_routing_info(" << std::hex << client_ << "): "; - for (uint32_t i = 0; i < _size; ++i) - msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; - VSOMEIP_INFO << msg.str(); -#endif - auto its_security = security_impl::get(); - if (!its_security) - return; - - uint32_t i = 0; - while (i + sizeof(uint32_t) + sizeof(routing_info_entry_e) <= _size) { - routing_info_entry_e routing_info_entry; - std::memcpy(&routing_info_entry, &_data[i], sizeof(routing_info_entry_e)); - i += uint32_t(sizeof(routing_info_entry_e)); - - uint32_t its_client_size; - std::memcpy(&its_client_size, &_data[i], sizeof(uint32_t)); - i += uint32_t(sizeof(uint32_t)); - - if (its_client_size + i > _size) { - VSOMEIP_WARNING << "Client 0x" << std::hex << get_client() << " : " - << "Processing of routing info failed due to bad length fields!"; - return; - } - - if (i + sizeof(client_t) <= _size) { - client_t its_client; - std::memcpy(&its_client, &_data[i], sizeof(client_t)); - i += uint32_t(sizeof(client_t)); - - if (routing_info_entry == routing_info_entry_e::RIE_ADD_CLIENT) { - { - std::lock_guard<std::mutex> its_lock(known_clients_mutex_); - known_clients_.insert(its_client); - } - if (its_client == get_client()) { - VSOMEIP_INFO << std::hex << "Application/Client " << get_client() - << " (" << host_->get_name() << ") is registered."; - -#ifndef _WIN32 - if (!its_security->check_credentials(get_client(), own_uid_, own_gid_)) { - VSOMEIP_ERROR << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::on_routing_info: RIE_ADD_CLIENT: isn't allowed" - << " to use the server endpoint due to credential check failed!"; - deregister_application(); - host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_DEREGISTERED)); - return; - } -#endif - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - if (state_ == inner_state_type_e::ST_REGISTERING) { - boost::system::error_code ec; - register_application_timer_.cancel(ec); - send_registered_ack(); - send_pending_commands(); - state_ = inner_state_type_e::ST_REGISTERED; - // Notify stop() call about clean deregistration - state_condition_.notify_one(); - } - } - - // inform host about its own registration state changes - if (state_ == inner_state_type_e::ST_REGISTERED) - host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_REGISTERED)); - - } - } else if (routing_info_entry == routing_info_entry_e::RIE_DEL_CLIENT) { - { - std::lock_guard<std::mutex> its_lock(known_clients_mutex_); - known_clients_.erase(its_client); - } - if (its_client == get_client()) { - its_security->remove_client_to_uid_gid_mapping(its_client); - VSOMEIP_INFO << std::hex << "Application/Client " << get_client() - << " (" << host_->get_name() << ") is deregistered."; - - // inform host about its own registration state changes - host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_DEREGISTERED)); - - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - state_ = inner_state_type_e::ST_DEREGISTERED; - // Notify stop() call about clean deregistration - state_condition_.notify_one(); - } - } else if (its_client != VSOMEIP_ROUTING_CLIENT) { - remove_local(its_client, true); - } - } - - uint32_t j = 0; - while (j + sizeof(uint32_t) <= its_client_size) { - uint32_t its_services_size; - std::memcpy(&its_services_size, &_data[i + j], sizeof(uint32_t)); - j += uint32_t(sizeof(uint32_t)); - - if (its_services_size >= sizeof(service_t) + sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t)) { - its_services_size -= uint32_t(sizeof(service_t)); - - service_t its_service; - std::memcpy(&its_service, &_data[i + j], sizeof(service_t)); - j += uint32_t(sizeof(service_t)); - - while (its_services_size >= sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t)) { - instance_t its_instance; - std::memcpy(&its_instance, &_data[i + j], sizeof(instance_t)); - j += uint32_t(sizeof(instance_t)); - - major_version_t its_major; - std::memcpy(&its_major, &_data[i + j], sizeof(major_version_t)); - j += uint32_t(sizeof(major_version_t)); - - minor_version_t its_minor; - std::memcpy(&its_minor, &_data[i + j], sizeof(minor_version_t)); - j += uint32_t(sizeof(minor_version_t)); - - if (routing_info_entry == routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE) { - if (get_routing_state() == routing_state_e::RS_SUSPENDED) { - VSOMEIP_INFO << "rmp::" <<__func__ << " We are in suspended mode, the service will not be added!"; - return; - } - { - std::lock_guard<std::mutex> its_lock(known_clients_mutex_); - known_clients_.insert(its_client); - } - { - std::lock_guard<std::mutex> its_lock(local_services_mutex_); - local_services_[its_service][its_instance] = std::make_tuple(its_major, its_minor, its_client); - } - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - send_pending_subscriptions(its_service, its_instance, its_major); - } - host_->on_availability(its_service, its_instance, true, its_major, its_minor); - VSOMEIP_INFO << "ON_AVAILABLE(" - << std::hex << std::setw(4) << std::setfill('0') << get_client() <<"): [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << its_instance - << ":" << std::dec << int(its_major) << "." << std::dec << its_minor << "]"; - } else if (routing_info_entry == routing_info_entry_e::RIE_DEL_SERVICE_INSTANCE) { - { - std::lock_guard<std::mutex> its_lock(local_services_mutex_); - auto found_service = local_services_.find(its_service); - if (found_service != local_services_.end()) { - found_service->second.erase(its_instance); - // move previously offering client to history - local_services_history_[its_service][its_instance].insert(its_client); - if (found_service->second.size() == 0) { - local_services_.erase(its_service); - } - } - } - on_stop_offer_service(its_service, its_instance, its_major, its_minor); - host_->on_availability(its_service, its_instance, false, its_major, its_minor); - VSOMEIP_INFO << "ON_UNAVAILABLE(" - << std::hex << std::setw(4) << std::setfill('0') << get_client() <<"): [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << its_instance - << ":" << std::dec << int(its_major) << "." << std::dec << its_minor << "]"; - - if (its_client == get_client()) { - VSOMEIP_INFO << __func__ - << ": Clearing subscriptions for service [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << its_instance << "]"; - unsubscribe_all(its_service, its_instance); - } - } - - its_services_size -= uint32_t(sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t) ); - } - } - } - - i += j; - } - } - { - struct subscription_info { - service_t service_id_; - instance_t instance_id_; - eventgroup_t eventgroup_id_; - client_t client_id_; - major_version_t major_; - event_t event_; - uid_t uid_; - gid_t gid_; - }; - std::lock_guard<std::recursive_mutex> its_lock(incoming_subscriptions_mutex_); - std::forward_list<struct subscription_info> subscription_actions; - if (pending_incoming_subscripitons_.size()) { - { - std::lock_guard<std::mutex> its_lock(known_clients_mutex_); - for (const client_t client : known_clients_) { - auto its_client = pending_incoming_subscripitons_.find(client); - if (its_client != pending_incoming_subscripitons_.end()) { - for (const auto& subscription : its_client->second) { - subscription_actions.push_front( - { subscription.service_, subscription.instance_, - subscription.eventgroup_, client, - subscription.major_, subscription.event_, - subscription.uid_, subscription.gid_ }); - } - } - } - } - for (const subscription_info &si : subscription_actions) { -#ifdef VSOMEIP_ENABLE_COMPAT - routing_manager_base::set_incoming_subscription_state(si.client_id_, si.service_id_, si.instance_id_, - si.eventgroup_id_, si.event_, subscription_state_e::IS_SUBSCRIBING); -#endif - (void) ep_mgr_->find_or_create_local(si.client_id_); - auto self = shared_from_this(); - host_->on_subscription( - si.service_id_, si.instance_id_, si.eventgroup_id_, - si.client_id_, si.uid_, si.gid_, true, - [this, self, si](const bool _subscription_accepted) { - if (!_subscription_accepted) { - send_subscribe_nack(si.client_id_, si.service_id_, - si.instance_id_, si.eventgroup_id_, si.event_, PENDING_SUBSCRIPTION_ID); - } else { - send_subscribe_ack(si.client_id_, si.service_id_, - si.instance_id_, si.eventgroup_id_, si.event_, PENDING_SUBSCRIPTION_ID); - routing_manager_base::subscribe(si.client_id_, si.uid_, si.gid_, - si.service_id_, si.instance_id_, si.eventgroup_id_, - si.major_, si.event_); -#ifdef VSOMEIP_ENABLE_COMPAT - send_pending_notify_ones(si.service_id_, - si.instance_id_, si.eventgroup_id_, si.client_id_); -#endif - } -#ifdef VSOMEIP_ENABLE_COMPAT - routing_manager_base::erase_incoming_subscription_state(si.client_id_, si.service_id_, - si.instance_id_, si.eventgroup_id_, si.event_); -#endif - { - std::lock_guard<std::recursive_mutex> its_lock2(incoming_subscriptions_mutex_); - pending_incoming_subscripitons_.erase(si.client_id_); - } - }); - } - } - } -} - -void routing_manager_proxy::on_offered_services_info(const byte_t *_data, - uint32_t _size) { -#if 0 - std::stringstream msg; - msg << "rmp::on_offered_services_info(" << std::hex << client_ << "): "; - for (uint32_t i = 0; i < _size; ++i) - msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; - VSOMEIP_INFO << msg.str(); -#endif - - std::vector<std::pair<service_t, instance_t>> its_offered_services_info; - - uint32_t i = 0; - while (i + sizeof(uint32_t) + sizeof(routing_info_entry_e) <= _size) { - routing_info_entry_e routing_info_entry; - std::memcpy(&routing_info_entry, &_data[i], sizeof(routing_info_entry_e)); - i += uint32_t(sizeof(routing_info_entry_e)); - - uint32_t its_service_entry_size; - std::memcpy(&its_service_entry_size, &_data[i], sizeof(uint32_t)); - i += uint32_t(sizeof(uint32_t)); - - if (its_service_entry_size + i > _size) { - VSOMEIP_WARNING << "Client 0x" << std::hex << get_client() << " : " - << "Processing of offered services info failed due to bad length fields!"; - return; - } - - if (its_service_entry_size >= sizeof(service_t) + sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t)) { - service_t its_service; - std::memcpy(&its_service, &_data[i], sizeof(service_t)); - i += uint32_t(sizeof(service_t)); - - instance_t its_instance; - std::memcpy(&its_instance, &_data[i], sizeof(instance_t)); - i += uint32_t(sizeof(instance_t)); - - major_version_t its_major; - std::memcpy(&its_major, &_data[i], sizeof(major_version_t)); - i += uint32_t(sizeof(major_version_t)); - - minor_version_t its_minor; - std::memcpy(&its_minor, &_data[i], sizeof(minor_version_t)); - i += uint32_t(sizeof(minor_version_t)); - - its_offered_services_info.push_back(std::make_pair(its_service, its_instance)); - } - } - host_->on_offered_services_info(its_offered_services_info); -} - -void routing_manager_proxy::reconnect(const std::unordered_set<client_t> &_clients) { - auto its_security = security_impl::get(); - if (!its_security) - return; - - // inform host about its own registration state changes - host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_DEREGISTERED)); - - { - std::lock_guard<std::mutex> 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, true); - } - } - - VSOMEIP_INFO << std::hex << "Application/Client " << get_client() - <<": Reconnecting to routing manager."; - -#ifndef _WIN32 - if (!its_security->check_credentials(get_client(), own_uid_, own_gid_)) { - VSOMEIP_ERROR << "vSomeIP Security: Client 0x" << std::hex << get_client() - << " : routing_manager_proxy::reconnect: isn't allowed" - << " to use the server endpoint due to credential check failed!"; - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->stop(); - } - return; - } -#endif - - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->restart(); - } -} - -void routing_manager_proxy::assign_client() { - std::vector<byte_t> its_command; - - std::string its_name(host_->get_name()); - uint32_t its_size(static_cast<uint32_t>(its_name.size())); - its_command.resize(7 + its_name.size()); - - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_ASSIGN_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)); - if (0 < its_name.size()) - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], its_name.c_str(), - its_name.size()); - - std::lock_guard<std::mutex> its_state_lock(state_mutex_); - if (is_connected_) { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - if (state_ != inner_state_type_e::ST_DEREGISTERED) - return; - state_ = inner_state_type_e::ST_ASSIGNING; - - sender_->send(&its_command[0], static_cast<uint32_t>(its_command.size())); - - boost::system::error_code ec; - register_application_timer_.cancel(ec); - register_application_timer_.expires_from_now(std::chrono::milliseconds(10000)); - register_application_timer_.async_wait( - std::bind( - &routing_manager_proxy::assign_client_timeout_cbk, - std::dynamic_pointer_cast<routing_manager_proxy>(shared_from_this()), - std::placeholders::_1)); - } - } -} - -void routing_manager_proxy::register_application() { - byte_t its_command[] = { - VSOMEIP_REGISTER_APPLICATION, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, - sizeof(client_)); - - if (is_connected_) { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - state_ = inner_state_type_e::ST_REGISTERING; - sender_->send(its_command, sizeof(its_command)); - - register_application_timer_.cancel(); - register_application_timer_.expires_from_now(std::chrono::milliseconds(1000)); - register_application_timer_.async_wait( - std::bind( - &routing_manager_proxy::register_application_timeout_cbk, - std::dynamic_pointer_cast<routing_manager_proxy>(shared_from_this()), - std::placeholders::_1)); - } - } -} - -void routing_manager_proxy::deregister_application() { - std::vector<byte_t> its_command(VSOMEIP_COMMAND_HEADER_SIZE, 0); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_DEREGISTER_APPLICATION; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, - sizeof(client_)); - if (is_connected_) - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(&its_command[0], uint32_t(its_command.size())); - } - } -} - -void routing_manager_proxy::send_pong() const { - byte_t its_pong[] = { - VSOMEIP_PONG, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; - - std::memcpy(&its_pong[VSOMEIP_COMMAND_CLIENT_POS], &client_, - sizeof(client_t)); - - if (is_connected_) { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_pong, sizeof(its_pong)); - } - } -} - -void routing_manager_proxy::send_request_services(std::set<service_data_t>& _requests) { - if (!_requests.size()) { - return; - } - size_t its_size = (VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE) * _requests.size(); - if (its_size > (std::numeric_limits<std::uint32_t>::max)()) { - VSOMEIP_ERROR<< "routing_manager_proxy::send_request_services too many" - << " requests (" << std::dec << its_size << "), returning."; - return; - } - - std::vector<byte_t> 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(std::uint32_t)); - - uint32_t entry_size = (sizeof(service_t) + sizeof(instance_t) - + sizeof(major_version_t) + sizeof(minor_version_t)); - - unsigned 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_)); - ++i; - } - - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(&its_command[0], - static_cast<std::uint32_t>(its_size + VSOMEIP_COMMAND_HEADER_SIZE)); - } - } -} - -void routing_manager_proxy::send_release_service(client_t _client, service_t _service, - instance_t _instance) { - (void)_client; - byte_t its_command[VSOMEIP_RELEASE_SERVICE_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_RELEASE_SERVICE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_RELEASE_SERVICE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, - sizeof(client_)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } -} - -void routing_manager_proxy::send_register_event(client_t _client, - service_t _service, instance_t _instance, - event_t _notifier, - const std::set<eventgroup_t> &_eventgroups, const event_type_e _type, - reliability_type_e _reliability, - bool _is_provided) { - - std::size_t its_eventgroups_size = (_eventgroups.size() * sizeof(eventgroup_t)) + - VSOMEIP_REGISTER_EVENT_COMMAND_SIZE; - if (its_eventgroups_size > (std::numeric_limits<std::uint32_t>::max)()) { - VSOMEIP_ERROR<< "routing_manager_proxy::send_register_event too many" - << " eventgroups (" << std::dec << its_eventgroups_size << "), returning."; - return; - } - byte_t *its_command = new byte_t[its_eventgroups_size]; - uint32_t its_size = static_cast<std::uint32_t>(its_eventgroups_size) - - VSOMEIP_COMMAND_HEADER_SIZE; - - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_REGISTER_EVENT; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, - sizeof(_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_notifier, - sizeof(_notifier)); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] - = static_cast<byte_t>(_type); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7] - = static_cast<byte_t>(_is_provided); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8] - = static_cast<byte_t>(_reliability); - - std::size_t i = 9; - for (auto eg : _eventgroups) { - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + i], &eg, - sizeof(eventgroup_t)); - i += sizeof(eventgroup_t); - } - - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, static_cast<std::uint32_t>(its_eventgroups_size)); - } - } - - if (_is_provided) { - VSOMEIP_INFO << "REGISTER EVENT(" - << std::hex << std::setw(4) << std::setfill('0') << client_ << "): [" - << std::hex << std::setw(4) << std::setfill('0') << _service << "." - << std::hex << std::setw(4) << std::setfill('0') << _instance << "." - << std::hex << std::setw(4) << std::setfill('0') << _notifier - << ":is_provider=" << _is_provided << "]"; - } - - delete[] its_command; -} - -void routing_manager_proxy::on_subscribe_ack(client_t _client, - service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { - (void)_client; -#if 0 - VSOMEIP_ERROR << "routing_manager_proxy::" << __func__ - << "(" << std::hex << host_->get_client() << "):" - << "event=" - << std::hex << _service << "." - << std::hex << _instance << "." - << std::hex << _eventgroup << "." - << std::hex << _event; -#endif - if (_event == ANY_EVENT) { - auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); - if (its_eventgroup) { - for (const auto& its_event : its_eventgroup->get_events()) { - host_->on_subscription_status(_service, _instance, _eventgroup, its_event->get_event(), 0x0 /*OK*/); - } - } - } else { - host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); - } -} - -void routing_manager_proxy::on_subscribe_nack(client_t _client, - service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { - (void)_client; - if (_event == ANY_EVENT) { - auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); - if (its_eventgroup) { - for (const auto& its_event : its_eventgroup->get_events()) { - host_->on_subscription_status(_service, _instance, _eventgroup, its_event->get_event(), 0x7 /*Rejected*/); - } - } - } else { - host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x7 /*Rejected*/); - } -} - -void routing_manager_proxy::cache_event_payload( - const std::shared_ptr<message> &_message) { - const service_t its_service(_message->get_service()); - const instance_t its_instance(_message->get_instance()); - const method_t its_method(_message->get_method()); - std::shared_ptr<event> its_event = find_event(its_service, its_instance, its_method); - if (its_event) { - if (its_event->is_field()) { - its_event->set_payload_dont_notify(_message->get_payload()); - } - } else { - // we received a event which was not yet requested - std::set<eventgroup_t> its_eventgroups; - // create a placeholder field until someone requests this event with - // full information like eventgroup, field or not etc. - routing_manager_base::register_event(host_->get_client(), - its_service, its_instance, - its_method, - its_eventgroups, event_type_e::ET_UNKNOWN, - reliability_type_e::RT_UNKNOWN, - std::chrono::milliseconds::zero(), false, true, - nullptr, - false, false, true); - std::shared_ptr<event> its_event = find_event(its_service, its_instance, its_method); - if (its_event) { - its_event->set_payload_dont_notify(_message->get_payload()); - } - } - -} - -void routing_manager_proxy::on_stop_offer_service(service_t _service, - instance_t _instance, - major_version_t _major, - minor_version_t _minor) { - (void) _major; - (void) _minor; - std::map<event_t, std::shared_ptr<event> > events; - { - std::lock_guard<std::mutex> its_lock(events_mutex_); - auto its_events_service = events_.find(_service); - if (its_events_service != events_.end()) { - auto its_events_instance = its_events_service->second.find(_instance); - if (its_events_instance != its_events_service->second.end()) { - for (auto &e : its_events_instance->second) - events[e.first] = e.second; - } - } - } - for (auto &e : events) { - e.second->unset_payload(); - } -} - -void routing_manager_proxy::send_pending_commands() { - for (auto &po : pending_offers_) - send_offer_service(client_, - po.service_, po.instance_, - po.major_, po.minor_); - - for (auto &per : pending_event_registrations_) - send_register_event(client_, - per.service_, per.instance_, - per.notifier_, - per.eventgroups_, per.type_, per.reliability_, - per.is_provided_); - - send_request_services(requests_); -} - -void routing_manager_proxy::init_receiver() { -#ifndef _WIN32 - auto its_security = security_impl::get(); - if (!its_security) - return; - - its_security->store_client_to_uid_gid_mapping(get_client(), own_uid_, own_gid_); - its_security->store_uid_gid_to_client_mapping(own_uid_, own_gid_, get_client()); -#endif - receiver_ = ep_mgr_->create_local_server(shared_from_this()); -} - -void routing_manager_proxy::notify_remote_initially(service_t _service, instance_t _instance, - eventgroup_t _eventgroup, const std::set<event_t> &_events_to_exclude) { - auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); - if (its_eventgroup) { - auto service_info = find_service(_service, _instance); - for (const auto &e : its_eventgroup->get_events()) { - if (e->is_field() && e->is_set() - && _events_to_exclude.find(e->get_event()) - == _events_to_exclude.end()) { - std::shared_ptr<message> its_notification - = runtime::get()->create_notification(); - its_notification->set_service(_service); - its_notification->set_instance(_instance); - its_notification->set_method(e->get_event()); - its_notification->set_payload(e->get_payload()); - if (service_info) { - its_notification->set_interface_version(service_info->get_major()); - } - - std::shared_ptr<serializer> its_serializer(get_serializer()); - if (its_serializer->serialize(its_notification.get())) { - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - send_local(sender_, VSOMEIP_ROUTING_CLIENT, its_serializer->get_data(), - its_serializer->get_size(), _instance, false, VSOMEIP_NOTIFY); - } - } - its_serializer->reset(); - put_serializer(its_serializer); - } else { - VSOMEIP_ERROR << "Failed to serialize message. Check message size!"; - } - } - } - } - -} - -uint32_t routing_manager_proxy::get_remote_subscriber_count(service_t _service, - instance_t _instance, eventgroup_t _eventgroup, bool _increment) { - std::lock_guard<std::mutex> its_lock(remote_subscriber_count_mutex_); - uint32_t count (0); - bool found(false); - auto found_service = remote_subscriber_count_.find(_service); - if (found_service != remote_subscriber_count_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto found_group = found_instance->second.find(_eventgroup); - if (found_group != found_instance->second.end()) { - found = true; - if (_increment) { - found_group->second = found_group->second + 1; - } else { - if (found_group->second > 0) { - found_group->second = found_group->second - 1; - } - } - count = found_group->second; - } - } - } - if (!found) { - if (_increment) { - remote_subscriber_count_[_service][_instance][_eventgroup] = 1; - count = 1; - } - } - return count; -} - -void routing_manager_proxy::clear_remote_subscriber_count( - service_t _service, instance_t _instance) { - std::lock_guard<std::mutex> its_lock(remote_subscriber_count_mutex_); - auto found_service = remote_subscriber_count_.find(_service); - if (found_service != remote_subscriber_count_.end()) { - if (found_service->second.erase(_instance)) { - if (!found_service->second.size()) { - remote_subscriber_count_.erase(found_service); - } - } - } -} - -void -routing_manager_proxy::assign_client_timeout_cbk( - boost::system::error_code const &_error) { - if (!_error) { - bool register_again(false); - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - if (state_ != inner_state_type_e::ST_REGISTERED) { - state_ = inner_state_type_e::ST_DEREGISTERED; - register_again = true; - } - } - if (register_again) { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - VSOMEIP_WARNING << std::hex << "Client 0x" << get_client() - << " request client timeout! Trying again..."; - - if (sender_) { - sender_->restart(); - } - } - } -} - -void routing_manager_proxy::register_application_timeout_cbk( - boost::system::error_code const &_error) { - - bool register_again(false); - { - std::lock_guard<std::mutex> its_lock(state_mutex_); - if (!_error && state_ != inner_state_type_e::ST_REGISTERED) { - state_ = inner_state_type_e::ST_DEREGISTERED; - register_again = true; - } - } - if (register_again) { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - VSOMEIP_WARNING << std::hex << "Client 0x" << get_client() - << " register timeout! Trying again..."; - - if (sender_) - sender_->restart(); - } -} - -void routing_manager_proxy::send_registered_ack() { - byte_t its_command[VSOMEIP_COMMAND_HEADER_SIZE] = { - VSOMEIP_REGISTERED_ACK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - client_t client = get_client(); - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client, - sizeof(client)); - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, VSOMEIP_COMMAND_HEADER_SIZE); - } - } -} - -bool routing_manager_proxy::is_client_known(client_t _client) { - std::lock_guard<std::mutex> its_lock(known_clients_mutex_); - return (known_clients_.find(_client) != known_clients_.end()); -} - -bool routing_manager_proxy::create_placeholder_event_and_subscribe( - service_t _service, instance_t _instance, - eventgroup_t _eventgroup, event_t _notifier, client_t _client) { - - std::lock_guard<std::mutex> its_lock(stop_mutex_); - - bool is_inserted(false); - - if (find_service(_service, _instance)) { - // We received an event for an existing service which was not yet - // requested/offered. Create a placeholder field until someone - // requests/offers this event with full information like eventgroup, - // field/event, etc. - std::set<eventgroup_t> its_eventgroups({ _eventgroup }); - // routing_manager_proxy: Always register with own client id and shadow = false - routing_manager_base::register_event(host_->get_client(), - _service, _instance, _notifier, - its_eventgroups, event_type_e::ET_UNKNOWN, reliability_type_e::RT_UNKNOWN, - std::chrono::milliseconds::zero(), false, true, nullptr, false, false, - true); - - std::shared_ptr<event> its_event = find_event(_service, _instance, _notifier); - if (its_event) { - is_inserted = its_event->add_subscriber(_eventgroup, _client, false); - } - } - - return is_inserted; -} - -void routing_manager_proxy::request_debounce_timeout_cbk( - boost::system::error_code const &_error) { - std::lock_guard<std::mutex> 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<std::mutex> 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<routing_manager_proxy>(shared_from_this()), - std::placeholders::_1)); - return; - } - } - } - } - { - std::lock_guard<std::mutex> 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) { - _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, true); - } else { - bool should_reconnect(true); - { - std::unique_lock<std::mutex> its_lock(state_mutex_); - should_reconnect = is_started_; - } - if (should_reconnect) { - std::unordered_set<client_t> its_known_clients; - { - std::lock_guard<std::mutex> its_lock(known_clients_mutex_); - its_known_clients = known_clients_; - } - reconnect(its_known_clients); - } - } -} - -void routing_manager_proxy::send_get_offered_services_info(client_t _client, offer_type_e _offer_type) { - (void)_client; - - byte_t its_command[VSOMEIP_OFFERED_SERVICES_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_OFFERED_SERVICES_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_OFFERED_SERVICES_REQUEST; - 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], &_offer_type, - sizeof(_offer_type)); - - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } -} - -void routing_manager_proxy::send_unsubscribe_ack( - service_t _service, instance_t _instance, eventgroup_t _eventgroup, - remote_subscription_id_t _id) { - byte_t its_command[VSOMEIP_UNSUBSCRIBE_ACK_COMMAND_SIZE]; - const std::uint32_t its_size = VSOMEIP_UNSUBSCRIBE_ACK_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - const client_t its_client = get_client(); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNSUBSCRIBE_ACK; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &its_client, - sizeof(its_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], &_id, - sizeof(_id)); - - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } -} - -void routing_manager_proxy::resend_provided_event_registrations() { - std::lock_guard<std::mutex> its_lock(state_mutex_); - for (const event_data_t& ed : pending_event_registrations_) { - if (ed.is_provided_) { - send_register_event(client_, ed.service_, ed.instance_, - ed.notifier_, ed.eventgroups_, ed.type_, ed.reliability_, - ed.is_provided_); - } - } -} - -void routing_manager_proxy::send_resend_provided_event_response(pending_remote_offer_id_t _id) { - byte_t its_command[VSOMEIP_RESEND_PROVIDED_EVENTS_COMMAND_SIZE]; - const std::uint32_t its_size = VSOMEIP_RESEND_PROVIDED_EVENTS_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - const client_t its_client = get_client(); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_RESEND_PROVIDED_EVENTS; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &its_client, - sizeof(its_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_id, - sizeof(pending_remote_offer_id_t)); - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } -} - -void routing_manager_proxy::send_update_security_policy_response(pending_security_update_id_t _update_id) { - byte_t its_command[VSOMEIP_UPDATE_SECURITY_POLICY_RESPONSE_COMMAND_SIZE]; - const std::uint32_t its_size = VSOMEIP_UPDATE_SECURITY_POLICY_RESPONSE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - const client_t its_client = get_client(); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UPDATE_SECURITY_POLICY_RESPONSE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &its_client, - sizeof(its_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_update_id, - sizeof(pending_security_update_id_t)); - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } -} - -void routing_manager_proxy::send_remove_security_policy_response(pending_security_update_id_t _update_id) { - byte_t its_command[VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE_COMMAND_SIZE]; - const std::uint32_t its_size = VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - const client_t its_client = get_client(); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &its_client, - sizeof(its_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_update_id, - sizeof(pending_security_update_id_t)); - { - std::lock_guard<std::mutex> its_lock(sender_mutex_); - if (sender_) { - sender_->send(its_command, sizeof(its_command)); - } - } -} - -void routing_manager_proxy::on_update_security_credentials(const byte_t *_data, uint32_t _size) { - auto its_security = security_impl::get(); - if (!its_security) - return; - - uint32_t i = 0; - while ( (i + sizeof(uint32_t) + sizeof(uint32_t)) <= _size) { - std::shared_ptr<policy> its_policy(std::make_shared<policy>()); - - boost::icl::interval_set<uint32_t> its_gid_set; - uint32_t its_uid, its_gid; - - std::memcpy(&its_uid, &_data[i], sizeof(uint32_t)); - i += uint32_t(sizeof(uint32_t)); - std::memcpy(&its_gid, &_data[i], sizeof(uint32_t)); - i += uint32_t(sizeof(uint32_t)); - - its_gid_set.insert(its_gid); - - its_policy->credentials_ += std::make_pair( - boost::icl::interval<uid_t>::closed(its_uid, its_uid), its_gid_set); - its_policy->allow_who_ = true; - its_policy->allow_what_ = true; - - its_security->add_security_credentials(its_uid, its_gid, its_policy, get_client()); - } -} - -void routing_manager_proxy::on_client_assign_ack(const client_t &_client) { - std::lock_guard<std::mutex> its_lock(state_mutex_); - if (state_ == inner_state_type_e::ST_ASSIGNING) { - if (_client != VSOMEIP_CLIENT_UNSET) { - state_ = inner_state_type_e::ST_ASSIGNED; - - boost::system::error_code ec; - register_application_timer_.cancel(ec); - host_->set_client(_client); - client_ = _client; - - if (is_started_) { - init_receiver(); - if (receiver_) { - receiver_->start(); - - VSOMEIP_INFO << std::hex << "Client " << client_ - << " (" << host_->get_name() - << ") successfully connected to routing ~> registering.."; - register_application(); - } else { - state_ = inner_state_type_e::ST_DEREGISTERED; - - host_->set_client(VSOMEIP_CLIENT_UNSET); - client_ = VSOMEIP_CLIENT_UNSET; - - sender_->restart(); - } - } - } else { - VSOMEIP_ERROR << "Didn't receive valid clientID! Won't register application."; - } - } else { - VSOMEIP_WARNING << "Client " << std::hex << client_ - << " received another client identifier (" - << std::hex << _client - << "). Ignoring it. (" - << (int)state_ << ")"; - } -} - -void routing_manager_proxy::on_suspend() { - - VSOMEIP_INFO << __func__ << ": Application " - << std::hex << std::setw(4) << std::setfill('0') - << host_->get_client(); - - std::lock_guard<std::mutex> its_lock(remote_subscriber_count_mutex_); - - // Unsubscribe everything that is left over. - for (const auto &s : remote_subscriber_count_) { - for (const auto &i : s.second) { - for (const auto e : i.second) - routing_manager_base::unsubscribe( - VSOMEIP_ROUTING_CLIENT, ANY_UID, ANY_GID, - s.first, i.first, e.first, ANY_EVENT); - } - } - - // Remove all entries. - remote_subscriber_count_.clear(); -} - -} // namespace vsomeip_v3 diff --git a/implementation/routing/src/routing_manager_stub.cpp b/implementation/routing/src/routing_manager_stub.cpp index 406b0d9..16ad36d 100644 --- a/implementation/routing/src/routing_manager_stub.cpp +++ b/implementation/routing/src/routing_manager_stub.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -11,28 +11,56 @@ #include <boost/system/error_code.hpp> #include <vsomeip/constants.hpp> +#include <vsomeip/error.hpp> +#include <vsomeip/payload.hpp> #include <vsomeip/primitive_types.hpp> #include <vsomeip/runtime.hpp> -#include <vsomeip/error.hpp> +#include <vsomeip/structured_types.hpp> #include <vsomeip/internal/logger.hpp> #include "../include/routing_manager_stub.hpp" #include "../include/routing_manager_stub_host.hpp" #include "../include/remote_subscription.hpp" #include "../../configuration/include/configuration.hpp" -#include "../../security/include/security.hpp" - -#include "../../endpoints/include/local_server_endpoint_impl.hpp" #include "../../endpoints/include/endpoint_manager_impl.hpp" +#include "../../endpoints/include/netlink_connector.hpp" +#include "../../protocol/include/deregister_application_command.hpp" +#include "../../protocol/include/distribute_security_policies_command.hpp" +#include "../../protocol/include/dummy_command.hpp" +#include "../../protocol/include/expire_command.hpp" +#include "../../protocol/include/offer_service_command.hpp" +#include "../../protocol/include/offered_services_request_command.hpp" +#include "../../protocol/include/offered_services_response_command.hpp" +#include "../../protocol/include/ping_command.hpp" +#include "../../protocol/include/pong_command.hpp" +#include "../../protocol/include/register_application_command.hpp" +#include "../../protocol/include/register_events_command.hpp" +#include "../../protocol/include/registered_ack_command.hpp" +#include "../../protocol/include/release_service_command.hpp" +#include "../../protocol/include/remove_security_policy_command.hpp" +#include "../../protocol/include/remove_security_policy_response_command.hpp" +#include "../../protocol/include/request_service_command.hpp" +#include "../../protocol/include/resend_provided_events_command.hpp" +#include "../../protocol/include/routing_info_command.hpp" +#include "../../protocol/include/send_command.hpp" +#include "../../protocol/include/stop_offer_service_command.hpp" +#include "../../protocol/include/subscribe_ack_command.hpp" +#include "../../protocol/include/subscribe_command.hpp" +#include "../../protocol/include/subscribe_nack_command.hpp" +#include "../../protocol/include/suspend_command.hpp" +#include "../../protocol/include/unregister_event_command.hpp" +#include "../../protocol/include/unsubscribe_ack_command.hpp" +#include "../../protocol/include/unsubscribe_command.hpp" +#include "../../protocol/include/update_security_credentials_command.hpp" +#include "../../protocol/include/update_security_policy_command.hpp" +#include "../../protocol/include/update_security_policy_response_command.hpp" +#include "../../security/include/policy_manager_impl.hpp" +#include "../../security/include/security.hpp" #include "../../utility/include/byteorder.hpp" #include "../../utility/include/utility.hpp" -#include "../implementation/message/include/payload_impl.hpp" namespace vsomeip_v3 { -const std::vector<byte_t> routing_manager_stub::its_ping_( - { VSOMEIP_PING, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); - routing_manager_stub::routing_manager_stub( routing_manager_stub_host *_host, const std::shared_ptr<configuration>& _configuration) : @@ -40,7 +68,7 @@ routing_manager_stub::routing_manager_stub( io_(_host->get_io()), watchdog_timer_(_host->get_io()), client_id_timer_(_host->get_io()), - endpoint_(nullptr), + root_(nullptr), local_receiver_(nullptr), configuration_(_configuration), is_socket_activated_(false), @@ -48,20 +76,31 @@ routing_manager_stub::routing_manager_stub( max_local_message_size_(configuration_->get_max_message_size_local()), configured_watchdog_timeout_(configuration_->get_watchdog_timeout()), pinged_clients_timer_(io_), - pending_security_update_id_(0) { + pending_security_update_id_(0) +#if defined(__linux__) || defined(ANDROID) + , is_local_link_available_(false) +#endif +{ } routing_manager_stub::~routing_manager_stub() { } void routing_manager_stub::init() { + init_routing_endpoint(); + + std::string its_env; + char its_hostname[1024]; + if (gethostname(its_hostname, sizeof(its_hostname)) == 0) + its_env = its_hostname; + host_->set_client_host(its_env); } void routing_manager_stub::start() { { std::lock_guard<std::mutex> its_lock(used_client_ids_mutex_); - used_client_ids_ = utility::get_used_client_ids(); + used_client_ids_ = utility::get_used_client_ids(configuration_->get_network()); // 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". @@ -73,12 +112,23 @@ void routing_manager_stub::start() { std::placeholders::_1)); } - if (!endpoint_) { - // application has been stopped and started again - init_routing_endpoint(); - } - if (endpoint_) { - endpoint_->start(); +#if defined(__linux__) || defined(ANDROID) + if (configuration_->is_local_routing()) { +#else + { +#endif // __linux__ || ANDROID + if (!root_) { + // application has been stopped and started again + init_routing_endpoint(); + } + if (root_) { + root_->start(); + } +#if defined(__linux__) || defined(ANDROID) + } else { + if (local_link_connector_) + local_link_connector_->start(); +#endif } client_registration_running_ = true; @@ -122,47 +172,60 @@ void routing_manager_stub::stop() { client_id_timer_.cancel(); } - if( !is_socket_activated_) { - endpoint_->stop(); - endpoint_ = nullptr; - std::stringstream its_endpoint_path; - its_endpoint_path << utility::get_base_path(configuration_) << std::hex - << VSOMEIP_ROUTING_CLIENT; -#ifdef _WIN32 - ::_unlink(its_endpoint_path.str().c_str()); -#else - if (-1 == ::unlink(its_endpoint_path.str().c_str())) { - VSOMEIP_ERROR << "routing_manager_stub::stop() unlink failed (" - << its_endpoint_path.str() << "): "<< std::strerror(errno); + bool is_local_routing(configuration_->is_local_routing()); + +#if defined(__linux__) || defined(ANDROID) + if (local_link_connector_) + local_link_connector_->stop(); +#endif // __linux__ || ANDROID + + if (!is_socket_activated_) { + root_->stop(); + root_ = nullptr; + + if (is_local_routing) { + std::stringstream its_endpoint_path; + its_endpoint_path << utility::get_base_path(configuration_->get_network()) + << std::hex << VSOMEIP_ROUTING_CLIENT; + #ifdef _WIN32 + ::_unlink(its_endpoint_path.str().c_str()); + #else + if (-1 == ::unlink(its_endpoint_path.str().c_str())) { + VSOMEIP_ERROR << "routing_manager_stub::stop() unlink failed (" + << its_endpoint_path.str() << "): "<< std::strerror(errno); + } + #endif } -#endif } - if(local_receiver_) { + if (local_receiver_) { local_receiver_->stop(); local_receiver_ = nullptr; - std::stringstream its_local_receiver_path; - its_local_receiver_path << utility::get_base_path(configuration_) - << std::hex << host_->get_client(); + + if (is_local_routing) { + std::stringstream its_local_receiver_path; + its_local_receiver_path << utility::get_base_path(configuration_->get_network()) + << std::hex << host_->get_client(); #ifdef _WIN32 - ::_unlink(its_local_receiver_path.str().c_str()); + ::_unlink(its_local_receiver_path.str().c_str()); #else - if (-1 == ::unlink(its_local_receiver_path.str().c_str())) { - VSOMEIP_ERROR << "routing_manager_stub::stop() unlink (local receiver) failed (" - << its_local_receiver_path.str() << "): "<< std::strerror(errno); - } + if (-1 == ::unlink(its_local_receiver_path.str().c_str())) { + VSOMEIP_ERROR << "routing_manager_stub::stop() unlink (local receiver) failed (" + << its_local_receiver_path.str() << "): "<< std::strerror(errno); + } #endif + } } } void routing_manager_stub::on_message(const byte_t *_data, length_t _size, - endpoint *_receiver, const boost::asio::ip::address &_destination, - client_t _bound_client, - credentials_t _credentials, + endpoint *_receiver, bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, const boost::asio::ip::address &_remote_address, std::uint16_t _remote_port) { + (void)_receiver; - (void)_destination; + (void)_is_multicast; (void)_remote_address; (void) _remote_port; #if 0 @@ -173,97 +236,118 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, VSOMEIP_INFO << msg.str(); #endif - std::uint32_t its_sender_uid = std::get<0>(_credentials); - std::uint32_t its_sender_gid = std::get<1>(_credentials); - - if (VSOMEIP_COMMAND_SIZE_POS_MAX < _size) { - byte_t its_command; - client_t its_client; - std::string its_client_endpoint; - service_t its_service; - instance_t its_instance; - method_t its_method; - eventgroup_t its_eventgroup; - event_t its_notifier; - event_type_e its_event_type; - bool is_provided(false); - major_version_t its_major; - minor_version_t its_minor; - std::shared_ptr<payload> its_payload; - const byte_t *its_data; - uint32_t its_size; - bool its_reliable(false); - client_t its_client_from_header; - client_t its_target_client; - client_t its_subscriber; - uint8_t its_check_status(0); - std::uint16_t its_subscription_id(PENDING_SUBSCRIPTION_ID); - offer_type_e its_offer_type; - - its_command = _data[VSOMEIP_COMMAND_TYPE_POS]; - std::memcpy(&its_client, &_data[VSOMEIP_COMMAND_CLIENT_POS], - sizeof(its_client)); - - if (security::get()->is_enabled() && _bound_client != its_client) { - VSOMEIP_WARNING << "vSomeIP Security: routing_manager_stub::on_message: " - << "Routing Manager received a message from client " - << std::hex << std::setw(4) << std::setfill('0') - << its_client << " with command " << (uint32_t)its_command - << " which doesn't match the bound client " - << std::setw(4) << std::setfill('0') << _bound_client - << " ~> skip message!"; - return; - } + client_t its_client; + protocol::id_e its_id; + std::string its_client_endpoint; + service_t its_service; + instance_t its_instance; + method_t its_method; + eventgroup_t its_eventgroup; + event_t its_notifier; + major_version_t its_major; + minor_version_t its_minor; + std::shared_ptr<payload> its_payload; + bool is_reliable(false); + client_t its_subscriber; + uint8_t its_check_status(0); + std::uint16_t its_subscription_id(PENDING_SUBSCRIPTION_ID); + port_t its_port(ILLEGAL_PORT); + + std::vector<byte_t> its_buffer(_data, _data + _size); + protocol::error_e its_error; + + // Use dummy command to deserialize id and client. + protocol::dummy_command its_base_command; + its_base_command.deserialize(its_buffer, its_error); + if (its_error != protocol::error_e::ERROR_OK) { - std::memcpy(&its_size, &_data[VSOMEIP_COMMAND_SIZE_POS_MIN], - sizeof(its_size)); + VSOMEIP_ERROR << __func__ + << ": deserialization of command and client identifier failed (" + << std::dec << static_cast<int>(its_error) + << ")"; + return; + } - if (its_size <= _size - VSOMEIP_COMMAND_HEADER_SIZE) { - switch (its_command) { - case VSOMEIP_REGISTER_APPLICATION: - if (_size != VSOMEIP_REGISTER_APPLICATION_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a REGISTER_APPLICATION command with wrong size ~> skip!"; - break; - } - update_registration(its_client, registration_type_e::REGISTER); - break; + its_client = its_base_command.get_client(); + its_id = its_base_command.get_id(); - case VSOMEIP_DEREGISTER_APPLICATION: - if (_size != VSOMEIP_DEREGISTER_APPLICATION_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a DEREGISTER_APPLICATION command with wrong size ~> skip!"; - break; - } - update_registration(its_client, registration_type_e::DEREGISTER); - break; + if (configuration_->is_security_enabled() + && configuration_->is_local_routing() + && _bound_client != its_client) { + VSOMEIP_WARNING << "vSomeIP Security: routing_manager_stub::on_message: " + << "Routing Manager received a message from client " + << std::hex << std::setw(4) << std::setfill('0') + << its_client << " with command " << (uint32_t)its_id + << " which doesn't match the bound client " + << std::setw(4) << std::setfill('0') << _bound_client + << " ~> skip message!"; + return; + } - case VSOMEIP_PONG: - if (_size != VSOMEIP_PONG_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a PONG command with wrong size ~> skip!"; - break; - } + switch (its_id) { + + case protocol::id_e::REGISTER_APPLICATION_ID: + { + protocol::register_application_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) + update_registration(its_command.get_client(), + registration_type_e::REGISTER, + _remote_address, its_command.get_port()); + else + VSOMEIP_ERROR << __func__ + << ": deserializing register application failed (" + << std::dec << static_cast<int>(its_error) << ")"; + + break; + } + + case protocol::id_e::DEREGISTER_APPLICATION_ID: + { + protocol::deregister_application_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) + update_registration(its_command.get_client(), + registration_type_e::DEREGISTER, + _remote_address, its_port); + else + VSOMEIP_ERROR << __func__ + << ": deserializing register application failed (" + << std::dec << static_cast<int>(its_error) << ")"; + + break; + } + + case protocol::id_e::PONG_ID: + { + protocol::pong_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { on_pong(its_client); VSOMEIP_TRACE << "PONG(" - << std::hex << std::setw(4) << std::setfill('0') << its_client << ")"; - break; - - case VSOMEIP_OFFER_SERVICE: - if (_size != VSOMEIP_OFFER_SERVICE_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a OFFER_SERVICE command with wrong size ~> skip!"; - break; - } + << std::hex << std::setw(4) << std::setfill('0') + << its_client << ")"; + } else + VSOMEIP_ERROR << __func__ + << ": deserializing pong failed (" + << std::dec << static_cast<int>(its_error) << ")"; + 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)); - - if (security::get()->is_offer_allowed(its_sender_uid, its_sender_gid, - its_client, its_service, its_instance)) { + case protocol::id_e::OFFER_SERVICE_ID: + { + protocol::offer_service_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_major = its_command.get_major(); + its_minor = its_command.get_minor(); + + if (VSOMEIP_SEC_OK == security::is_client_allowed_to_offer( + _sec_client, its_service, its_instance)) { host_->offer_service(its_client, its_service, its_instance, its_major, its_minor); } else { @@ -272,48 +356,54 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, << "the following service/instance " << its_service << "/" << its_instance << " ~> Skip offer!"; } - break; + } else + VSOMEIP_ERROR << __func__ + << ": deserializing offer service failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } - case VSOMEIP_STOP_OFFER_SERVICE: - if (_size != VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a STOP_OFFER_SERVICE 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_minor, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 5], - sizeof(its_minor)); - - host_->stop_offer_service(its_client, its_service, its_instance, its_major, its_minor); - break; - - case VSOMEIP_SUBSCRIBE: - if (_size != VSOMEIP_SUBSCRIBE_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a SUBSCRIBE 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_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_eventgroup)); - std::memcpy(&its_major, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(its_major)); - std::memcpy(&its_notifier, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7], - sizeof(its_notifier)); + case protocol::id_e::STOP_OFFER_SERVICE_ID: + { + protocol::stop_offer_service_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_major = its_command.get_major(); + its_minor = its_command.get_minor(); + + host_->stop_offer_service(its_client, + its_service, its_instance, + its_major, its_minor); + } else + VSOMEIP_ERROR << __func__ + << ": deserializing stop offer service failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::SUBSCRIBE_ID: + { + protocol::subscribe_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_eventgroup = its_command.get_eventgroup(); + its_major = its_command.get_major(); + its_notifier = its_command.get_event(); + auto its_filter = its_command.get_filter(); if (its_notifier == ANY_EVENT) { - if (host_->is_subscribe_to_any_event_allowed(_credentials, its_client, its_service, + if (host_->is_subscribe_to_any_event_allowed(_sec_client, its_client, its_service, its_instance, its_eventgroup)) { - host_->subscribe(its_client, its_sender_uid, its_sender_gid, its_service, its_instance, - its_eventgroup, its_major, its_notifier); + host_->subscribe(its_client, _sec_client, its_service, its_instance, + its_eventgroup, its_major, its_notifier, its_filter); } else { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client << " : routing_manager_stub::on_message: " @@ -322,10 +412,10 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, << " which violates the security policy ~> Skip subscribe!"; } } else { - if (security::get()->is_client_allowed(its_sender_uid, its_sender_gid, - its_client, its_service, its_instance, its_notifier)) { - host_->subscribe(its_client, its_sender_uid, its_sender_gid, its_service, its_instance, - its_eventgroup, its_major, its_notifier); + if (VSOMEIP_SEC_OK == security::is_client_allowed_to_access_member( + _sec_client, its_service, its_instance, its_notifier)) { + host_->subscribe(its_client, _sec_client, its_service, its_instance, + its_eventgroup, its_major, its_notifier, its_filter); } else { VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client << " : routing_manager_stub::on_message: " @@ -334,456 +424,397 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, << " which violates the security policy ~> Skip subscribe!"; } } - break; + } else + VSOMEIP_ERROR << __func__ + << ": deserializing subscribe failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::UNSUBSCRIBE_ID: + { + protocol::unsubscribe_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_eventgroup = its_command.get_eventgroup(); + its_notifier = its_command.get_event(); + + host_->unsubscribe(its_client, _sec_client, + its_service, its_instance, its_eventgroup, its_notifier); + } else + VSOMEIP_ERROR << __func__ + << ": deserializing unsubscribe failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::SUBSCRIBE_ACK_ID: + { + protocol::subscribe_ack_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_eventgroup = its_command.get_eventgroup(); + its_subscriber = its_command.get_subscriber(); + its_notifier = its_command.get_event(); + its_subscription_id = its_command.get_pending_id(); - case VSOMEIP_UNSUBSCRIBE: - if (_size != VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a UNSUBSCRIBE 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_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_eventgroup)); - std::memcpy(&its_notifier, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(its_notifier)); - - host_->unsubscribe(its_client, its_sender_uid, its_sender_gid, its_service, - its_instance, its_eventgroup, its_notifier); - break; - - case VSOMEIP_SUBSCRIBE_ACK: - if (_size != VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a SUBSCRIBE_ACK 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_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_eventgroup)); - std::memcpy(&its_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(its_subscriber)); - std::memcpy(&its_notifier, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], - sizeof(its_notifier)); - std::memcpy(&its_subscription_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 10], - sizeof(its_subscription_id)); host_->on_subscribe_ack(its_subscriber, its_service, its_instance, its_eventgroup, its_notifier, its_subscription_id); + VSOMEIP_INFO << "SUBSCRIBE ACK(" << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" << std::hex << std::setw(4) << std::setfill('0') << its_service << "." << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." << std::hex << std::setw(4) << std::setfill('0') << its_notifier << "]"; - break; + } else + VSOMEIP_ERROR << __func__ + << ": deserializing subscribe ack failed (" + << std::dec << static_cast<int>(its_error) << ")"; + + break; + } + + case protocol::id_e::SUBSCRIBE_NACK_ID: + { + protocol::subscribe_nack_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_eventgroup = its_command.get_eventgroup(); + its_subscriber = its_command.get_subscriber(); + its_notifier = its_command.get_event(); + its_subscription_id = its_command.get_pending_id(); - case VSOMEIP_SUBSCRIBE_NACK: - if (_size != VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a SUBSCRIBE_NACK 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_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_eventgroup)); - std::memcpy(&its_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(its_subscriber)); - std::memcpy(&its_notifier, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], - sizeof(its_notifier)); - std::memcpy(&its_subscription_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 10], - sizeof(its_subscription_id)); host_->on_subscribe_nack(its_subscriber, its_service, - its_instance, its_eventgroup, its_notifier, - its_subscription_id, false); + its_instance, its_eventgroup, its_notifier, its_subscription_id); + VSOMEIP_INFO << "SUBSCRIBE NACK(" << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" << std::hex << std::setw(4) << std::setfill('0') << its_service << "." << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "." << std::hex << std::setw(4) << std::setfill('0') << its_notifier << "]"; - break; - case VSOMEIP_UNSUBSCRIBE_ACK: - if (_size != VSOMEIP_UNSUBSCRIBE_ACK_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a VSOMEIP_UNSUBSCRIBE_ACK 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_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_eventgroup)); - std::memcpy(&its_subscription_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(its_subscription_id)); + } else + VSOMEIP_ERROR << __func__ + << ": deserializing subscribe nack failed (" + << std::dec << static_cast<int>(its_error) << ")"; + + break; + } + + case protocol::id_e::UNSUBSCRIBE_ACK_ID: + { + protocol::unsubscribe_ack_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_eventgroup = its_command.get_eventgroup(); + its_subscription_id = its_command.get_pending_id(); + host_->on_unsubscribe_ack(its_client, its_service, its_instance, its_eventgroup, its_subscription_id); + VSOMEIP_INFO << "UNSUBSCRIBE ACK(" << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" << std::hex << std::setw(4) << std::setfill('0') << its_service << "." << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "]"; - break; - case VSOMEIP_SEND: { - if (_size < VSOMEIP_SEND_COMMAND_SIZE + VSOMEIP_FULL_HEADER_SIZE) { - VSOMEIP_WARNING << "Received a SEND command with too small size ~> skip!"; - break; - } - its_data = &_data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS]; - its_service = VSOMEIP_BYTES_TO_WORD( - its_data[VSOMEIP_SERVICE_POS_MIN], - its_data[VSOMEIP_SERVICE_POS_MAX]); - its_client_from_header = VSOMEIP_BYTES_TO_WORD( - its_data[VSOMEIP_CLIENT_POS_MIN], - its_data[VSOMEIP_CLIENT_POS_MAX]); - its_method = VSOMEIP_BYTES_TO_WORD( - its_data[VSOMEIP_METHOD_POS_MIN], - its_data[VSOMEIP_METHOD_POS_MAX]); - std::memcpy(&its_instance, &_data[VSOMEIP_SEND_COMMAND_INSTANCE_POS_MIN], - sizeof(its_instance)); - std::memcpy(&its_reliable, &_data[VSOMEIP_SEND_COMMAND_RELIABLE_POS], - sizeof(its_reliable)); - std::memcpy(&its_check_status, &_data[VSOMEIP_SEND_COMMAND_CHECK_STATUS_POS], - sizeof(its_check_status)); - - // Allow response messages from local proxies as answer to remote requests - // but check requests sent by local proxies to remote against policy. - if (utility::is_request(its_data[VSOMEIP_MESSAGE_TYPE_POS])) { - if (!security::get()->is_client_allowed(its_sender_uid, its_sender_gid, - its_client_from_header, its_service, its_instance, its_method)) { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client_from_header - << " : routing_manager_stub::on_message: " - << " isn't allowed to send a request to service/instance/method " - << its_service << "/" << its_instance << "/" << its_method - << " ~> Skip message!"; - return; - } - } - // reduce by size of instance, flush, reliable, client and is_valid_crc flag - const std::uint32_t its_message_size = its_size - - (VSOMEIP_SEND_COMMAND_SIZE - VSOMEIP_COMMAND_HEADER_SIZE); - if (its_message_size != - VSOMEIP_BYTES_TO_LONG(_data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 1], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 2], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 3]) - + VSOMEIP_SOMEIP_HEADER_SIZE) { - VSOMEIP_WARNING << "Received a SEND command containing message with invalid size -> skip!"; - break; - } - host_->on_message(its_service, its_instance, its_data, its_message_size, - its_reliable, _bound_client, _credentials, its_check_status, false); - break; - } - case VSOMEIP_NOTIFY: { - if (_size < VSOMEIP_SEND_COMMAND_SIZE + VSOMEIP_FULL_HEADER_SIZE) { - VSOMEIP_WARNING << "Received a NOTIFY command with too small size ~> skip!"; - break; - } - its_data = &_data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS]; - its_service = VSOMEIP_BYTES_TO_WORD( - its_data[VSOMEIP_SERVICE_POS_MIN], - its_data[VSOMEIP_SERVICE_POS_MAX]); - std::memcpy(&its_instance, &_data[VSOMEIP_SEND_COMMAND_INSTANCE_POS_MIN], - sizeof(its_instance)); - // reduce by size of instance, flush, reliable, is_valid_crc flag and target client - const std::uint32_t its_message_size = its_size - - (VSOMEIP_SEND_COMMAND_SIZE - VSOMEIP_COMMAND_HEADER_SIZE); - if (its_message_size != - VSOMEIP_BYTES_TO_LONG(_data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 1], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 2], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 3]) - + VSOMEIP_SOMEIP_HEADER_SIZE) { - VSOMEIP_WARNING << "Received a NOTIFY command containing message with invalid size -> skip!"; - break; - } - host_->on_notification(VSOMEIP_ROUTING_CLIENT, its_service, its_instance, its_data, its_message_size); - break; - } - case VSOMEIP_NOTIFY_ONE: { - if (_size < VSOMEIP_SEND_COMMAND_SIZE + VSOMEIP_FULL_HEADER_SIZE) { - VSOMEIP_WARNING << "Received a NOTIFY_ONE command with too small size ~> skip!"; - break; - } - its_data = &_data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS]; - its_service = VSOMEIP_BYTES_TO_WORD( - its_data[VSOMEIP_SERVICE_POS_MIN], - its_data[VSOMEIP_SERVICE_POS_MAX]); - std::memcpy(&its_instance, &_data[VSOMEIP_SEND_COMMAND_INSTANCE_POS_MIN], - sizeof(its_instance)); - std::memcpy(&its_target_client, &_data[VSOMEIP_SEND_COMMAND_DST_CLIENT_POS_MIN], - sizeof(client_t)); - // reduce by size of instance, flush, reliable flag, is_valid_crc and target client - const std::uint32_t its_message_size = its_size - - (VSOMEIP_SEND_COMMAND_SIZE - VSOMEIP_COMMAND_HEADER_SIZE); - if (its_message_size != - VSOMEIP_BYTES_TO_LONG(_data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 1], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 2], - _data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS + VSOMEIP_LENGTH_POS_MIN + 3]) - + VSOMEIP_SOMEIP_HEADER_SIZE) { - VSOMEIP_WARNING << "Received a NOTIFY_ONE command containing message with invalid size -> skip!"; - break; - } - host_->on_notification(its_target_client, its_service, its_instance, - its_data, its_message_size, true); - break; - } - case VSOMEIP_REQUEST_SERVICE: - { - uint32_t entry_size = (sizeof(service_t) + sizeof(instance_t) - + sizeof(major_version_t) + sizeof(minor_version_t)); - if (its_size % entry_size > 0) { - VSOMEIP_WARNING << "Received a REQUEST_SERVICE command with invalid size -> skip!"; - break; - } - uint32_t request_count(its_size / entry_size); - std::set<service_data_t> 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; - 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)); - if (security::get()->is_client_allowed(its_sender_uid, its_sender_gid, - its_client, its_service, its_instance, 0x00, true)) { - host_->request_service(its_client, its_service, its_instance, - its_major, its_minor ); - service_data_t request = { - its_service, its_instance, - its_major, its_minor - }; - requests.insert(request); - } else { - VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex - << its_client << " : routing_manager_stub::on_message: " - << "requests service/instance " - << its_service << "/" << its_instance - << " which violates the security policy ~> Skip request!"; + } else + VSOMEIP_ERROR << __func__ + << ": deserializing unsubscribe ack failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::SEND_ID: + { + protocol::send_command its_command(its_id); + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + auto its_message_data(its_command.get_message()); + if (its_message_data.size() > VSOMEIP_MESSAGE_TYPE_POS) { + + its_service = VSOMEIP_BYTES_TO_WORD( + its_message_data[VSOMEIP_SERVICE_POS_MIN], + its_message_data[VSOMEIP_SERVICE_POS_MAX]); + its_method = VSOMEIP_BYTES_TO_WORD( + its_message_data[VSOMEIP_METHOD_POS_MIN], + its_message_data[VSOMEIP_METHOD_POS_MAX]); + its_client = VSOMEIP_BYTES_TO_WORD( + its_message_data[VSOMEIP_CLIENT_POS_MIN], + its_message_data[VSOMEIP_CLIENT_POS_MAX]); + + its_instance = its_command.get_instance(); + is_reliable = its_command.is_reliable(); + its_check_status = its_command.get_status(); + + // Allow response messages from local proxies as answer to remote requests + // but check requests sent by local proxies to remote against policy. + if (utility::is_request(its_message_data[VSOMEIP_MESSAGE_TYPE_POS])) { + if (VSOMEIP_SEC_OK != security::is_client_allowed_to_access_member( + _sec_client, its_service, its_instance, its_method)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_stub::on_message: " + << " isn't allowed to send a request to service/instance/method " + << its_service << "/" << its_instance << "/" << its_method + << " ~> Skip message!"; + return; } } - if (security::get()->is_enabled()) { - handle_credentials(its_client, requests); + // reduce by size of instance, flush, reliable, client and is_valid_crc flag + auto its_contained_size = VSOMEIP_BYTES_TO_LONG( + its_message_data[VSOMEIP_LENGTH_POS_MIN], + its_message_data[VSOMEIP_LENGTH_POS_MIN+1], + its_message_data[VSOMEIP_LENGTH_POS_MIN+2], + its_message_data[VSOMEIP_LENGTH_POS_MIN+3]); + if (its_message_data.size() != its_contained_size + VSOMEIP_SOMEIP_HEADER_SIZE) { + VSOMEIP_WARNING << "Received a SEND command containing message with invalid size -> skip!"; + break; } - handle_requests(its_client, requests); - break; + host_->on_message(its_service, its_instance, + &its_message_data[0], length_t(its_message_data.size()), + is_reliable, _bound_client, _sec_client, its_check_status, false); } + } + break; + } - case VSOMEIP_RELEASE_SERVICE: - if (_size != VSOMEIP_RELEASE_SERVICE_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a RELEASE_SERVICE command with wrong size ~> skip!"; + case protocol::id_e::NOTIFY_ID: + case protocol::id_e::NOTIFY_ONE_ID: + { + protocol::send_command its_command(its_id); + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + auto its_message_data(its_command.get_message()); + if (its_message_data.size() > VSOMEIP_MESSAGE_TYPE_POS) { + + its_client = its_command.get_target(); + its_service = VSOMEIP_BYTES_TO_WORD( + its_message_data[VSOMEIP_SERVICE_POS_MIN], + its_message_data[VSOMEIP_SERVICE_POS_MAX]); + its_instance = its_command.get_instance(); + + auto its_contained_size = VSOMEIP_BYTES_TO_LONG( + its_message_data[VSOMEIP_LENGTH_POS_MIN], + its_message_data[VSOMEIP_LENGTH_POS_MIN+1], + its_message_data[VSOMEIP_LENGTH_POS_MIN+2], + its_message_data[VSOMEIP_LENGTH_POS_MIN+3]); + if (its_message_data.size() != its_contained_size + VSOMEIP_SOMEIP_HEADER_SIZE) { + VSOMEIP_WARNING << "Received a NOTIFY command containing message with invalid 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)); - host_->release_service(its_client, its_service, its_instance); + host_->on_notification(its_client, its_service, its_instance, + &its_message_data[0], length_t(its_message_data.size()), + its_id == protocol::id_e::NOTIFY_ONE_ID); break; + } + } + break; + } - case VSOMEIP_REGISTER_EVENT: { - if (_size < VSOMEIP_REGISTER_EVENT_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a REGISTER_EVENT command with wrong size ~> skip!"; - break; + case protocol::id_e::REQUEST_SERVICE_ID: + { + protocol::request_service_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + its_client = its_command.get_client(); + auto its_requests = its_command.get_services(); + + std::set<protocol::service> its_allowed_requests; + for (const auto &r : its_requests) { + if (VSOMEIP_SEC_OK == security::is_client_allowed_to_request( + _sec_client, r.service_, r.instance_)) { + host_->request_service(its_client, + r.service_, r.instance_, r.major_, r.minor_); + its_allowed_requests.insert(r); } + } + if (configuration_->is_security_enabled()) { + handle_credentials(its_client, its_allowed_requests); + } + handle_requests(its_client, its_allowed_requests); + } else + VSOMEIP_ERROR << __func__ << ": request service deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; - std::set<eventgroup_t> its_eventgroups; - reliability_type_e its_reliability = reliability_type_e::RT_UNKNOWN; - - 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_notifier, - &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_notifier)); - std::memcpy(&its_event_type, - &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(its_event_type)); - std::memcpy(&is_provided, - &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7], - sizeof(is_provided)); - std::memcpy(&its_reliability, - &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], - sizeof(its_reliability)); - if (is_provided - && !configuration_->is_offered_remote(its_service, - its_instance)) { - break; + break; + } + + case protocol::id_e::RELEASE_SERVICE_ID: + { + protocol::release_service_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + host_->release_service(its_command.get_client(), + its_command.get_service(), its_command.get_instance()); + } else + VSOMEIP_ERROR << __func__ << ": release service deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::REGISTER_EVENT_ID: + { + protocol::register_events_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + for(std::size_t i = 0; i < its_command.get_num_registrations(); i++) { + protocol::register_event register_event; + if (!its_command.get_registration_at(i, register_event)) { + continue; } - for (std::size_t i = 9; i+1 < its_size; i++) { - std::memcpy(&its_eventgroup, - &_data[VSOMEIP_COMMAND_PAYLOAD_POS + i], - sizeof(its_eventgroup)); - its_eventgroups.insert(its_eventgroup); + + its_service = register_event.get_service(); + its_instance = register_event.get_instance(); + + if (register_event.is_provided() + && !configuration_->is_offered_remote(its_service, its_instance)) { + continue; } + host_->register_shadow_event(its_client, its_service, its_instance, - its_notifier, its_eventgroups, its_event_type, - its_reliability, - is_provided); + register_event.get_event(), register_event.get_eventgroups(), + register_event.get_event_type(), register_event.get_reliability(), + register_event.is_provided(), register_event.is_cyclic()); + VSOMEIP_INFO << "REGISTER EVENT(" << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." - << std::hex << std::setw(4) << std::setfill('0') << its_notifier - << ":is_provider=" << is_provided << ":reliability=" - << (std::uint32_t)(its_reliability) << "]"; - break; + << std::hex << std::setw(4) << std::setfill('0') << its_instance + << ":eventtype=" << std::dec << (int)register_event.get_event_type() + << ":is_provided=" << std::boolalpha << register_event.is_provided() + << ":reliable=" << std::dec << (int)register_event.get_reliability() << "]"; } - case VSOMEIP_UNREGISTER_EVENT: - if (_size != VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a UNREGISTER_EVENT 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_notifier, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], - sizeof(its_notifier)); - std::memcpy(&is_provided, - &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], - sizeof(is_provided)); - if (is_provided - && !configuration_->is_offered_remote(its_service, - its_instance)) { - break; - } - host_->unregister_shadow_event(its_client, its_service, its_instance, - its_notifier, is_provided); - VSOMEIP_INFO << "UNREGISTER EVENT(" - << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" - << std::hex << std::setw(4) << std::setfill('0') << its_service << "." - << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." - << std::hex << std::setw(4) << std::setfill('0') << its_notifier - << ":is_provider=" << is_provided << "]"; - break; - case VSOMEIP_REGISTERED_ACK: - if (_size != VSOMEIP_REGISTERED_ACK_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a REGISTERED_ACK command with wrong size ~> skip!"; - break; - } - VSOMEIP_INFO << "REGISTERED_ACK(" - << std::hex << std::setw(4) << std::setfill('0') << its_client << ")"; - break; - case VSOMEIP_OFFERED_SERVICES_REQUEST: { - if (_size != VSOMEIP_OFFERED_SERVICES_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a VSOMEIP_OFFERED_SERVICES_REQUEST command with wrong size ~> skip!"; - break; - } - std::memcpy(&its_offer_type, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], - sizeof(its_offer_type)); + } else + VSOMEIP_ERROR << __func__ << ": register event deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } - std::lock_guard<std::mutex> its_guard(routing_info_mutex_); - create_offered_services_info(its_client); - - for (const auto& found_client : routing_info_) { - // skip services which are offered on remote hosts - if (found_client.first != VSOMEIP_ROUTING_CLIENT) { - for (const auto &its_service : found_client.second.second) { - for (const auto &its_instance : its_service.second) { - uint16_t its_reliable_port = configuration_->get_reliable_port(its_service.first, - its_instance.first); - uint16_t its_unreliable_port = configuration_->get_unreliable_port( - its_service.first, its_instance.first); - - if (its_offer_type == offer_type_e::OT_LOCAL) { - if (its_reliable_port == ILLEGAL_PORT - && its_unreliable_port == ILLEGAL_PORT) { - insert_offered_services_info(its_client, - routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, - its_service.first, its_instance.first, - its_instance.second.first, its_instance.second.second); - } - } - else if (its_offer_type == offer_type_e::OT_REMOTE) { - if (its_reliable_port != ILLEGAL_PORT - || its_unreliable_port != ILLEGAL_PORT) { - insert_offered_services_info(its_client, - routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, - its_service.first, its_instance.first, - its_instance.second.first, its_instance.second.second); - } - } else if (its_offer_type == offer_type_e::OT_ALL) { - insert_offered_services_info(its_client, - routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, - its_service.first, its_instance.first, - its_instance.second.first, its_instance.second.second); - } - } - } - } - } - send_offered_services_info(its_client); - break; - } - case VSOMEIP_RESEND_PROVIDED_EVENTS: { - if (_size != VSOMEIP_RESEND_PROVIDED_EVENTS_COMMAND_SIZE) { - VSOMEIP_WARNING << "Received a RESEND_PROVIDED_EVENTS command with wrong size ~> skip!"; - break; - } - pending_remote_offer_id_t its_pending_remote_offer_id(0); - std::memcpy(&its_pending_remote_offer_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], - sizeof(pending_remote_offer_id_t)); - host_->on_resend_provided_events_response(its_pending_remote_offer_id); - VSOMEIP_INFO << "RESEND_PROVIDED_EVENTS(" - << std::hex << std::setw(4) << std::setfill('0') << its_client << ")"; - break; - } - case VSOMEIP_UPDATE_SECURITY_POLICY_RESPONSE: { - if (_size != VSOMEIP_UPDATE_SECURITY_POLICY_RESPONSE_COMMAND_SIZE) { - VSOMEIP_WARNING << "vSomeIP Security: Received a VSOMEIP_UPDATE_SECURITY_POLICY_RESPONSE " - << "command with wrong size ~> skip!"; - break; - } - pending_security_update_id_t its_pending_security_update_id(0); - std::memcpy(&its_pending_security_update_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], - sizeof(pending_security_update_id_t)); + case protocol::id_e::UNREGISTER_EVENT_ID: + { + protocol::unregister_event_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + host_->unregister_shadow_event(its_command.get_client(), + its_command.get_service(), its_command.get_instance(), + its_command.get_event(), its_command.is_provided()); + + VSOMEIP_INFO << "UNREGISTER EVENT(" + << std::hex << std::setw(4) << std::setfill('0') << its_command.get_client() << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_command.get_service() << "." + << std::hex << std::setw(4) << std::setfill('0') << its_command.get_instance() << "." + << std::hex << std::setw(4) << std::setfill('0') << its_command.get_event() + << ":is_provider=" << std::boolalpha << its_command.is_provided() << "]"; + } else + VSOMEIP_ERROR << __func__ << ": unregister event deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } - on_security_update_response(its_pending_security_update_id ,its_client); - break; - } - case VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE: { - if (_size != VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE_COMMAND_SIZE) { - VSOMEIP_WARNING << "vSomeIP Security: Received a VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE " - << "command with wrong size ~> skip!"; - break; - } - pending_security_update_id_t its_pending_security_update_id(0); - std::memcpy(&its_pending_security_update_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], - sizeof(pending_security_update_id_t)); + case protocol::id_e::REGISTERED_ACK_ID: + { + protocol::registered_ack_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + VSOMEIP_INFO << "REGISTERED_ACK(" + << std::hex << std::setw(4) << std::setfill('0') + << its_command.get_client() << ")"; + } else + VSOMEIP_ERROR << __func__ << ": registered ack deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } - on_security_update_response(its_pending_security_update_id ,its_client); - break; - } - } + case protocol::id_e::OFFERED_SERVICES_REQUEST_ID: + { + protocol::offered_services_request_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + on_offered_service_request(its_command.get_client(), its_command.get_offer_type()); + } else + VSOMEIP_ERROR << __func__ << ": offer service request deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::RESEND_PROVIDED_EVENTS_ID: + { + protocol::resend_provided_events_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + host_->on_resend_provided_events_response(its_command.get_remote_offer_id()); + VSOMEIP_INFO << "RESEND_PROVIDED_EVENTS(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << ")"; + } else + VSOMEIP_ERROR << __func__ << ": resend provided events deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } +#ifndef VSOMEIP_DISABLE_SECURITY + case protocol::id_e::UPDATE_SECURITY_POLICY_RESPONSE_ID: + { + protocol::update_security_policy_response_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + on_security_update_response(its_command.get_update_id(), its_client); + } else + VSOMEIP_ERROR << __func__ << ": update security policy deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::REMOVE_SECURITY_POLICY_RESPONSE_ID: + { + protocol::remove_security_policy_response_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + on_security_update_response(its_command.get_update_id(), its_client); + } else + VSOMEIP_ERROR << __func__ << ": update security policy deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; } +#endif // !VSOMEIP_DISABLE_SECURITY + default: + VSOMEIP_WARNING << __func__ << ": Received an unhandled command (" + << std::dec << static_cast<int>(its_id) << ")"; } } +void routing_manager_stub::add_known_client(client_t _client, const std::string &_client_host) { + host_->add_known_client(_client, _client_host); +} + void routing_manager_stub::on_register_application(client_t _client) { + auto endpoint = host_->find_local(_client); if (endpoint) { VSOMEIP_WARNING << "Reregistering application: " << std::hex << _client @@ -794,15 +825,21 @@ void routing_manager_stub::on_register_application(client_t _client) { std::lock_guard<std::mutex> its_lock(routing_info_mutex_); routing_info_[_client].first = 0; } +#ifndef VSOMEIP_DISABLE_SECURITY + if (configuration_->is_local_routing()) { + vsomeip_sec_client_t its_sec_client; + std::set<std::shared_ptr<policy> > its_policies; + + policy_manager_impl::get()->get_client_to_sec_client_mapping(_client, its_sec_client); + if (its_sec_client.client_type == VSOMEIP_CLIENT_UDS) { + get_requester_policies(its_sec_client.client.uds_client.user, + its_sec_client.client.uds_client.group, its_policies); + } - std::pair<uid_t, gid_t> its_uid_gid; - std::set<std::shared_ptr<policy> > its_policies; - - security::get()->get_client_to_uid_gid_mapping(_client, its_uid_gid); - get_requester_policies(its_uid_gid.first, its_uid_gid.second, its_policies); - - if (!its_policies.empty()) - send_requester_policies({ _client }, its_policies); + if (!its_policies.empty()) + send_requester_policies({ _client }, its_policies); + } +#endif // !VSOMEIP_DISABLE_SECURITY } } @@ -827,15 +864,59 @@ void routing_manager_stub::on_deregister_application(client_t _client) { routing_info_.erase(_client); } for (const auto &s : services_to_report) { - host_->on_availability(std::get<0>(s), std::get<1>(s), false, + host_->on_availability(std::get<0>(s), std::get<1>(s), + availability_state_e::AS_UNAVAILABLE, std::get<2>(s), std::get<3>(s)); host_->on_stop_offer_service(_client, std::get<0>(s), std::get<1>(s), std::get<2>(s), std::get<3>(s)); } } +void +routing_manager_stub::on_offered_service_request(client_t _client, + offer_type_e _offer_type) { + + protocol::offered_services_response_command its_command; + its_command.set_client(_client); + + for (const auto& found_client : routing_info_) { + // skip services which are offered on remote hosts + if (found_client.first != VSOMEIP_ROUTING_CLIENT) { + for (const auto &s : found_client.second.second) { + for (const auto &i : s.second) { + uint16_t its_reliable_port + = configuration_->get_reliable_port(s.first, i.first); + uint16_t its_unreliable_port + = configuration_->get_unreliable_port(s.first, i.first); + bool has_port = (its_reliable_port != ILLEGAL_PORT + || its_unreliable_port != ILLEGAL_PORT); + + if (_offer_type == offer_type_e::OT_ALL + || (_offer_type == offer_type_e::OT_LOCAL && !has_port) + || (_offer_type == offer_type_e::OT_REMOTE && has_port)) { + + protocol::service its_service(s.first, i.first, + i.second.first, i.second.second); + its_command.add_service(its_service); + } + } + } + } + } + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) + its_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size())); + } +} + void routing_manager_stub::client_registration_func(void) { -#ifndef _WIN32 +#if defined(__linux__) || defined(ANDROID) { std::stringstream s; s << std::hex << std::setw(4) << std::setfill('0') @@ -845,9 +926,9 @@ void routing_manager_stub::client_registration_func(void) { #endif std::unique_lock<std::mutex> its_lock(client_registration_mutex_); while (client_registration_running_) { - while (!pending_client_registrations_.size() && client_registration_running_) { - client_registration_condition_.wait(its_lock); - } + client_registration_condition_.wait(its_lock, [this] { + return pending_client_registrations_.size() || !client_registration_running_; + }); std::map<client_t, std::vector<registration_type_e>> its_registrations( pending_client_registrations_); @@ -867,44 +948,53 @@ void routing_manager_stub::client_registration_func(void) { // endpoint error to avoid writing in an already closed socket if (b != registration_type_e::DEREGISTER_ON_ERROR) { std::lock_guard<std::mutex> its_guard(routing_info_mutex_); - 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); - // distribute updated security config to new clients + add_connection(r.first, r.first); + protocol::routing_info_entry its_entry; + its_entry.set_client(r.first); if (b == registration_type_e::REGISTER) { + boost::asio::ip::address its_address; + port_t its_port; + + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_CLIENT); + if (host_->get_guest(r.first, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } +#ifndef VSOMEIP_DISABLE_SECURITY + // distribute updated security config to new clients send_cached_security_policies(r.first); +#endif // !VSOMEIP_DISABLE_SECURITY + } else { + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_DELETE_CLIENT); } - send_client_routing_info(r.first); + send_client_routing_info(r.first, its_entry); } if (b != registration_type_e::REGISTER) { { std::lock_guard<std::mutex> its_guard(routing_info_mutex_); - auto its_connection = connection_matrix_.find(r.first); - if (its_connection != connection_matrix_.end()) { - for (auto its_client : its_connection->second) { + auto find_connections = connection_matrix_.find(r.first); + if (find_connections != connection_matrix_.end()) { + for (auto its_client : find_connections->second) { if (its_client != r.first && its_client != VSOMEIP_ROUTING_CLIENT && its_client != get_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); + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_DELETE_CLIENT); + its_entry.set_client(r.first); + send_client_routing_info(its_client, its_entry); } } - connection_matrix_.erase(r.first); + remove_source(r.first); } - for (const auto& its_client : connection_matrix_) { - connection_matrix_[its_client.first].erase(r.first); + for (const auto &its_connections : connection_matrix_) { + remove_connection(its_connections.first, r.first); } service_requests_.erase(r.first); } // Don't remove client ID to UID maping as same client // could have passed its credentials again host_->remove_local(r.first, false); - utility::release_client_id(r.first); + utility::release_client_id(configuration_->get_network(), r.first); } } } @@ -913,9 +1003,75 @@ void routing_manager_stub::client_registration_func(void) { } void routing_manager_stub::init_routing_endpoint() { - endpoint_ = host_->get_endpoint_manager()->create_local_server( - &is_socket_activated_, shared_from_this()); + +#if defined(__linux__) || defined(ANDROID) + if (configuration_->is_local_routing()) { +#else + { +#endif // __linux__ || ANDROID + bool is_successful = host_->get_endpoint_manager()->create_routing_root( + root_, is_socket_activated_, shared_from_this()); + + if (!is_successful) { + VSOMEIP_WARNING << "Routing root creating (partially) failed. Please check your configuration."; + } +#if defined(__linux__) || defined(ANDROID) + } else { + auto its_host_address = configuration_->get_routing_host_address(); + local_link_connector_ = std::make_shared<netlink_connector>( + io_, its_host_address, boost::asio::ip::address(), false); // routing host doesn't need link up + if (local_link_connector_) { + local_link_connector_->register_net_if_changes_handler( + std::bind(&routing_manager_stub::on_net_state_change, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + } +#endif // __linux__ || ANDROID + } +} + +#if defined(__linux__) || defined(ANDROID) +void +routing_manager_stub::on_net_state_change( + bool _is_interface, const std::string &_name, bool _is_available) { + + VSOMEIP_INFO << __func__ + << "("<< std::hex << std::this_thread::get_id() << "): " + << std::boolalpha << _is_interface << " " + << _name << " " + << std::boolalpha << _is_available; + + if (_is_interface) { + if (_is_available) { + if (!is_local_link_available_) { + is_local_link_available_ = true; + if (!root_) + (void)host_->get_endpoint_manager()->create_routing_root( + root_, is_socket_activated_, shared_from_this()); + if (root_) { + VSOMEIP_INFO << __func__ + << ": Starting routing root."; + root_->start(); + } else + VSOMEIP_WARNING << "Routing root creating (partially) failed. " + "Please check your configuration."; + } + } else { + if (is_local_link_available_) { + + VSOMEIP_INFO << __func__ + << ": Stopping routing root."; + root_->stop(); + + routing_info_.clear(); + host_->clear_local_services(); + + is_local_link_available_ = false; + } + } + } } +#endif // __linux__ || ANDROID void routing_manager_stub::on_offer_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) { @@ -925,11 +1081,11 @@ void routing_manager_stub::on_offer_service(client_t _client, std::lock_guard<std::mutex> its_guard(routing_info_mutex_); routing_info_[_client].second[_service][_instance] = std::make_pair(_major, _minor); - if (security::get()->is_enabled()) { + if (configuration_->is_security_enabled()) { distribute_credentials(_client, _service, _instance); } inform_requesters(_client, _service, _instance, _major, _minor, - routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, true); + protocol::routing_info_entry_type_e::RIE_ADD_SERVICE_INSTANCE, true); } void routing_manager_stub::on_stop_offer_service(client_t _client, @@ -947,102 +1103,29 @@ void routing_manager_stub::on_stop_offer_service(client_t _client, if (0 == found_service->second.size()) { found_client->second.second.erase(_service); } - inform_provider(_client, _service, _instance, _major, _minor, - routing_info_entry_e::RIE_DEL_SERVICE_INSTANCE); inform_requesters(_client, _service, _instance, _major, _minor, - routing_info_entry_e::RIE_DEL_SERVICE_INSTANCE, false); + protocol::routing_info_entry_type_e::RIE_DELETE_SERVICE_INSTANCE, false); } else if( _major == DEFAULT_MAJOR && _minor == DEFAULT_MINOR) { found_service->second.erase(_instance); if (0 == found_service->second.size()) { found_client->second.second.erase(_service); } - inform_provider(_client, _service, _instance, _major, _minor, - routing_info_entry_e::RIE_DEL_SERVICE_INSTANCE); inform_requesters(_client, _service, _instance, _major, _minor, - routing_info_entry_e::RIE_DEL_SERVICE_INSTANCE, false); + protocol::routing_info_entry_type_e::RIE_DELETE_SERVICE_INSTANCE, false); } } } } } -void routing_manager_stub::create_client_routing_info(const client_t _target) { - std::vector<byte_t> its_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<const byte_t*>(&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); - } - - client_routing_info_[_target] = its_command; -} - -void routing_manager_stub::create_client_credentials_info(const client_t _target) { - std::vector<byte_t> its_command; - its_command.push_back(VSOMEIP_UPDATE_SECURITY_CREDENTIALS); - - // Sender client - client_t client = get_client(); - for (uint32_t i = 0; i < sizeof(client_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&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); - } - - client_credentials_info_[_target] = its_command; -} - -void routing_manager_stub::insert_client_credentials_info(client_t _target, std::set<std::pair<uint32_t, uint32_t>> _credentials) { - if (client_credentials_info_.find(_target) == client_credentials_info_.end()) { - return; - } - - auto its_command = client_credentials_info_[_target]; - - // insert uid / gid credential pairs - for (auto its_credentials : _credentials) { - //uid - for (uint32_t i = 0; i < sizeof(uint32_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&std::get<0>(its_credentials))[i]); - } - //gid - for (uint32_t i = 0; i < sizeof(uint32_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&std::get<1>(its_credentials))[i]); - } - } - - client_credentials_info_[_target] = its_command; -} - -void routing_manager_stub::send_client_credentials_info(const client_t _target) { - if (client_credentials_info_.find(_target) == client_credentials_info_.end()) { - return; - } +void routing_manager_stub::send_client_credentials(const client_t _target, + std::set<std::pair<uint32_t, uint32_t>> &_credentials) { std::shared_ptr<endpoint> its_endpoint = host_->find_local(_target); if (its_endpoint) { - auto its_command = client_credentials_info_[_target]; - - // File overall size - std::size_t its_size = its_command.size() - VSOMEIP_COMMAND_PAYLOAD_POS; - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, sizeof(uint32_t)); - its_size += VSOMEIP_COMMAND_PAYLOAD_POS; + protocol::update_security_credentials_command its_command; + its_command.set_client(_target); + its_command.set_credentials(_credentials); #if 0 std::stringstream msg; @@ -1052,235 +1135,66 @@ void routing_manager_stub::send_client_credentials_info(const client_t _target) VSOMEIP_INFO << msg.str(); #endif - // Send routing info or error! - if(its_command.size() <= max_local_message_size_ - || VSOMEIP_MAX_LOCAL_MESSAGE_SIZE == 0) { - its_endpoint->send(&its_command[0], uint32_t(its_size)); - } else { - VSOMEIP_ERROR << "Credentials info exceeds maximum message size: Can't send!"; - } - - client_credentials_info_.erase(_target); - } else { - VSOMEIP_ERROR << "Send credentials info to client 0x" << std::hex << _target - << " failed: No valid endpoint!"; - } -} - -void routing_manager_stub::create_offered_services_info(const client_t _target) { - std::vector<byte_t> its_command; - its_command.push_back(VSOMEIP_OFFERED_SERVICES_RESPONSE); - - // Sender client - client_t client = get_client(); - for (uint32_t i = 0; i < sizeof(client_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&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); - } - - offered_services_info_[_target] = its_command; -} - - -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<endpoint> 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; - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, sizeof(uint32_t)); - its_size += VSOMEIP_COMMAND_PAYLOAD_POS; - -#if 0 - std::stringstream msg; - msg << "rms::send_routing_info to (" << std::hex << _target << "): "; - for (uint32_t i = 0; i < its_size; ++i) - msg << std::hex << std::setw(2) << std::setfill('0') << (int)its_command[i] << " "; - VSOMEIP_INFO << msg.str(); -#endif - - // Send routing info or error! - if(its_command.size() <= max_local_message_size_ - || VSOMEIP_MAX_LOCAL_MESSAGE_SIZE == 0) { - its_endpoint->send(&its_command[0], uint32_t(its_size)); - } else { - VSOMEIP_ERROR << "Routing info exceeds maximum message size: Can't send!"; - } - - client_routing_info_.erase(_target); - } else { - VSOMEIP_ERROR << "Send routing info to client 0x" << std::hex << _target - << " failed: No valid endpoint!"; - } -} - - -void routing_manager_stub::send_offered_services_info(const client_t _target) { - if (offered_services_info_.find(_target) == offered_services_info_.end()) { - return; - } - std::shared_ptr<endpoint> its_endpoint = host_->find_local(_target); - if (its_endpoint) { - auto its_command = offered_services_info_[_target]; - - // File overall size - std::size_t its_size = its_command.size() - VSOMEIP_COMMAND_PAYLOAD_POS; - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, sizeof(uint32_t)); - its_size += VSOMEIP_COMMAND_PAYLOAD_POS; - -#if 0 - std::stringstream msg; - msg << "rms::send_offered_services_info to (" << std::hex << _target << "): "; - for (uint32_t i = 0; i < its_size; ++i) - msg << std::hex << std::setw(2) << std::setfill('0') << (int)its_command[i] << " "; - VSOMEIP_INFO << msg.str(); -#endif - - // Send routing info or error! - if(its_command.size() <= max_local_message_size_ - || VSOMEIP_MAX_LOCAL_MESSAGE_SIZE == 0) { - its_endpoint->send(&its_command[0], uint32_t(its_size)); - } else { - VSOMEIP_ERROR << "Offered services info exceeds maximum message size: Can't send!"; - } - - offered_services_info_.erase(_target); - } else { - VSOMEIP_ERROR << "Send offered services info to client 0x" << std::hex << _target - << " failed: No valid endpoint!"; - } + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + if(its_buffer.size() <= max_local_message_size_ + || VSOMEIP_MAX_LOCAL_MESSAGE_SIZE == 0) { + its_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": Credentials info exceeds maximum message size: Can't send!"; + + } else + VSOMEIP_ERROR << __func__ + << ": update security credentials command serialization failed (" + << static_cast<int>(its_error) + << ")"; + } else + VSOMEIP_ERROR << __func__ + << ": Sending credentials to client [" + << std::hex << std::setw(4) << std::setfill('0') + << _target + << "] failed"; } -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<const byte_t*>(&_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<const byte_t*>(&_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<const byte_t*>(&its_service_entry_size)[i]); - } - for (uint32_t i = 0; i < sizeof(service_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&_service)[i]); - } - // Instance - for (uint32_t i = 0; i < sizeof(instance_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&_instance)[i]); - } - // Major version - for (uint32_t i = 0; i < sizeof(major_version_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&_major)[i]); - } - // Minor version - for (uint32_t i = 0; i < sizeof(minor_version_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&_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)); +void routing_manager_stub::send_client_routing_info(const client_t _target, + protocol::routing_info_entry &_entry) { - client_routing_info_[_target] = its_command; + std::vector<protocol::routing_info_entry> its_entries; + its_entries.emplace_back(_entry); + send_client_routing_info(_target, std::move(its_entries)); } -void routing_manager_stub::insert_offered_services_info(client_t _target, - routing_info_entry_e _entry, - service_t _service, - instance_t _instance, - major_version_t _major, - minor_version_t _minor) { +void routing_manager_stub::send_client_routing_info(const client_t _target, + std::vector<protocol::routing_info_entry> &&_entries) { - if (offered_services_info_.find(_target) == offered_services_info_.end()) { - return; - } + auto its_target_endpoint = host_->find_local(_target); + if (its_target_endpoint) { - auto its_command = offered_services_info_[_target]; + protocol::routing_info_command its_command; + its_command.set_client(get_client()); + its_command.set_entries(std::move(_entries)); - // Routing Info State Change - for (uint32_t i = 0; i < sizeof(routing_info_entry_e); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&_entry)[i]); - } + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); - // entry size - 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<const byte_t*>(&its_service_entry_size)[i]); - } - //Service - for (uint32_t i = 0; i < sizeof(service_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&_service)[i]); - } - // Instance - for (uint32_t i = 0; i < sizeof(instance_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&_instance)[i]); - } - // Major version - for (uint32_t i = 0; i < sizeof(major_version_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&_major)[i]); - } - // Minor version - for (uint32_t i = 0; i < sizeof(minor_version_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&_minor)[i]); - } - - offered_services_info_[_target] = its_command; + if (its_error == protocol::error_e::ERROR_OK) { + its_target_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": routing info command serialization failed (" + << static_cast<int>(its_error) + << ")"; + } else + VSOMEIP_ERROR << __func__ + << ": Sending routing info to client [" + << std::hex << std::setw(4) << std::setfill('0') + << _target + << "] failed"; } void routing_manager_stub::distribute_credentials(client_t _hoster, service_t _service, instance_t _instance) { @@ -1298,38 +1212,30 @@ void routing_manager_stub::distribute_credentials(client_t _hoster, service_t _s } // search for UID / GID linked with the client ID that offers the requested services - std::pair<uint32_t, uint32_t> its_uid_gid; - if (security::get()->get_client_to_uid_gid_mapping(_hoster, its_uid_gid)) { + vsomeip_sec_client_t its_sec_client; + if (policy_manager_impl::get()->get_client_to_sec_client_mapping(_hoster, its_sec_client)) { + std::pair<uint32_t, uint32_t> its_uid_gid; + its_uid_gid.first = its_sec_client.client.uds_client.user; + its_uid_gid.second = its_sec_client.client.uds_client.group; its_credentials.insert(its_uid_gid); for (auto its_requesting_client : its_requesting_clients) { - std::pair<uint32_t, uint32_t> its_requester_uid_gid; - if (security::get()->get_client_to_uid_gid_mapping(its_requesting_client, its_requester_uid_gid)) { - if (its_uid_gid != its_requester_uid_gid) { - create_client_credentials_info(its_requesting_client); - insert_client_credentials_info(its_requesting_client, its_credentials); - send_client_credentials_info(its_requesting_client); - } + vsomeip_sec_client_t its_requester_sec_client; + if (policy_manager_impl::get()->get_client_to_sec_client_mapping( + its_requesting_client, its_requester_sec_client)) { + if (!utility::compare(its_sec_client, its_requester_sec_client)) + send_client_credentials(its_requesting_client, its_credentials); } } } } -void routing_manager_stub::inform_provider(client_t _hoster, service_t _service, +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) { + protocol::routing_info_entry_type_e _type, bool _inform_service) { - if (_hoster != VSOMEIP_ROUTING_CLIENT - && _hoster != host_->get_client()) { - create_client_routing_info(_hoster); - insert_client_routing_info(_hoster, _entry, _hoster, - _service, _instance, _major, _minor); - send_client_routing_info(_hoster); - } -}; + boost::asio::ip::address its_address; + port_t its_port; -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) { for (auto its_client : service_requests_) { auto its_service = its_client.second.find(_service); if (its_service != its_client.second.end()) { @@ -1338,31 +1244,39 @@ void routing_manager_stub::inform_requesters(client_t _hoster, service_t _servic if (_inform_service) { if (_hoster != VSOMEIP_ROUTING_CLIENT && _hoster != host_->get_client()) { - if (!is_already_connected(_hoster, its_client.first)) { - 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); + if (!is_connected(_hoster, its_client.first)) { + add_connection(_hoster, its_client.first); + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_CLIENT); + its_entry.set_client(its_client.first); + if (host_->get_guest(its_client.first, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } + send_client_routing_info(_hoster, its_entry); } } } if (its_client.first != VSOMEIP_ROUTING_CLIENT && its_client.first != get_client()) { - 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); + add_connection(its_client.first, _hoster); + protocol::routing_info_entry its_entry; + its_entry.set_type(_type); + its_entry.set_client(_hoster); + if ((_type == protocol::routing_info_entry_type_e::RIE_ADD_CLIENT + || _type == protocol::routing_info_entry_type_e::RIE_ADD_SERVICE_INSTANCE) + && host_->get_guest(_hoster, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } + its_entry.add_service({ _service, _instance, _major, _minor} ); + send_client_routing_info(its_client.first, its_entry); } } } } } -bool routing_manager_stub::is_already_connected(client_t _source, client_t _sink) { - return connection_matrix_[_source].find(_sink) != connection_matrix_[_source].end(); -} - void routing_manager_stub::broadcast(const std::vector<byte_t> &_command) const { std::lock_guard<std::mutex> its_guard(routing_info_mutex_); for (const auto& a : routing_info_) { @@ -1376,42 +1290,50 @@ void routing_manager_stub::broadcast(const std::vector<byte_t> &_command) const } } -bool routing_manager_stub::send_subscribe(const std::shared_ptr<endpoint>& _target, - client_t _client, service_t _service, instance_t _instance, +bool routing_manager_stub::send_subscribe( + const std::shared_ptr<endpoint>& _target, client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, - event_t _event, remote_subscription_id_t _id) { + event_t _event, const std::shared_ptr<debounce_filter_t> &_filter, + remote_subscription_id_t _id) { + + bool has_sent(false); + if (_target) { - byte_t its_command[VSOMEIP_SUBSCRIBE_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_SUBSCRIBE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, - sizeof(_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] = _major; - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7], &_event, - sizeof(_event)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 9], &_id, - sizeof(_id)); - - return _target->send(its_command, sizeof(its_command)); + + protocol::subscribe_command its_command; + its_command.set_client(_client); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_major(_major); + its_command.set_event(_event); + its_command.set_filter(_filter); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + has_sent = _target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": subscribe command serialization failed (" + << std::dec << int(its_error) << ")"; + } else { - VSOMEIP_WARNING << __func__ << " Couldn't send subscription to local client [" - << std::hex << std::setw(4) << std::setfill('0') << _service << "." - << std::hex << std::setw(4) << std::setfill('0') << _instance << "." - << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "." - << std::hex << std::setw(4) << std::setfill('0') << _event << "]" - << " subscriber: "<< std::hex << std::setw(4) << std::setfill('0') - << _client; - return false; + VSOMEIP_WARNING << __func__ + << " Couldn't send subscription to local client [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "." + << std::hex << std::setw(4) << std::setfill('0') << _event << "]" + << " subscriber: "<< std::hex << std::setw(4) << std::setfill('0') + << _client; } + + return (has_sent); } bool routing_manager_stub::send_unsubscribe( @@ -1419,37 +1341,41 @@ bool routing_manager_stub::send_unsubscribe( client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event, remote_subscription_id_t _id) { + + bool has_sent(false); + if (_target) { - byte_t its_command[VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNSUBSCRIBE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, - sizeof(_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], &_event, - sizeof(_event)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_id, - sizeof(_id)); - - return _target->send(its_command, sizeof(its_command)); + + protocol::unsubscribe_command its_command; + its_command.set_client(_client); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_event(_event); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + has_sent = _target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": unsubscribe command serialization failed (" + << std::dec << int(its_error) << ")"; } else { - VSOMEIP_WARNING << __func__ << " Couldn't send unsubscription to local client [" - << std::hex << std::setw(4) << std::setfill('0') << _service << "." - << std::hex << std::setw(4) << std::setfill('0') << _instance << "." - << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "." - << std::hex << std::setw(4) << std::setfill('0') << _event << "]" - << " subscriber: "<< std::hex << std::setw(4) << std::setfill('0') - << _client; - return false; + VSOMEIP_WARNING << __func__ + << " Couldn't send unsubscription to local client [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "." + << std::hex << std::setw(4) << std::setfill('0') << _event << "]" + << " subscriber: "<< std::hex << std::setw(4) << std::setfill('0') + << _client; } + + return (has_sent); } bool routing_manager_stub::send_expired_subscription( @@ -1457,100 +1383,94 @@ bool routing_manager_stub::send_expired_subscription( client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event, remote_subscription_id_t _id) { + + bool has_sent(false); + if (_target) { - byte_t its_command[VSOMEIP_EXPIRED_SUBSCRIPTION_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_EXPIRED_SUBSCRIPTION_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_EXPIRED_SUBSCRIPTION; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, - sizeof(_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], &_event, - sizeof(_event)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_id, - sizeof(_id)); - - return _target->send(its_command, sizeof(its_command)); + + protocol::expire_command its_command; + its_command.set_client(_client); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_event(_event); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + has_sent = _target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": unsubscribe command serialization failed (" + << std::dec << int(its_error) << ")"; } else { - VSOMEIP_WARNING << __func__ << " Couldn't send expired subscription to local client [" - << std::hex << std::setw(4) << std::setfill('0') << _service << "." - << std::hex << std::setw(4) << std::setfill('0') << _instance << "." - << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "." - << std::hex << std::setw(4) << std::setfill('0') << _event << "]" - << " subscriber: "<< std::hex << std::setw(4) << std::setfill('0') - << _client; - return false; + VSOMEIP_WARNING << __func__ + << " Couldn't send expired subscription to local client [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "." + << std::hex << std::setw(4) << std::setfill('0') << _event << "]" + << " subscriber: "<< std::hex << std::setw(4) << std::setfill('0') + << _client; } + + return (has_sent); } void routing_manager_stub::send_subscribe_ack(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { - std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); - if (its_endpoint) { - byte_t its_command[VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - client_t this_client = get_client(); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_ACK; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &this_client, - sizeof(this_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], &_client, - sizeof(_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_event, - sizeof(_event)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 10], - &PENDING_SUBSCRIPTION_ID, sizeof(PENDING_SUBSCRIPTION_ID)); - - its_endpoint->send(&its_command[0], sizeof(its_command)); + std::shared_ptr<endpoint> its_target = host_->find_local(_client); + if (its_target) { + + protocol::subscribe_ack_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_subscriber(_client); + its_command.set_event(_event); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + (void)its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": subscribe ack command serialization failed (" + << std::dec << int(its_error) << ")"; } } void routing_manager_stub::send_subscribe_nack(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { - std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); - if (its_endpoint) { - byte_t its_command[VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - client_t this_client = get_client(); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_NACK; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &this_client, - sizeof(this_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6], &_client, - sizeof(_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_event, - sizeof(_event)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 10], - &PENDING_SUBSCRIPTION_ID, sizeof(PENDING_SUBSCRIPTION_ID)); - - its_endpoint->send(&its_command[0], sizeof(its_command)); + std::shared_ptr<endpoint> its_target = host_->find_local(_client); + if (its_target) { + + protocol::subscribe_nack_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_subscriber(_client); + its_command.set_event(_event); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + (void)its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": subscribe ack command serialization failed (" + << std::dec << int(its_error) << ")"; } } @@ -1576,7 +1496,19 @@ bool routing_manager_stub::contained_in_routing_info( // Watchdog void routing_manager_stub::broadcast_ping() const { - broadcast(its_ping_); + + protocol::ping_command its_command; + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) + broadcast(its_buffer); + else + VSOMEIP_ERROR << __func__ + << ": ping command serialization failed (" + << std::dec << int(its_error) << ")"; } void routing_manager_stub::on_pong(client_t _client) { @@ -1656,8 +1588,8 @@ void routing_manager_stub::create_local_receiver() { if (local_receiver_) { return; } -#ifndef _WIN32 - else if (!security::get()->check_credentials(get_client(), getuid(), getgid())) { +#if defined(__linux__) || defined(ANDROID) + else if (!policy_manager_impl::get()->check_credentials(get_client(), host_->get_sec_client())) { VSOMEIP_ERROR << "vSomeIP Security: Client 0x" << std::hex << get_client() << " : routing_manager_stub::create_local_receiver: isn't allowed" << " to create a server endpoint due to credential check failed!"; @@ -1666,56 +1598,71 @@ void routing_manager_stub::create_local_receiver() { #endif local_receiver_ = std::static_pointer_cast<endpoint_manager_base>( host_->get_endpoint_manager())->create_local_server(shared_from_this()); - local_receiver_->start(); + + if (local_receiver_) + local_receiver_->start(); } bool routing_manager_stub::send_ping(client_t _client) { - std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); - if (!its_endpoint) { - return false; - } - { + bool has_sent(false); + + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) { std::lock_guard<std::mutex> its_lock(pinged_clients_mutex_); if (pinged_clients_.find(_client) != pinged_clients_.end()) { // client was already pinged: don't ping again and wait for answer // or timeout of previous ping. - return true; - } - - boost::system::error_code ec; - pinged_clients_timer_.cancel(ec); - if (ec) { - VSOMEIP_ERROR << "routing_manager_stub::send_ping cancellation of " - "timer failed: " << ec.message(); - } - const std::chrono::steady_clock::time_point now( - std::chrono::steady_clock::now()); + has_sent = true; + } else { + boost::system::error_code ec; + pinged_clients_timer_.cancel(ec); + if (ec) { + VSOMEIP_ERROR << "routing_manager_stub::send_ping cancellation of " + "timer failed: " << ec.message(); + } + const std::chrono::steady_clock::time_point now( + std::chrono::steady_clock::now()); - std::chrono::milliseconds next_timeout(configured_watchdog_timeout_); - for (const auto &tp : pinged_clients_) { - const std::chrono::milliseconds its_clients_timeout = - std::chrono::duration_cast<std::chrono::milliseconds>( - now - tp.second); - if (next_timeout > its_clients_timeout) { - next_timeout = its_clients_timeout; + std::chrono::milliseconds next_timeout(configured_watchdog_timeout_); + for (const auto &tp : pinged_clients_) { + const std::chrono::milliseconds its_clients_timeout = + std::chrono::duration_cast<std::chrono::milliseconds>( + now - tp.second); + if (next_timeout > its_clients_timeout) { + next_timeout = its_clients_timeout; + } } - } - pinged_clients_[_client] = now; + pinged_clients_[_client] = now; - ec.clear(); - pinged_clients_timer_.expires_from_now(next_timeout, ec); - if (ec) { - VSOMEIP_ERROR<< "routing_manager_stub::send_ping setting " - "expiry time of timer failed: " << ec.message(); + ec.clear(); + pinged_clients_timer_.expires_from_now(next_timeout, ec); + if (ec) { + VSOMEIP_ERROR << "routing_manager_stub::send_ping setting " + "expiry time of timer failed: " << ec.message(); + } + pinged_clients_timer_.async_wait( + std::bind(&routing_manager_stub::on_ping_timer_expired, this, + std::placeholders::_1)); + + protocol::ping_command its_command; + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) + has_sent = its_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size())); + else + VSOMEIP_ERROR << __func__ + << ": ping command serialization failed (" + << std::dec << int(its_error) << ")"; } - pinged_clients_timer_.async_wait( - std::bind(&routing_manager_stub::on_ping_timer_expired, this, - std::placeholders::_1)); - return its_endpoint->send(&its_ping_[0], uint32_t(its_ping_.size())); } + + return (has_sent); } void routing_manager_stub::on_ping_timer_expired( @@ -1821,19 +1768,33 @@ bool routing_manager_stub::is_registered(client_t _client) const { } void routing_manager_stub::update_registration(client_t _client, - registration_type_e _type) { + registration_type_e _type, + const boost::asio::ip::address &_address, port_t _port) { + + std::stringstream its_client; + its_client << std::hex << std::setw(4) << std::setfill('0') + << _client; + + if (_port > 0 && _port < ILLEGAL_PORT) { + its_client << " @ " << _address.to_string() << ":" << std::dec << _port; + } VSOMEIP_INFO << "Application/Client " - << std::hex << std::setw(4) << std::setfill('0') << _client + << its_client.str() << " is " << (_type == registration_type_e::REGISTER ? "registering." : "deregistering."); if (_type != registration_type_e::REGISTER) { - security::get()->remove_client_to_uid_gid_mapping(_client); + policy_manager_impl::get()->remove_client_to_sec_client_mapping(_client); + } else { + if (_port > 0 && _port < ILLEGAL_PORT) + host_->add_guest(_client, _address, _port); } if (_type == registration_type_e::DEREGISTER) { + host_->remove_guest(_client); + // If we receive a DEREGISTER client command // the endpoint error handler is not longer needed // as the client is going down anyways. @@ -1868,15 +1829,15 @@ client_t routing_manager_stub::get_client() const { return host_->get_client(); } -void routing_manager_stub::handle_credentials(const client_t _client, std::set<service_data_t>& _requests) { +void routing_manager_stub::handle_credentials(const client_t _client, std::set<protocol::service> &_requests) { if (!_requests.size()) { return; } std::lock_guard<std::mutex> its_guard(routing_info_mutex_); std::set<std::pair<uint32_t, uint32_t>> its_credentials; - std::pair<uint32_t, uint32_t> its_requester_uid_gid; - if (security::get()->get_client_to_uid_gid_mapping(_client, its_requester_uid_gid)) { + vsomeip_sec_client_t its_requester_sec_client; + if (policy_manager_impl::get()->get_client_to_sec_client_mapping(_client, its_requester_sec_client)) { // determine credentials of offering clients using current routing info std::set<client_t> its_offering_clients; @@ -1891,65 +1852,79 @@ void routing_manager_stub::handle_credentials(const client_t _client, std::set<s // search for UID / GID linked with the client ID that offers the requested services for (auto its_offering_client : its_offering_clients) { - std::pair<uint32_t, uint32_t> its_uid_gid; - if (security::get()->get_client_to_uid_gid_mapping(its_offering_client, its_uid_gid)) { - if (its_uid_gid != its_requester_uid_gid) { - its_credentials.insert(std::make_pair(std::get<0>(its_uid_gid), std::get<1>(its_uid_gid))); + vsomeip_sec_client_t its_sec_client; + if (policy_manager_impl::get()->get_client_to_sec_client_mapping(its_offering_client, its_sec_client)) { + if (its_sec_client.client_type == VSOMEIP_CLIENT_UDS + && !utility::compare(its_sec_client, its_requester_sec_client)) { + + its_credentials.insert(std::make_pair( + its_sec_client.client.uds_client.user, its_sec_client.client.uds_client.group)); } } } // send credentials to clients - if (!its_credentials.empty()) { - create_client_credentials_info(_client); - insert_client_credentials_info(_client, its_credentials); - send_client_credentials_info(_client); - } + if (!its_credentials.empty()) + send_client_credentials(_client, its_credentials); } } -void routing_manager_stub::handle_requests(const client_t _client, std::set<service_data_t>& _requests) { - if (!_requests.size()) { +void routing_manager_stub::handle_requests(const client_t _client, std::set<protocol::service> &_requests) { + + if (_requests.empty()) return; - } - bool service_available(false); + + boost::asio::ip::address its_address; + port_t its_port; + + std::vector<protocol::routing_info_entry> its_entries; std::lock_guard<std::mutex> its_guard(routing_info_mutex_); - create_client_routing_info(_client); + for (auto request : _requests) { service_requests_[_client][request.service_][request.instance_] - = std::make_pair(request.major_, request.minor_); + = std::make_pair(request.major_, request.minor_); if (request.instance_ == ANY_INSTANCE) { std::set<client_t> its_clients = host_->find_local_clients(request.service_, request.instance_); - // insert VSOMEIP_ROUTING_CLIENT to check wether service is remotely offered + // insert VSOMEIP_ROUTING_CLIENT to check whether service is remotely offered its_clients.insert(VSOMEIP_ROUTING_CLIENT); for (const client_t c : its_clients) { if (c != VSOMEIP_ROUTING_CLIENT && c != host_->get_client()) { - if (!is_already_connected(c, _client)) { + if (!is_connected(c, _client)) { + add_connection(c, _client); + + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_CLIENT); + its_entry.set_client(_client); + if (host_->get_guest(_client, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } if (_client == c) { - service_available = true; - insert_client_routing_info(c, - routing_info_entry_e::RIE_ADD_CLIENT, _client); + its_entries.emplace_back(its_entry); } else { - create_client_routing_info(c); - insert_client_routing_info(c, - routing_info_entry_e::RIE_ADD_CLIENT, _client); - send_client_routing_info(c); + send_client_routing_info(c, its_entry); } } } - if (_client != VSOMEIP_ROUTING_CLIENT && - _client != host_->get_client()) { + if (_client != VSOMEIP_ROUTING_CLIENT && _client != host_->get_client()) { const auto found_client = routing_info_.find(c); if (found_client != routing_info_.end()) { const auto found_service = found_client->second.second.find(request.service_); if (found_service != found_client->second.second.end()) { for (auto instance : found_service->second) { - service_available = true; - insert_client_routing_info(_client, - routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, - c, request.service_, instance.first, - instance.second.first, instance.second.second); + add_connection(_client, c); + + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_SERVICE_INSTANCE); + its_entry.set_client(c); + if (host_->get_guest(c, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } + its_entry.add_service({ request.service_, instance.first, + instance.second.first, instance.second.second }); + its_entries.emplace_back(its_entry); } } } @@ -1963,38 +1938,46 @@ void routing_manager_stub::handle_requests(const client_t _client, std::set<serv if (found_service != found_client->second.second.end()) { const auto found_instance = found_service->second.find(request.instance_); if (found_instance != found_service->second.end()) { - if (c != VSOMEIP_ROUTING_CLIENT && - c != host_->get_client()) { - if (!is_already_connected(c, _client)) { + if (c != VSOMEIP_ROUTING_CLIENT && c != host_->get_client()) { + if (!is_connected(c, _client)) { + add_connection(c, _client); + + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_CLIENT); + its_entry.set_client(_client); + if (host_->get_guest(_client, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } if (_client == c) { - service_available = true; - insert_client_routing_info(c, - routing_info_entry_e::RIE_ADD_CLIENT, _client); + its_entries.emplace_back(its_entry); } else { - create_client_routing_info(c); - insert_client_routing_info(c, - routing_info_entry_e::RIE_ADD_CLIENT, _client); - send_client_routing_info(c); + send_client_routing_info(c, its_entry); } } } - if (_client != VSOMEIP_ROUTING_CLIENT && - _client != host_->get_client()) { - service_available = true; - insert_client_routing_info(_client, - routing_info_entry_e::RIE_ADD_SERVICE_INSTANCE, - c, request.service_, request.instance_, - found_instance->second.first, - found_instance->second.second); + if (_client != VSOMEIP_ROUTING_CLIENT && _client != host_->get_client()) { + add_connection(_client, c); + + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_SERVICE_INSTANCE); + its_entry.set_client(c); + if (host_->get_guest(c, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } + its_entry.add_service({ request.service_, request.instance_, + found_instance->second.first, found_instance->second.second }); + its_entries.emplace_back(its_entry); } } } } } } - if (service_available) { - send_client_routing_info(_client); - } + + if (!its_entries.empty()) + send_client_routing_info(_client, std::move(its_entries)); } void routing_manager_stub::on_client_id_timer_expired(boost::system::error_code const &_error) { @@ -2029,34 +2012,37 @@ void routing_manager_stub::print_endpoint_status() const { if (local_receiver_) { local_receiver_->print_status(); } - if (endpoint_) { - endpoint_->print_status(); + if (root_) { + root_->print_status(); } } -bool routing_manager_stub::send_provided_event_resend_request(client_t _client, - pending_remote_offer_id_t _id) { +bool routing_manager_stub::send_provided_event_resend_request( + client_t _client, pending_remote_offer_id_t _id) { + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); if (its_endpoint) { - byte_t its_command[VSOMEIP_RESEND_PROVIDED_EVENTS_COMMAND_SIZE]; - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_RESEND_PROVIDED_EVENTS; - const client_t routing_client(VSOMEIP_ROUTING_CLIENT); - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &routing_client, - sizeof(routing_client)); - std::uint32_t its_size = sizeof(pending_remote_offer_id_t); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_id, - sizeof(pending_remote_offer_id_t)); - return its_endpoint->send(its_command, sizeof(its_command)); + + protocol::resend_provided_events_command its_command; + its_command.set_client(VSOMEIP_ROUTING_CLIENT); + its_command.set_remote_offer_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) + return (its_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size()))); } else { VSOMEIP_WARNING << __func__ << " Couldn't send provided event resend " "request to local client: 0x" << std::hex << std::setw(4) << std::setfill('0') << _client; - return false; } + + return (false); } +#ifndef VSOMEIP_DISABLE_SECURITY bool routing_manager_stub::is_policy_cached(uint32_t _uid) { { std::lock_guard<std::mutex> its_lock(updated_security_policies_mutex_); @@ -2089,11 +2075,16 @@ void routing_manager_stub::policy_cache_remove(uint32_t _uid) { bool routing_manager_stub::send_update_security_policy_request(client_t _client, pending_security_update_id_t _update_id, uint32_t _uid, const std::shared_ptr<payload>& _payload) { (void)_uid; + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); if (its_endpoint) { std::vector<byte_t> its_command; // command - its_command.push_back(VSOMEIP_UPDATE_SECURITY_POLICY); + its_command.push_back(byte_t(protocol::id_e::UPDATE_SECURITY_POLICY_ID)); + + // version + its_command.push_back(0x00); + its_command.push_back(0x00); // client ID for (uint32_t i = 0; i < sizeof(client_t); ++i) { @@ -2123,89 +2114,74 @@ bool routing_manager_stub::send_update_security_policy_request(client_t _client, } bool routing_manager_stub::send_cached_security_policies(client_t _client) { - std::vector<byte_t> its_command; - std::size_t its_size(0); - std::lock_guard<std::mutex> its_lock(updated_security_policies_mutex_); - uint32_t its_policy_count = uint32_t(updated_security_policies_.size()); + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) { - if (!its_policy_count) { - return true; - } - VSOMEIP_INFO << __func__ << " Distributing [" - << std::dec << its_policy_count - << "] security policy updates to registering client: " - << std::hex << _client; + std::lock_guard<std::mutex> its_lock(updated_security_policies_mutex_); + if (!updated_security_policies_.empty()) { - // command - its_command.push_back(VSOMEIP_DISTRIBUTE_SECURITY_POLICIES); + VSOMEIP_INFO << __func__ << " Distributing [" + << std::dec << updated_security_policies_.size() + << "] security policy updates to registering client: " + << std::hex << _client; - // client ID - client_t its_client = get_client(); - for (uint32_t i = 0; i < sizeof(client_t); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&its_client)[i]); - } + protocol::distribute_security_policies_command its_command; + its_command.set_client(get_client()); + its_command.set_payloads(updated_security_policies_); - //overall size (placeholder - for (uint32_t i = 0; i < sizeof(uint32_t); ++i) { - its_command.push_back(0x00); - } + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); - // number of policies contained in message - for (uint32_t i = 0; i < sizeof(its_policy_count); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&its_policy_count)[i]); - } + if (its_error == protocol::error_e::ERROR_OK) + return its_endpoint->send(its_buffer.data(), uint32_t(its_buffer.size())); - for (const auto& its_uid_gid : updated_security_policies_) { - // policy payload length including gid and uid - std::uint32_t its_length = uint32_t(its_uid_gid.second->get_length()); - for (uint32_t i = 0; i < sizeof(its_length); ++i) { - its_command.push_back( - reinterpret_cast<const byte_t*>(&its_length)[i]); + VSOMEIP_ERROR << __func__ + << ": serializing distribute security policies (" + << static_cast<int>(its_error) + << ")"; } - // payload - its_command.insert(its_command.end(), its_uid_gid.second->get_data(), - its_uid_gid.second->get_data() + its_uid_gid.second->get_length()); - } - // File overall size - its_size = its_command.size() - VSOMEIP_COMMAND_PAYLOAD_POS; - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, sizeof(uint32_t)); + } else + VSOMEIP_WARNING << __func__ + << ": could not send cached security policies to registering client: 0x" + << std::hex << std::setw(4) << std::setfill('0') << _client; + + return (false); +} + +bool routing_manager_stub::send_remove_security_policy_request( + client_t _client, pending_security_update_id_t _update_id, + uint32_t _uid, uint32_t _gid) { + + protocol::remove_security_policy_command its_command; + its_command.set_client(_client); + its_command.set_update_id(_update_id); + its_command.set_uid(_uid); + its_command.set_gid(_gid); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) + return (its_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size()))); + else + VSOMEIP_ERROR << __func__ + << ": cannot find local client endpoint for client " + << std::hex << std::setw(4) << std::setfill('0') + << _client; + } else + VSOMEIP_ERROR << __func__ + << ": remove security policy command serialization failed (" + << std::dec << static_cast<int>(its_error) + << ")"; - std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); - if (its_endpoint) { - return its_endpoint->send(its_command.data(), uint32_t(its_command.size())); - } else { - VSOMEIP_WARNING << __func__ << " Couldn't send cached security policies " - " to registering client: 0x" - << std::hex << std::setw(4) << std::setfill('0') << _client; - return false; - } -} + return (false); -bool routing_manager_stub::send_remove_security_policy_request( client_t _client, pending_security_update_id_t _update_id, - uint32_t _uid, uint32_t _gid) { - std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); - if (its_endpoint) { - byte_t its_command[VSOMEIP_REMOVE_SECURITY_POLICY_COMMAND_SIZE]; - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_REMOVE_SECURITY_POLICY; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, - sizeof(client_t)); - std::uint32_t its_size = sizeof(_update_id) + sizeof(_uid) + sizeof(_gid); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_update_id, - sizeof(uint32_t)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_uid, - sizeof(uint32_t)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_gid, - sizeof(uint32_t)); - return its_endpoint->send(its_command, sizeof(its_command)); - } else { - return false; - } } bool @@ -2219,7 +2195,7 @@ routing_manager_stub::add_requester_policies(uid_t _uid, gid_t _gid, if (found_gid != found_uid->second.end()) { found_gid->second.insert(_policies.begin(), _policies.end()); } else { - found_uid->second.insert(std::make_pair(_gid, _policies)); + found_uid->second[_gid] = _policies; } } else { requester_policies_[_uid][_gid] = _policies; @@ -2228,7 +2204,7 @@ routing_manager_stub::add_requester_policies(uid_t _uid, gid_t _gid, // Check whether clients with uid/gid are already registered. // If yes, update their policy std::unordered_set<client_t> its_clients; - security::get()->get_clients(_uid, _gid, its_clients); + policy_manager_impl::get()->get_clients(_uid, _gid, its_clients); if (!its_clients.empty()) return send_requester_policies(its_clients, _policies); @@ -2263,7 +2239,7 @@ routing_manager_stub::get_requester_policies(uid_t _uid, gid_t _gid, void routing_manager_stub::add_pending_security_update_handler( - pending_security_update_id_t _id, security_update_handler_t _handler) { + pending_security_update_id_t _id, const security_update_handler_t &_handler) { std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_); security_update_handlers_[_id] = _handler; @@ -2304,7 +2280,13 @@ routing_manager_stub::send_requester_policies(const std::unordered_set<client_t> std::vector<byte_t> its_policy_data; if (p->serialize(its_policy_data)) { std::vector<byte_t> its_message; - its_message.push_back(VSOMEIP_UPDATE_SECURITY_POLICY_INT); + its_message.push_back(byte_t(protocol::id_e::UPDATE_SECURITY_POLICY_INT_ID)); + + // version + its_message.push_back(0); + its_message.push_back(0); + + // client identifier its_message.push_back(0); its_message.push_back(0); @@ -2322,7 +2304,7 @@ routing_manager_stub::send_requester_policies(const std::unordered_set<client_t> its_message.insert(its_message.end(), its_policy_data.begin(), its_policy_data.end()); - for (const auto& c : _clients) { + for (const auto c : _clients) { std::shared_ptr<endpoint> its_endpoint = host_->find_local(c); if (its_endpoint) its_endpoint->send(&its_message[0], static_cast<uint32_t>(its_message.size())); @@ -2401,11 +2383,11 @@ bool routing_manager_stub::update_security_policy_configuration( policy_cache_add(_uid, _payload); // update security policy from configuration - security::get()->update_security_policy(_uid, _gid, _policy); + policy_manager_impl::get()->update_security_policy(_uid, _gid, _policy); // Build requester policies for the services offered by the new policy std::set<std::shared_ptr<policy> > its_requesters; - security::get()->get_requester_policies(_policy, its_requesters); + policy_manager_impl::get()->get_requester_policies(_policy, its_requesters); // and add them to the requester policy cache add_requester_policies(_uid, _gid, its_requesters); @@ -2464,7 +2446,7 @@ bool routing_manager_stub::remove_security_policy_configuration( // remove security policy from configuration (only if there was a updateACL call before) if (is_policy_cached(_uid)) { - if (!security::get()->remove_security_policy(_uid, _gid)) { + if (!policy_manager_impl::get()->remove_security_policy(_uid, _gid)) { _handler(security_update_state_e::SU_UNKNOWN_USER_ID); ret = false; } else { @@ -2611,13 +2593,33 @@ void routing_manager_stub::on_security_update_response( } } } +#endif // !VSOMEIP_DISABLE_SECURITY void routing_manager_stub::send_suspend() const { - static const std::vector<byte_t> its_suspend( - { VSOMEIP_SUSPEND, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); + protocol::suspend_command its_command; + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); - broadcast(its_suspend); + if (its_error == protocol::error_e::ERROR_OK) + broadcast(its_buffer); + else + VSOMEIP_ERROR << __func__ + << ": suspend command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void +routing_manager_stub::remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port) { + + (void)_local_port; + (void)_remote_address; + (void)_remote_port; + // dummy method to implement routing_host interface } } // namespace vsomeip_v3 diff --git a/implementation/routing/src/serviceinfo.cpp b/implementation/routing/src/serviceinfo.cpp index 324fcd7..fcdcbd8 100644 --- a/implementation/routing/src/serviceinfo.cpp +++ b/implementation/routing/src/serviceinfo.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -10,8 +10,7 @@ namespace vsomeip_v3 { serviceinfo::serviceinfo(service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, ttl_t _ttl, bool _is_local) - : group_(0), - service_(_service), + : service_(_service), instance_(_instance), major_(_major), minor_(_minor), @@ -26,7 +25,6 @@ serviceinfo::serviceinfo(service_t _service, instance_t _instance, } serviceinfo::serviceinfo(const serviceinfo& _other) : - group_(_other.group_), service_(_other.service_), instance_(_other.instance_), major_(_other.major_), @@ -42,14 +40,6 @@ serviceinfo::serviceinfo(const serviceinfo& _other) : serviceinfo::~serviceinfo() { } -servicegroup * serviceinfo::get_group() const { - return group_; -} - -void serviceinfo::set_group(servicegroup *_group) { - group_ = _group; -} - service_t serviceinfo::get_service() const { return service_; } |