diff options
Diffstat (limited to 'implementation')
79 files changed, 6456 insertions, 1687 deletions
diff --git a/implementation/configuration/include/configuration.hpp b/implementation/configuration/include/configuration.hpp index c89ed39..9740a79 100644 --- a/implementation/configuration/include/configuration.hpp +++ b/implementation/configuration/include/configuration.hpp @@ -24,6 +24,7 @@ #include "../../e2e_protection/include/e2exf/config.hpp" #include "e2e.hpp" +#include "policy.hpp" #include "debounce.hpp" @@ -38,10 +39,22 @@ public: virtual ~configuration() {} virtual bool load(const std::string &_name) = 0; + virtual bool remote_offer_info_add(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled) = 0; + virtual bool remote_offer_info_remove(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool* _still_offered_remote) = 0; virtual const std::string &get_network() const = 0; virtual const boost::asio::ip::address & get_unicast_address() const = 0; + virtual const boost::asio::ip::address& get_netmask() const = 0; virtual unsigned short get_diagnosis_address() const = 0; virtual std::uint16_t get_diagnosis_mask() const = 0; virtual bool is_v4() const = 0; @@ -84,6 +97,7 @@ public: virtual std::size_t get_max_dispatchers(const std::string &_name) const = 0; virtual std::size_t get_max_dispatch_time(const std::string &_name) const = 0; virtual std::size_t get_io_thread_count(const std::string &_name) const = 0; + virtual int get_io_thread_nice_level(const std::string &_name) const = 0; virtual std::size_t get_request_debouncing(const std::string &_name) const = 0; virtual std::uint32_t get_max_message_size_local() const = 0; @@ -124,7 +138,7 @@ public: virtual uint32_t get_allowed_missing_pongs() const = 0; // File permissions - virtual std::uint32_t get_umask() const = 0; + virtual std::uint32_t get_permissions_uds() const = 0; virtual std::uint32_t get_permissions_shm() const = 0; virtual bool log_version() const = 0; @@ -133,11 +147,19 @@ public: // Security virtual bool is_security_enabled() const = 0; virtual bool is_client_allowed(client_t _client, service_t _service, - instance_t _instance) const = 0; + instance_t _instance, method_t _method, bool _is_request_service = false) const = 0; virtual bool is_offer_allowed(client_t _client, service_t _service, instance_t _instance) const = 0; virtual bool check_credentials(client_t _client, uint32_t _uid, uint32_t _gid) = 0; + virtual bool store_client_to_uid_gid_mapping(client_t _client, uint32_t _uid, uint32_t _gid) = 0; + virtual void store_uid_gid_to_client_mapping(uint32_t _uid, uint32_t _gid, client_t _client) = 0; + + virtual bool get_client_to_uid_gid_mapping(client_t _client, + std::pair<uint32_t, uint32_t> &_uid_gid) = 0; + virtual bool remove_client_to_uid_gid_mapping(client_t _client) = 0; + virtual bool get_uid_gid_to_client_mapping(std::pair<uint32_t, uint32_t> _uid_gid, + std::set<client_t> &_clients) = 0; // Plugins virtual std::map<plugin_type_e, std::set<std::string>> get_plugins( @@ -146,7 +168,7 @@ public: virtual void set_configuration_path(const std::string &_path) = 0; //E2E - virtual std::map<e2exf::data_identifier, std::shared_ptr<cfg::e2e>> get_e2e_configuration() const = 0; + virtual std::map<e2exf::data_identifier_t, std::shared_ptr<cfg::e2e>> get_e2e_configuration() const = 0; virtual bool is_e2e_enabled() const = 0; virtual bool log_memory() const = 0; @@ -170,6 +192,39 @@ public: virtual endpoint_queue_limit_t get_endpoint_queue_limit( const std::string& _address, std::uint16_t _port) const = 0; virtual endpoint_queue_limit_t get_endpoint_queue_limit_local() const = 0; + + virtual std::uint32_t get_max_tcp_restart_aborts() const = 0; + virtual std::uint32_t get_max_tcp_connect_time() const = 0; + + // Offer acceptance + virtual bool offer_acceptance_required( + const boost::asio::ip::address& _address) const = 0; + virtual void set_offer_acceptance_required( + const boost::asio::ip::address& _address, const std::string& _path, + bool _enable) = 0; + virtual std::map<boost::asio::ip::address, std::string> get_offer_acceptance_required() = 0; + + // Security policy + virtual void update_security_policy(uint32_t _uid, uint32_t _gid, ::std::shared_ptr<policy> _policy) = 0; + virtual bool remove_security_policy(uint32_t _uid, uint32_t _gid) = 0; + + virtual void add_security_credentials(uint32_t _uid, uint32_t _gid, + ::std::shared_ptr<policy> _credentials_policy, client_t _client) = 0; + + virtual bool is_remote_client_allowed() const = 0; + + virtual bool is_policy_update_allowed(uint32_t _uid, std::shared_ptr<policy> &_policy) const = 0; + + virtual bool is_policy_removal_allowed(uint32_t _uid) const = 0; + + virtual std::uint32_t get_udp_receive_buffer_size() const = 0; + + virtual bool is_audit_mode_enabled() const = 0; + + virtual bool check_routing_credentials(client_t _client, uint32_t _uid, uint32_t _gid) const = 0; + + // routing shutdown timeout + virtual std::uint32_t get_shutdown_timeout() const = 0; }; } // namespace vsomeip diff --git a/implementation/configuration/include/configuration_impl.hpp b/implementation/configuration/include/configuration_impl.hpp index af04ce1..9bf1188 100644 --- a/implementation/configuration/include/configuration_impl.hpp +++ b/implementation/configuration/include/configuration_impl.hpp @@ -49,16 +49,28 @@ class configuration_impl: public std::enable_shared_from_this<configuration_impl> { public: VSOMEIP_EXPORT configuration_impl(); - VSOMEIP_EXPORT configuration_impl(const configuration_impl &_cfg); + VSOMEIP_EXPORT configuration_impl(const configuration_impl &_other); VSOMEIP_EXPORT virtual ~configuration_impl(); VSOMEIP_EXPORT bool load(const std::string &_name); + VSOMEIP_EXPORT bool remote_offer_info_add(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled); + VSOMEIP_EXPORT bool remote_offer_info_remove(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool* _still_offered_remote); VSOMEIP_EXPORT const std::string &get_network() const; VSOMEIP_EXPORT void set_configuration_path(const std::string &_path); VSOMEIP_EXPORT const boost::asio::ip::address & get_unicast_address() const; + VSOMEIP_EXPORT const boost::asio::ip::address& get_netmask() const; VSOMEIP_EXPORT unsigned short get_diagnosis_address() const; VSOMEIP_EXPORT std::uint16_t get_diagnosis_mask() const; VSOMEIP_EXPORT bool is_v4() const; @@ -91,6 +103,7 @@ public: VSOMEIP_EXPORT std::size_t get_max_dispatchers(const std::string &_name) const; VSOMEIP_EXPORT std::size_t get_max_dispatch_time(const std::string &_name) const; VSOMEIP_EXPORT std::size_t get_io_thread_count(const std::string &_name) const; + VSOMEIP_EXPORT int get_io_thread_nice_level(const std::string &_name) const; VSOMEIP_EXPORT std::size_t get_request_debouncing(const std::string &_name) const; VSOMEIP_EXPORT std::set<std::pair<service_t, instance_t> > get_remote_services() const; @@ -140,22 +153,30 @@ public: VSOMEIP_EXPORT uint32_t get_watchdog_timeout() const; VSOMEIP_EXPORT uint32_t get_allowed_missing_pongs() const; - VSOMEIP_EXPORT std::uint32_t get_umask() const; + VSOMEIP_EXPORT std::uint32_t get_permissions_uds() const; VSOMEIP_EXPORT std::uint32_t get_permissions_shm() const; // Policy VSOMEIP_EXPORT bool is_security_enabled() const; VSOMEIP_EXPORT bool is_client_allowed(client_t _client, service_t _service, - instance_t _instance) const; + instance_t _instance, method_t _method, bool _is_request_service = false) const; VSOMEIP_EXPORT bool is_offer_allowed(client_t _client, service_t _service, instance_t _instance) const; VSOMEIP_EXPORT bool check_credentials(client_t _client, uint32_t _uid, uint32_t _gid); + VSOMEIP_EXPORT bool store_client_to_uid_gid_mapping(client_t _client, uint32_t _uid, uint32_t _gid); + VSOMEIP_EXPORT void store_uid_gid_to_client_mapping(uint32_t _uid, uint32_t _gid, client_t _client); + VSOMEIP_EXPORT bool get_client_to_uid_gid_mapping(client_t _client, + std::pair<uint32_t, uint32_t> &_uid_gid); + VSOMEIP_EXPORT bool remove_client_to_uid_gid_mapping(client_t _client); + VSOMEIP_EXPORT bool get_uid_gid_to_client_mapping(std::pair<uint32_t, uint32_t> _uid_gid, + std::set<client_t> &_clients); + VSOMEIP_EXPORT std::map<plugin_type_e, std::set<std::string>> get_plugins( const std::string &_name) const; // E2E - VSOMEIP_EXPORT std::map<e2exf::data_identifier, std::shared_ptr<cfg::e2e>> get_e2e_configuration() const; + VSOMEIP_EXPORT std::map<e2exf::data_identifier_t, std::shared_ptr<cfg::e2e>> get_e2e_configuration() const; VSOMEIP_EXPORT bool is_e2e_enabled() const; VSOMEIP_EXPORT bool log_memory() const; @@ -173,11 +194,42 @@ public: VSOMEIP_EXPORT endpoint_queue_limit_t get_endpoint_queue_limit( const std::string& _address, std::uint16_t _port) const; VSOMEIP_EXPORT endpoint_queue_limit_t get_endpoint_queue_limit_local() const; + + VSOMEIP_EXPORT std::uint32_t get_max_tcp_restart_aborts() const; + VSOMEIP_EXPORT std::uint32_t get_max_tcp_connect_time() const; + + VSOMEIP_EXPORT bool offer_acceptance_required( + const boost::asio::ip::address& _address) const; + + VSOMEIP_EXPORT void set_offer_acceptance_required( + const boost::asio::ip::address& _address, const std::string& _path, + bool _enable); + VSOMEIP_EXPORT std::map<boost::asio::ip::address, std::string> get_offer_acceptance_required(); + + VSOMEIP_EXPORT void update_security_policy(uint32_t _uid, uint32_t _gid, ::std::shared_ptr<policy> _policy); + VSOMEIP_EXPORT bool remove_security_policy(uint32_t _uid, uint32_t _gid); + + VSOMEIP_EXPORT void add_security_credentials(uint32_t _uid, uint32_t _gid, + ::std::shared_ptr<policy> _credentials_policy, client_t _client); + + VSOMEIP_EXPORT bool is_remote_client_allowed() const; + + VSOMEIP_EXPORT bool is_policy_update_allowed(uint32_t _uid, std::shared_ptr<policy> &_policy) const; + + VSOMEIP_EXPORT bool is_policy_removal_allowed(uint32_t _uid) const; + + VSOMEIP_EXPORT std::uint32_t get_udp_receive_buffer_size() const; + + VSOMEIP_EXPORT bool is_audit_mode_enabled() const; + + VSOMEIP_EXPORT bool check_routing_credentials(client_t _client, uint32_t _uid, uint32_t _gid) const; + + VSOMEIP_EXPORT std::uint32_t get_shutdown_timeout() const; private: void read_data(const std::set<std::string> &_input, std::vector<element> &_elements, std::set<std::string> &_failed, - bool _standard_only); + bool _mandatory_only); bool load_data(const std::vector<element> &_elements, bool _load_mandatory, bool _load_optional); @@ -185,10 +237,11 @@ private: bool load_logging(const element &_element, std::set<std::string> &_warnings); bool load_routing(const element &_element); + bool load_routing_credentials(const element &_element); bool load_applications(const element &_element); void load_application_data(const boost::property_tree::ptree &_tree, - const std::string &_name); + const std::string &_file_name); void load_tracing(const element &_element); void load_trace_channels(const boost::property_tree::ptree &_tree); @@ -198,12 +251,17 @@ private: void load_trace_filter_expressions( const boost::property_tree::ptree &_tree, std::string &_criteria, - std::shared_ptr<trace_filter_rule> &_filter_rule); + std::shared_ptr<trace_filter> &_filter); + void load_trace_filter_match( + const boost::property_tree::ptree &_data, + std::tuple<service_t, instance_t, method_t> &_match); void load_network(const element &_element); void load_unicast_address(const element &_element); + void load_netmask(const element &_element); void load_diagnosis_address(const element &_element); + void load_shutdown_timeout(const element &_element); void load_service_discovery(const element &_element); void load_delays(const boost::property_tree::ptree &_tree); @@ -234,6 +292,11 @@ private: void load_policy(const boost::property_tree::ptree &_tree); void load_credential(const boost::property_tree::ptree &_tree, ids_t &_ids); void load_ranges(const boost::property_tree::ptree &_tree, ranges_t &_range); + void load_instance_ranges(const boost::property_tree::ptree &_tree, ranges_t &_range); + + void load_security_update_whitelist(const element &_element); + void load_service_ranges(const boost::property_tree::ptree &_tree, + std::set<std::pair<service_t, service_t>> &_ranges); void load_debounce(const element &_element); void load_service_debounce(const boost::property_tree::ptree &_tree); @@ -243,11 +306,15 @@ private: std::map<event_t, std::shared_ptr<debounce>> &_debounces); void load_event_debounce_ignore(const boost::property_tree::ptree &_tree, std::map<std::size_t, byte_t> &_ignore); + void load_offer_acceptance_required(const element &_element); + void load_udp_receive_buffer_size(const element &_element); + servicegroup *find_servicegroup(const std::string &_name) const; std::shared_ptr<client> find_client(service_t _service, instance_t _instance) const; std::shared_ptr<service> find_service(service_t _service, instance_t _instance) const; + std::shared_ptr<service> find_service_unlocked(service_t _service, instance_t _instance) const; std::shared_ptr<eventgroup> find_eventgroup(service_t _service, instance_t _instance, eventgroup_t _eventgroup) const; bool find_port(uint16_t &_port, uint16_t _remote, bool _reliable, @@ -271,8 +338,14 @@ private: void load_endpoint_queue_sizes(const element &_element); + void load_tcp_restart_settings(const element &_element); + + std::shared_ptr<policy> find_client_id_policy(client_t _client) const; + private: std::mutex mutex_; + mutable std::mutex ids_mutex_; + mutable std::mutex uid_to_clients_mutex_; bool is_loaded_; bool is_logging_loaded_; @@ -282,6 +355,7 @@ private: protected: // Configuration data boost::asio::ip::address unicast_; + boost::asio::ip::address netmask_; unsigned short diagnosis_; std::uint16_t diagnosis_mask_; @@ -292,9 +366,10 @@ protected: boost::log::trivial::severity_level loglevel_; std::map<std::string, std::tuple<client_t, std::size_t, std::size_t, - size_t, size_t, std::map<plugin_type_e, std::set<std::string>>>> applications_; + size_t, size_t, std::map<plugin_type_e, std::set<std::string>>, int>> applications_; std::set<client_t> client_identifiers_; + mutable std::mutex services_mutex_; std::map<service_t, std::map<instance_t, std::shared_ptr<service> > > services_; @@ -368,24 +443,39 @@ protected: ET_ENDPOINT_QUEUE_LIMITS, ET_ENDPOINT_QUEUE_LIMIT_EXTERNAL, ET_ENDPOINT_QUEUE_LIMIT_LOCAL, - ET_MAX = 31 + ET_TCP_RESTART_ABORTS_MAX, + ET_TCP_CONNECT_TIME_MAX, + ET_OFFER_ACCEPTANCE_REQUIRED, + ET_NETMASK, + ET_UDP_RECEIVE_BUFFER_SIZE, + ET_ROUTING_CREDENTIALS, + ET_SHUTDOWN_TIMEOUT, + ET_MAX = 38 }; bool is_configured_[ET_MAX]; std::uint32_t permissions_shm_; - std::uint32_t umask_; + std::uint32_t permissions_uds_; - std::map<client_t, std::shared_ptr<policy>> policies_; + std::map<std::pair<uint16_t, uint16_t>, std::shared_ptr<policy>> policies_; std::vector<std::shared_ptr<policy> > any_client_policies_; + + mutable std::mutex policies_mutex_; + mutable std::mutex any_client_policies_mutex_; std::map<client_t, std::pair<uint32_t, uint32_t> > ids_; + std::map<std::pair<uint32_t, uint32_t>, std::set<client_t> > uid_to_clients_; + bool policy_enabled_; bool check_credentials_; + bool check_routing_credentials_; + bool allow_remote_clients_; + bool check_whitelist_; std::string network_; std::string configuration_path_; bool e2e_enabled_; - std::map<e2exf::data_identifier, std::shared_ptr<cfg::e2e>> e2e_configuration_; + std::map<e2exf::data_identifier_t, std::shared_ptr<cfg::e2e>> e2e_configuration_; bool log_memory_; uint32_t log_memory_interval_; @@ -401,6 +491,28 @@ protected: std::map<std::string, std::map<std::uint16_t, endpoint_queue_limit_t>> endpoint_queue_limits_; endpoint_queue_limit_t endpoint_queue_limit_external_; endpoint_queue_limit_t endpoint_queue_limit_local_; + + uint32_t tcp_restart_aborts_max_; + uint32_t tcp_connect_time_max_; + + mutable std::mutex offer_acceptance_required_ips_mutex_; + std::map<boost::asio::ip::address, std::string> offer_acceptance_required_ips_; + + bool has_issued_methods_warning_; + bool has_issued_clients_warning_; + + std::uint32_t udp_receive_buffer_size_; + + mutable std::mutex service_interface_whitelist_mutex_; + std::set<std::pair<service_t, service_t>> service_interface_whitelist_; + + mutable std::mutex uid_whitelist_mutex_; + ranges_t uid_whitelist_; + + mutable std::mutex routing_credentials_mutex_; + std::pair<uint32_t, uint32_t> routing_credentials_; + + std::uint32_t shutdown_timeout_; }; } // namespace cfg diff --git a/implementation/configuration/include/e2e.hpp b/implementation/configuration/include/e2e.hpp index 6f7bcda..94eb33d 100644 --- a/implementation/configuration/include/e2e.hpp +++ b/implementation/configuration/include/e2e.hpp @@ -30,8 +30,8 @@ struct e2e { } - e2e(uint16_t _data_id, std::string _variant, std::string _profile, uint16_t _service_id, - uint16_t _event_id,uint16_t _crc_offset, + e2e(uint16_t _data_id, std::string _variant, std::string _profile, service_t _service_id, + event_t _event_id,uint16_t _crc_offset, uint8_t _data_id_mode, uint16_t _data_length, uint16_t _data_id_nibble_offset, uint16_t _counter_offset) : data_id(_data_id), @@ -51,8 +51,8 @@ struct e2e { uint16_t data_id; std::string variant; std::string profile; - uint16_t service_id; - uint16_t event_id; + service_t service_id; + event_t event_id; //profile 1 specific config // [SWS_E2E_00018] diff --git a/implementation/configuration/include/internal.hpp.in b/implementation/configuration/include/internal.hpp.in index 1cb9895..b1a1372 100644 --- a/implementation/configuration/include/internal.hpp.in +++ b/implementation/configuration/include/internal.hpp.in @@ -16,11 +16,10 @@ #define VSOMEIP_ENV_MANDATORY_CONFIGURATION_FILES "VSOMEIP_MANDATORY_CONFIGURATION_FILES" #define VSOMEIP_ENV_LOAD_PLUGINS "VSOMEIP_LOAD_PLUGINS" #define VSOMEIP_ENV_CLIENTSIDELOGGING "VSOMEIP_CLIENTSIDELOGGING" -#define VSOMEIP_ENV_DEBUG_CONFIGURATION "VSOMEIP_DEBUG_CONFIGURATION" #define VSOMEIP_DEFAULT_CONFIGURATION_FILE "/etc/vsomeip.json" #define VSOMEIP_LOCAL_CONFIGURATION_FILE "./vsomeip.json" -#define VSOMEIP_MANDATORY_CONFIGURATION_FILES "vsomeip_std.json,vsomeip_app.json,vsomeip_plc.json,vsomeip_log.json,vsomeip_security.json" +#define VSOMEIP_MANDATORY_CONFIGURATION_FILES "vsomeip_std.json,vsomeip_app.json,vsomeip_plc.json,vsomeip_log.json,vsomeip_security.json,vsomeip_whitelist.json" #define VSOMEIP_DEFAULT_CONFIGURATION_FOLDER "/etc/vsomeip" #define VSOMEIP_DEBUG_CONFIGURATION_FOLDER "/var/opt/public/sin/vsomeip/" @@ -50,15 +49,26 @@ #endif #define VSOMEIP_UNICAST_ADDRESS "@VSOMEIP_UNICAST_ADDRESS@" +#define VSOMEIP_NETMASK "255.255.255.0" #define VSOMEIP_DEFAULT_CONNECT_TIMEOUT 100 #define VSOMEIP_MAX_CONNECT_TIMEOUT 1600 #define VSOMEIP_DEFAULT_FLUSH_TIMEOUT 1000 +#define VSOMEIP_DEFAULT_SHUTDOWN_TIMEOUT 5000 + +#define VSOMEIP_MAX_TCP_CONNECT_TIME 5000 +#define VSOMEIP_MAX_TCP_RESTART_ABORTS 5 + +#define VSOMEIP_DEFAULT_BUFFER_SHRINK_THRESHOLD 5 + #define VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT 5000 #define VSOMEIP_DEFAULT_MAX_MISSING_PONGS 3 +#define VSOMEIP_DEFAULT_UDP_RCV_BUFFER_SIZE 1703936 + #define VSOMEIP_IO_THREAD_COUNT 2 +#define VSOMEIP_IO_THREAD_NICE_LEVEL 255 #define VSOMEIP_MAX_DISPATCHERS 10 #define VSOMEIP_MAX_DISPATCH_TIME 100 @@ -104,6 +114,14 @@ #define VSOMEIP_OFFERED_SERVICES_REQUEST 0x1F #define VSOMEIP_OFFERED_SERVICES_RESPONSE 0x20 #define VSOMEIP_UNSUBSCRIBE_ACK 0x21 +#define VSOMEIP_RESEND_PROVIDED_EVENTS 0x22 + +#define VSOMEIP_UPDATE_SECURITY_POLICY 0x23 +#define VSOMEIP_UPDATE_SECURITY_POLICY_RESPONSE 0x24 +#define VSOMEIP_REMOVE_SECURITY_POLICY 0x25 +#define VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE 0x26 +#define VSOMEIP_UPDATE_SECURITY_CREDENTIALS 0x27 +#define VSOMEIP_DISTRIBUTE_SECURITY_POLICIES 0x28 #define VSOMEIP_SEND_COMMAND_SIZE 14 #define VSOMEIP_SEND_COMMAND_INSTANCE_POS_MIN 7 @@ -129,6 +147,16 @@ #define VSOMEIP_ID_RESPONSE_COMMAND_SIZE 12 #define VSOMEIP_ID_REQUEST_COMMAND_SIZE 13 #define VSOMEIP_OFFERED_SERVICES_COMMAND_SIZE 8 +#define VSOMEIP_RESEND_PROVIDED_EVENTS_COMMAND_SIZE 11 +#define VSOMEIP_REMOVE_SECURITY_POLICY_COMMAND_SIZE 19 +#define VSOMEIP_UPDATE_SECURITY_POLICY_RESPONSE_COMMAND_SIZE 11 +#define VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE_COMMAND_SIZE 11 +#define VSOMEIP_PING_COMMAND_SIZE 7 +#define VSOMEIP_PONG_COMMAND_SIZE 7 +#define VSOMEIP_REGISTER_APPLICATION_COMMAND_SIZE 7 +#define VSOMEIP_DEREGISTER_APPLICATION_COMMAND_SIZE 7 +#define VSOMEIP_REGISTERED_ACK_COMMAND_SIZE 7 + #ifndef _WIN32 #include <pthread.h> @@ -138,7 +166,7 @@ #define VSOMEIP_DIAGNOSIS_ADDRESS @VSOMEIP_DIAGNOSIS_ADDRESS@ #define VSOMEIP_DEFAULT_SHM_PERMISSION 0666 -#define VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS 0000 +#define VSOMEIP_DEFAULT_UDS_PERMISSIONS 0666 #define VSOMEIP_ROUTING_READY_MESSAGE "@VSOMEIP_ROUTING_READY_MESSAGE@" @@ -180,7 +208,7 @@ struct configuration_data_t { unsigned short client_base_; unsigned short max_clients_; int max_used_client_ids_index_; - unsigned short max_assigned_client_id_without_diagnosis_; + unsigned short max_assigned_client_id_; unsigned short routing_manager_host_; // array of used client ids here, pointer to it is kept in utility class }; @@ -189,6 +217,8 @@ const std::uint32_t MESSAGE_SIZE_UNLIMITED = (std::numeric_limits<std::uint32_t> const std::uint32_t QUEUE_SIZE_UNLIMITED = (std::numeric_limits<std::uint32_t>::max)(); +const std::uint32_t MAX_RECONNECTS_UNLIMITED = (std::numeric_limits<std::uint32_t>::max)(); + } // namespace vsomeip diff --git a/implementation/configuration/include/policy.hpp b/implementation/configuration/include/policy.hpp index 9132a4d..c8f649e 100644 --- a/implementation/configuration/include/policy.hpp +++ b/implementation/configuration/include/policy.hpp @@ -12,7 +12,6 @@ #include <vsomeip/primitive_types.hpp> namespace vsomeip { -namespace cfg { typedef std::set<std::pair<uint32_t, uint32_t>> ranges_t; typedef std::set<std::pair<ranges_t, ranges_t>> ids_t; @@ -23,12 +22,11 @@ struct policy { ids_t ids_; bool allow_who_; - std::set<std::pair<service_t, instance_t>> services_; - std::set<std::pair<service_t, instance_t>> offers_; + std::set<std::pair<service_t, ids_t>> services_; + std::set<std::pair<service_t, ranges_t>> offers_; bool allow_what_; }; -} // namespace cfg } // namespace vsomeip #endif // VSOMEIP_CFG_POLICY_HPP diff --git a/implementation/configuration/include/trace.hpp b/implementation/configuration/include/trace.hpp index db92286..3d4e1f4 100644 --- a/implementation/configuration/include/trace.hpp +++ b/implementation/configuration/include/trace.hpp @@ -3,67 +3,51 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -#ifndef CONFIGURATION_INCLUDE_TRACE_HPP_ -#define CONFIGURATION_INCLUDE_TRACE_HPP_ +#ifndef CFG_TRACE_HPP_ +#define CFG_TRACE_HPP_ #include <string> #include <vector> #include <vsomeip/primitive_types.hpp> - -#include "../../tracing/include/defines.hpp" +#include <vsomeip/trace.hpp> namespace vsomeip { namespace cfg { struct trace_channel { - - trace_channel() : - id_(VSOMEIP_TC_DEFAULT_CHANNEL_ID), - name_(VSOMEIP_TC_DEFAULT_CHANNEL_NAME) { - - } - trace_channel_t id_; std::string name_; }; -struct trace_filter_rule { - - trace_filter_rule() : - channel_(VSOMEIP_TC_DEFAULT_CHANNEL_ID), - services_(), - methods_(), - clients_(), - type_(VSOMEIP_TC_DEFAULT_FILTER_TYPE) { - +struct trace_filter { + trace_filter() + : is_positive_(true), + is_range_(false) { } - trace_channel_t channel_; - std::vector<service_t> services_; - std::vector<method_t> methods_; - std::vector<client_t> clients_; - trace_filter_type_t type_; + std::vector<trace_channel_t> channels_; + bool is_positive_; + bool is_range_; + std::vector<vsomeip::trace::match_t> matches_; }; struct trace { - - trace() : - channels_(), - filter_rules_(), - is_enabled_(false), - is_sd_enabled_(false) { - channels_.push_back(std::make_shared<trace_channel>()); + trace() + : is_enabled_(false), + is_sd_enabled_(false), + channels_(), + filters_() { } - std::vector<std::shared_ptr<trace_channel>> channels_; - std::vector<std::shared_ptr<trace_filter_rule>> filter_rules_; - bool is_enabled_; bool is_sd_enabled_; + + std::vector<std::shared_ptr<trace_channel>> channels_; + std::vector<std::shared_ptr<trace_filter>> filters_; }; } // namespace cfg } // namespace vsomeip -#endif /* CONFIGURATION_INCLUDE_TRACE_HPP_ */ +#endif // CFG_TRACE_HPP_ diff --git a/implementation/configuration/src/configuration_impl.cpp b/implementation/configuration/src/configuration_impl.cpp index ccf3883..b574841 100644 --- a/implementation/configuration/src/configuration_impl.cpp +++ b/implementation/configuration/src/configuration_impl.cpp @@ -64,15 +64,18 @@ configuration_impl::configuration_impl() max_configured_message_size_(0), max_local_message_size_(0), max_reliable_message_size_(0), - buffer_shrink_threshold_(0), + buffer_shrink_threshold_(VSOMEIP_DEFAULT_BUFFER_SHRINK_THRESHOLD), trace_(std::make_shared<trace>()), watchdog_(std::make_shared<watchdog>()), log_version_(true), log_version_interval_(10), permissions_shm_(VSOMEIP_DEFAULT_SHM_PERMISSION), - umask_(VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS), + permissions_uds_(VSOMEIP_DEFAULT_UDS_PERMISSIONS), policy_enabled_(false), check_credentials_(false), + check_routing_credentials_(false), + allow_remote_clients_(true), + check_whitelist_(false), network_("vsomeip"), e2e_enabled_(false), log_memory_(false), @@ -80,8 +83,15 @@ configuration_impl::configuration_impl() log_status_(false), log_status_interval_(0), endpoint_queue_limit_external_(QUEUE_SIZE_UNLIMITED), - endpoint_queue_limit_local_(QUEUE_SIZE_UNLIMITED) { + endpoint_queue_limit_local_(QUEUE_SIZE_UNLIMITED), + tcp_restart_aborts_max_(VSOMEIP_MAX_TCP_RESTART_ABORTS), + tcp_connect_time_max_(VSOMEIP_MAX_TCP_CONNECT_TIME), + has_issued_methods_warning_(false), + has_issued_clients_warning_(false), + udp_receive_buffer_size_(VSOMEIP_DEFAULT_UDP_RCV_BUFFER_SIZE), + shutdown_timeout_(VSOMEIP_DEFAULT_SHUTDOWN_TIMEOUT) { unicast_ = unicast_.from_string(VSOMEIP_UNICAST_ADDRESS); + netmask_ = netmask_.from_string(VSOMEIP_NETMASK); for (auto i = 0; i < ET_MAX; i++) is_configured_[i] = false; } @@ -97,14 +107,21 @@ configuration_impl::configuration_impl(const configuration_impl &_other) max_reliable_message_size_(_other.max_reliable_message_size_), buffer_shrink_threshold_(_other.buffer_shrink_threshold_), permissions_shm_(VSOMEIP_DEFAULT_SHM_PERMISSION), - umask_(VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS), + permissions_uds_(VSOMEIP_DEFAULT_UDS_PERMISSIONS), endpoint_queue_limit_external_(_other.endpoint_queue_limit_external_), - endpoint_queue_limit_local_(_other.endpoint_queue_limit_local_) { + endpoint_queue_limit_local_(_other.endpoint_queue_limit_local_), + tcp_restart_aborts_max_(_other.tcp_restart_aborts_max_), + tcp_connect_time_max_(_other.tcp_connect_time_max_), + udp_receive_buffer_size_(_other.udp_receive_buffer_size_), + shutdown_timeout_(_other.shutdown_timeout_) { applications_.insert(_other.applications_.begin(), _other.applications_.end()); + client_identifiers_ = _other.client_identifiers_; services_.insert(_other.services_.begin(), _other.services_.end()); + clients_ = _other.clients_; unicast_ = _other.unicast_; + netmask_ = _other.netmask_; diagnosis_ = _other.diagnosis_; diagnosis_mask_ = _other.diagnosis_mask_; @@ -132,26 +149,48 @@ configuration_impl::configuration_impl(const configuration_impl &_other) sd_offer_debounce_time_ = _other.sd_offer_debounce_time_; trace_ = std::make_shared<trace>(*_other.trace_.get()); + supported_selective_addresses = _other.supported_selective_addresses; watchdog_ = std::make_shared<watchdog>(*_other.watchdog_.get()); + internal_service_ranges_ = _other.internal_service_ranges_; log_version_ = _other.log_version_; log_version_interval_ = _other.log_version_interval_; magic_cookies_.insert(_other.magic_cookies_.begin(), _other.magic_cookies_.end()); + message_sizes_ = _other.message_sizes_; for (auto i = 0; i < ET_MAX; i++) is_configured_[i] = _other.is_configured_[i]; + policies_ = _other.policies_; + any_client_policies_ = _other.any_client_policies_; + ids_ = _other.ids_; policy_enabled_ = _other.policy_enabled_; check_credentials_ = _other.check_credentials_; + check_routing_credentials_ = _other.check_routing_credentials_; + allow_remote_clients_ = _other.allow_remote_clients_; + check_whitelist_ = _other.check_whitelist_; + network_ = _other.network_; + configuration_path_ = _other.configuration_path_; + e2e_enabled_ = _other.e2e_enabled_; + e2e_configuration_ = _other.e2e_configuration_; log_memory_ = _other.log_memory_; log_memory_interval_ = _other.log_memory_interval_; log_status_ = _other.log_status_; log_status_interval_ = _other.log_status_interval_; + ttl_factors_offers_ = _other.ttl_factors_offers_; + ttl_factors_subscriptions_ = _other.ttl_factors_subscriptions_; + debounces_ = _other.debounces_; + endpoint_queue_limits_ = _other.endpoint_queue_limits_; + + offer_acceptance_required_ips_ = _other.offer_acceptance_required_ips_; + + has_issued_methods_warning_ = _other.has_issued_methods_warning_; + has_issued_clients_warning_ = _other.has_issued_clients_warning_; } configuration_impl::~configuration_impl() { @@ -195,14 +234,14 @@ bool configuration_impl::load(const std::string &_name) { } if (its_folder != "") { its_input.insert(its_folder); - } - - // Add debug configuration folder/file on top of already set input - const char* its_debug_env = getenv(VSOMEIP_ENV_DEBUG_CONFIGURATION); - if (nullptr != its_debug_env) { - its_input.insert(its_debug_env); - } else { - its_input.insert(VSOMEIP_DEBUG_CONFIGURATION_FOLDER); +#ifndef _WIN32 + // load security configuration files from UID_GID sub folder if existing + std::stringstream its_security_config_folder; + its_security_config_folder << its_folder << "/" << getuid() << "_" << getgid(); + if (utility::is_folder(its_security_config_folder.str())) { + its_input.insert(its_security_config_folder.str()); + } +#endif } // Determine standard configuration file @@ -271,6 +310,101 @@ bool configuration_impl::load(const std::string &_name) { return is_loaded_; } +bool configuration_impl::remote_offer_info_add(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled) { + bool ret = false; + if (!is_loaded_) { + VSOMEIP_ERROR << __func__ << " shall only be called after normal" + "configuration has been parsed"; + } else { + std::shared_ptr<service> its_service(std::make_shared<service>()); + its_service->service_ = _service; + its_service->instance_ = _instance; + its_service->reliable_ = its_service->unreliable_ = ILLEGAL_PORT; + _reliable ? + its_service->reliable_ = _port : + its_service->unreliable_ = _port; + its_service->unicast_address_ = "local"; + its_service->multicast_address_ = ""; + its_service->multicast_port_ = ILLEGAL_PORT; + its_service->protocol_ = "someip"; + + { + std::lock_guard<std::mutex> its_lock(services_mutex_); + bool updated(false); + auto found_service = services_.find(its_service->service_); + if (found_service != services_.end()) { + auto found_instance = found_service->second.find(its_service->instance_); + if (found_instance != found_service->second.end()) { + VSOMEIP_INFO << "Updating remote configuration for service [" + << std::hex << std::setw(4) << std::setfill('0') + << its_service->service_ << "." << its_service->instance_ << "]"; + if (_reliable) { + found_instance->second->reliable_ = its_service->reliable_; + } else { + found_instance->second->unreliable_ = its_service->unreliable_; + } + updated = true; + } + } + if (!updated) { + services_[_service][_instance] = its_service; + VSOMEIP_INFO << "Added new remote configuration for service [" + << std::hex << std::setw(4) << std::setfill('0') + << its_service->service_ << "." + << std::hex << std::setw(4) << std::setfill('0') + << its_service->instance_ << "]"; + } + if (_magic_cookies_enabled) { + magic_cookies_[its_service->unicast_address_].insert(its_service->reliable_); + } + } + ret = true; + } + return ret; +} + +bool configuration_impl::remote_offer_info_remove(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool* _still_offered_remote) { + (void)_port; + (void)_magic_cookies_enabled; + bool ret = false; + if (!is_loaded_) { + VSOMEIP_ERROR << __func__ << " shall only be called after normal" + "configuration has been parsed"; + } else { + std::lock_guard<std::mutex> its_lock(services_mutex_); + auto found_service = services_.find(_service); + if (found_service != services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + VSOMEIP_INFO << "Removing remote configuration for service [" + << std::hex << std::setw(4) << std::setfill('0') + << _service << "." << _instance << "]"; + if (_reliable) { + found_instance->second->reliable_ = ILLEGAL_PORT; + // TODO delete from magic_cookies_map without overwriting + // configurations from other services offered on the same port + } else { + found_instance->second->unreliable_ = ILLEGAL_PORT; + } + *_still_offered_remote = ( + found_instance->second->unreliable_ != ILLEGAL_PORT || + found_instance->second->reliable_ != ILLEGAL_PORT); + ret = true; + } + } + } + return ret; +} + void configuration_impl::read_data(const std::set<std::string> &_input, std::vector<element> &_elements, std::set<std::string> &_failed, bool _mandatory_only) { @@ -339,17 +473,23 @@ bool configuration_impl::load_data(const std::vector<element> &_elements, has_applications = load_applications(e) || has_applications; load_network(e); load_diagnosis_address(e); + load_shutdown_timeout(e); load_payload_sizes(e); load_endpoint_queue_sizes(e); + load_tcp_restart_settings(e); load_permissions(e); load_policies(e); load_tracing(e); + load_udp_receive_buffer_size(e); + load_security_update_whitelist(e); + load_routing_credentials(e); } } if (_load_optional) { for (auto e : _elements) { load_unicast_address(e); + load_netmask(e); load_service_discovery(e); load_services(e); load_internal_services(e); @@ -358,6 +498,7 @@ bool configuration_impl::load_data(const std::vector<element> &_elements, load_selective_broadcasts_support(e); load_e2e(e); load_debounce(e); + load_offer_acceptance_required(e); } } @@ -476,6 +617,51 @@ bool configuration_impl::load_routing(const element &_element) { return true; } +bool configuration_impl::load_routing_credentials(const element &_element) { + try { + auto its_routing_cred = _element.tree_.get_child("routing-credentials"); + if (is_configured_[ET_ROUTING_CREDENTIALS]) { + VSOMEIP_WARNING << "vSomeIP Security: Multiple definitions of routing-credentials." + << " Ignoring definition from " << _element.name_; + } else { + for (auto i = its_routing_cred.begin(); + i != its_routing_cred.end(); + ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + if (its_key == "uid") { + uint32_t its_uid(0); + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_uid; + std::lock_guard<std::mutex> its_lock(routing_credentials_mutex_); + std::get<0>(routing_credentials_) = its_uid; + } else if (its_key == "gid") { + uint32_t its_gid(0); + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_gid; + std::lock_guard<std::mutex> its_lock(routing_credentials_mutex_); + std::get<1>(routing_credentials_) = its_gid; + } + } + check_routing_credentials_ = true; + is_configured_[ET_ROUTING_CREDENTIALS] = true; + } + } catch (...) { + return false; + } + return true; +} + + bool configuration_impl::load_applications(const element &_element) { try { std::stringstream its_converter; @@ -500,6 +686,7 @@ void configuration_impl::load_application_data( std::size_t its_io_thread_count(VSOMEIP_IO_THREAD_COUNT); std::size_t its_request_debounce_time(VSOMEIP_REQUEST_DEBOUNCE_TIME); std::map<plugin_type_e, std::set<std::string>> plugins; + int its_io_thread_nice_level(VSOMEIP_IO_THREAD_NICE_LEVEL); for (auto i = _tree.begin(); i != _tree.end(); ++i) { std::string its_key(i->first); std::string its_value(i->second.data()); @@ -529,6 +716,9 @@ void configuration_impl::load_application_data( VSOMEIP_WARNING << "Max. number of threads per application is 255"; its_io_thread_count = 255; } + } else if (its_key == "io_thread_nice") { + its_converter << std::dec << its_value; + its_converter >> its_io_thread_nice_level; } else if (its_key == "request_debounce_time") { its_converter << std::dec << its_value; its_converter >> its_request_debounce_time; @@ -552,13 +742,13 @@ void configuration_impl::load_application_data( if (its_inner_key == "application_plugin") { #ifndef _WIN32 library += "."; - library += (VSOMEIP_APPLICATION_PLUGIN_VERSION + '0'); + library += std::to_string(std::uint32_t(VSOMEIP_APPLICATION_PLUGIN_VERSION)); #endif plugins[plugin_type_e::APPLICATION_PLUGIN].insert(library); } else if (its_inner_key == "configuration_plugin") { #ifndef _WIN32 library += "."; - library += (VSOMEIP_PRE_CONFIGURATION_PLUGIN_VERSION + '0'); + library += std::to_string(std::uint32_t(VSOMEIP_PRE_CONFIGURATION_PLUGIN_VERSION)); #endif plugins[plugin_type_e::PRE_CONFIGURATION_PLUGIN].insert(library); } else { @@ -586,7 +776,7 @@ void configuration_impl::load_application_data( applications_[its_name] = std::make_tuple(its_id, its_max_dispatchers, its_max_dispatch_time, its_io_thread_count, - its_request_debounce_time, plugins); + its_request_debounce_time, plugins, its_io_thread_nice_level); } else { VSOMEIP_WARNING << "Multiple configurations for application " << its_name << ". Ignoring a configuration from " @@ -672,56 +862,137 @@ void configuration_impl::load_trace_filters( void configuration_impl::load_trace_filter( const boost::property_tree::ptree &_tree) { - std::shared_ptr<trace_filter_rule> its_filter_rule = std::make_shared<trace_filter_rule>(); - for(auto i = _tree.begin(); i != _tree.end(); ++i) { + std::shared_ptr<trace_filter> its_filter = std::make_shared<trace_filter>(); + bool has_channel(false); + for (auto i = _tree.begin(); i != _tree.end(); ++i) { std::string its_key = i->first; - std::string its_value = i->second.data(); - if(its_key == "channel") { - its_filter_rule->channel_ = its_value; + if (its_key == "channel") { + std::string its_value; + if (i->second.size() == 0) { + its_value = i->second.data(); + its_filter->channels_.push_back(its_value); + } else { + for (auto j = i->second.begin(); j != i->second.end(); ++j) { + its_filter->channels_.push_back(j->second.data()); + } + } + has_channel = true; } else if(its_key == "type") { - its_filter_rule->type_ = its_value; + std::string its_value = i->second.data(); + its_filter->is_positive_ = (its_value == "positive"); } else { - load_trace_filter_expressions(i->second, its_key, its_filter_rule); + load_trace_filter_expressions(i->second, its_key, its_filter); } } - trace_->filter_rules_.push_back(its_filter_rule); + + if (!has_channel) { + its_filter->channels_.push_back("TC"); // default + } + + if (!its_filter->is_range_ || its_filter->matches_.size() == 2) { + trace_->filters_.push_back(its_filter); + } } void configuration_impl::load_trace_filter_expressions( const boost::property_tree::ptree &_tree, std::string &_criteria, - std::shared_ptr<trace_filter_rule> &_filter_rule) { - for(auto i = _tree.begin(); i != _tree.end(); ++i) { - std::string its_value = i->second.data(); - std::stringstream its_converter; - - if(_criteria == "services") { - service_t its_id = NO_TRACE_FILTER_EXPRESSION; - if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { - its_converter << std::hex << its_value; - } else { - its_converter << std::dec << its_value; - } - its_converter >> its_id; - _filter_rule->services_.push_back(its_id); - } else if(_criteria == "methods") { - method_t its_id = NO_TRACE_FILTER_EXPRESSION; - if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { - its_converter << std::hex << its_value; + std::shared_ptr<trace_filter> &_filter) { + if (_criteria == "services") { + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + vsomeip::trace::match_t its_match; + load_trace_filter_match(i->second, its_match); + _filter->matches_.push_back(its_match); + } + } else if (_criteria == "methods") { + if (!has_issued_methods_warning_) { + VSOMEIP_WARNING << "\"method\" entry in filter configuration has no effect!"; + has_issued_methods_warning_ = true; + } + } else if (_criteria == "clients") { + if (!has_issued_clients_warning_) { + VSOMEIP_WARNING << "\"clients\" entry in filter configuration has no effect!"; + has_issued_clients_warning_ = true; + } + } else if (_criteria == "matches") { + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + vsomeip::trace::match_t its_match; + load_trace_filter_match(i->second, its_match); + if (i->first == "from") { + _filter->is_range_ = true; + _filter->matches_.insert(_filter->matches_.begin(), its_match); } else { - its_converter << std::dec << its_value; + if (i->first == "to") _filter->is_range_ = true; + _filter->matches_.push_back(its_match); } - its_converter >> its_id; - _filter_rule->methods_.push_back(its_id); - } else if(_criteria == "clients") { - client_t its_id = NO_TRACE_FILTER_EXPRESSION; - if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { - its_converter << std::hex << its_value; - } else { - its_converter << std::dec << its_value; + } + } +} + +void configuration_impl::load_trace_filter_match( + const boost::property_tree::ptree &_data, + vsomeip::trace::match_t &_match) { + std::stringstream its_converter; + + if (_data.size() == 0) { + std::string its_value(_data.data()); + service_t its_service(ANY_SERVICE); + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_service; + + std::get<0>(_match) = its_service; + std::get<1>(_match) = ANY_INSTANCE; + std::get<2>(_match) = ANY_METHOD; + } else { + std::get<0>(_match) = ANY_SERVICE; + std::get<1>(_match) = ANY_INSTANCE; + std::get<2>(_match) = ANY_METHOD; + + for (auto i = _data.begin(); i != _data.end(); ++i) { + std::string its_value; + + its_converter.str(""); + its_converter.clear(); + + try { + its_value = i->second.data(); + if (its_value == "any") its_value = "0xffff"; + + if (i->first == "service") { + service_t its_service(ANY_SERVICE); + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_service; + std::get<0>(_match) = its_service; + } else if (i->first == "instance") { + instance_t its_instance(ANY_INSTANCE); + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_instance; + std::get<1>(_match) = its_instance; + } else if (i->first == "method") { + method_t its_method(ANY_METHOD); + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_method; + std::get<2>(_match) = its_method; + } + } catch (...) { + // Intentionally left empty } - its_converter >> its_id; - _filter_rule->clients_.push_back(its_id); } } } @@ -741,6 +1012,21 @@ void configuration_impl::load_unicast_address(const element &_element) { } } +void configuration_impl::load_netmask(const element &_element) { + try { + std::string its_value = _element.tree_.get<std::string>("netmask"); + if (is_configured_[ET_NETMASK]) { + VSOMEIP_WARNING << "Multiple definitions for netmask." + "Ignoring definition from " << _element.name_; + } else { + netmask_ = netmask_.from_string(its_value); + is_configured_[ET_NETMASK] = true; + } + } catch (...) { + // intentionally left empty! + } +} + void configuration_impl::load_network(const element &_element) { try { std::string its_value(_element.tree_.get<std::string>("network")); @@ -793,6 +1079,31 @@ void configuration_impl::load_diagnosis_address(const element &_element) { } } +void configuration_impl::load_shutdown_timeout(const element &_element) { + const std::string shutdown_timeout("shutdown_timeout"); + try { + if (_element.tree_.get_child_optional(shutdown_timeout)) { + std::string its_value = _element.tree_.get<std::string>("shutdown_timeout"); + if (is_configured_[ET_SHUTDOWN_TIMEOUT]) { + VSOMEIP_WARNING << "Multiple definitions for shutdown_timeout." + "Ignoring definition from " << _element.name_; + } else { + std::stringstream its_converter; + + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> shutdown_timeout_; + is_configured_[ET_SHUTDOWN_TIMEOUT] = true; + } + } + } catch (...) { + // intentionally left empty + } +} + void configuration_impl::load_service_discovery( const element &_element) { try { @@ -978,6 +1289,7 @@ void configuration_impl::load_delays( } void configuration_impl::load_services(const element &_element) { + std::lock_guard<std::mutex> its_lock(services_mutex_); try { auto its_services = _element.tree_.get_child("services"); for (auto i = its_services.begin(); i != its_services.end(); ++i) @@ -1587,10 +1899,10 @@ void configuration_impl::load_permissions(const element &_element) { std::string its_value(i->second.data()); its_converter << std::oct << its_value; its_converter >> permissions_shm_; - } else if (its_key == "umask") { + } else if (its_key == "permissions-uds") { std::string its_value(i->second.data()); its_converter << std::oct << its_value; - its_converter >> umask_; + its_converter >> permissions_uds_; } } @@ -1636,8 +1948,13 @@ void configuration_impl::load_policies(const element &_element) { } else { check_credentials_ = false; } - } - if (its_security->first == "policies") { + } else if (its_security->first == "allow_remote_clients") { + if (its_security->second.data() == "true") { + allow_remote_clients_ = true; + } else { + allow_remote_clients_ = false; + } + } else if (its_security->first == "policies") { for (auto its_policy = its_security->second.begin(); its_policy != its_security->second.end(); ++its_policy) { load_policy(its_policy->second); @@ -1676,16 +1993,19 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { if (firstClient < lastClient && lastClient != ANY_CLIENT) { uint32_t overrides(0); for (client_t c = firstClient; c <= lastClient; ++c) { - if (policies_.find(c) != policies_.end()) { + if (find_client_id_policy(c)) { overrides++; } - policies_[c] = policy; } if (overrides) { - VSOMEIP_INFO << std::hex << "Security configuration: " - << "Client range 0x" << firstClient - << " - 0x" << lastClient << " overrides policy of " - << std::dec << overrides << " clients"; + VSOMEIP_WARNING << std::hex << "Security configuration: " + << "for client range 0x" << firstClient + << " - 0x" << lastClient + << " will be ignored as it would override an already existing policy of " + << std::dec << overrides << " clients!"; + } else { + std::lock_guard<std::mutex> its_lock(policies_mutex_); + policies_[std::make_pair(firstClient, lastClient)] = policy; } has_been_inserted = true; } else { @@ -1699,47 +2019,63 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { its_converter << std::hex << value; its_converter >> client; if (client != 0x0) { - if (policies_.find(client) != policies_.end()) { - VSOMEIP_INFO << std::hex << "Security configuration: " - << "Overriding policy for client 0x" << client << "."; + if (find_client_id_policy(client)) { + VSOMEIP_WARNING << std::hex << "Security configuration for client " + << client + << " will be ignored as it would overwrite an already existing policy!"; + } else { + std::lock_guard<std::mutex> its_lock(policies_mutex_); + policies_[std::make_pair(client, client)] = policy; } - policies_[client] = policy; has_been_inserted= true; } } } else if (i->first == "credentials") { std::pair<uint32_t, uint32_t> its_uid_range, its_gid_range; + ranges_t its_uid_ranges, its_gid_ranges; + bool has_uid(false), has_gid(false); + bool has_uid_range(false), has_gid_range(false); for (auto n = i->second.begin(); n != i->second.end(); ++n) { std::string its_key(n->first); std::string its_value(n->second.data()); if (its_key == "uid") { - if (its_value != "any") { - uint32_t its_uid; - std::stringstream its_converter; - its_converter << std::dec << its_value; - its_converter >> its_uid; - std::get<0>(its_uid_range) = its_uid; - std::get<1>(its_uid_range) = its_uid; + if(n->second.data().empty()) { + load_ranges(n->second, its_uid_ranges); + has_uid_range = true; } else { - std::get<0>(its_uid_range) = 0; - std::get<1>(its_uid_range) = 0xFFFFFFFF; + if (its_value != "any") { + uint32_t its_uid; + std::stringstream its_converter; + its_converter << std::dec << its_value; + its_converter >> its_uid; + std::get<0>(its_uid_range) = its_uid; + std::get<1>(its_uid_range) = its_uid; + } else { + std::get<0>(its_uid_range) = 0; + std::get<1>(its_uid_range) = 0xFFFFFFFF; + } + has_uid = true; } - has_uid = true; } else if (its_key == "gid") { - if (its_value != "any") { - uint32_t its_gid; - std::stringstream its_converter; - its_converter << std::dec << its_value; - its_converter >> its_gid; - std::get<0>(its_gid_range) = its_gid; - std::get<1>(its_gid_range) = its_gid; + if(n->second.data().empty()) { + load_ranges(n->second, its_gid_ranges); + has_gid_range = true; } else { - std::get<0>(its_gid_range) = 0; - std::get<1>(its_gid_range) = 0xFFFFFFFF; + if (its_value != "any") { + uint32_t its_gid; + std::stringstream its_converter; + its_converter << std::dec << its_value; + its_converter >> its_gid; + std::get<0>(its_gid_range) = its_gid; + std::get<1>(its_gid_range) = its_gid; + } else { + std::get<0>(its_gid_range) = 0; + std::get<1>(its_gid_range) = 0xFFFFFFFF; + } + has_gid = true; } - has_gid = true; } else if (its_key == "allow" || its_key == "deny") { policy->allow_who_ = (its_key == "allow"); load_credential(n->second, policy->ids_); @@ -1755,10 +2091,13 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { policy->allow_who_ = true; policy->ids_.insert(std::make_pair(its_uids, its_gids)); } - + if (has_uid_range && has_gid_range) { + policy->allow_who_ = true; + policy->ids_.insert(std::make_pair(its_uid_ranges, its_gid_ranges)); + } } else if (i->first == "allow") { if (allow_deny_set) { - VSOMEIP_WARNING << "Security configuration: \"allow\" tag overrides " + VSOMEIP_WARNING << "vSomeIP Security: Security configuration: \"allow\" tag overrides " << "already set \"deny\" tag. " << "Either \"deny\" or \"allow\" is allowed."; } @@ -1769,49 +2108,98 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { for (auto n = l->second.begin(); n != l->second.end(); ++n) { service_t service = 0x0; instance_t instance = 0x0; + ids_t its_instance_method_ranges; for (auto k = n->second.begin(); k != n->second.end(); ++k) { std::stringstream its_converter; if (k->first == "service") { std::string value = k->second.data(); its_converter << std::hex << value; its_converter >> service; - } else if (k->first == "instance") { + } else if (k->first == "instance") { // legacy definition for instances + ranges_t its_instance_ranges; + ranges_t its_method_ranges; std::string value = k->second.data(); - its_converter << std::hex << value; - its_converter >> instance; + if (value != "any") { + its_converter << std::hex << value; + its_converter >> instance; + if (instance != 0x0) { + its_instance_ranges.insert(std::make_pair(instance, instance)); + its_method_ranges.insert(std::make_pair(0x01, 0xFFFF)); + } + } else { + its_instance_ranges.insert(std::make_pair(0x01, 0xFFFF)); + its_method_ranges.insert(std::make_pair(0x01, 0xFFFF)); + } + its_instance_method_ranges.insert(std::make_pair(its_instance_ranges, its_method_ranges)); + } else if (k->first == "instances") { // new instances definition + for (auto p = k->second.begin(); p != k->second.end(); ++p) { + ranges_t its_instance_ranges; + ranges_t its_method_ranges; + for (auto m = p->second.begin(); m != p->second.end(); ++m) { + if (m->first == "ids") { + load_instance_ranges(m->second, its_instance_ranges); + } else if (m->first == "methods") { + load_instance_ranges(m->second, its_method_ranges); + } + if (!its_instance_ranges.empty() && !its_method_ranges.empty()) { + its_instance_method_ranges.insert(std::make_pair(its_instance_ranges, its_method_ranges)); + } + } + } + if (its_instance_method_ranges.empty()) { + ranges_t its_legacy_instance_ranges; + ranges_t its_legacy_method_ranges; + its_legacy_method_ranges.insert(std::make_pair(0x01, 0xFFFF)); + // try to only load instance ranges with any method to be allowed + load_instance_ranges(k->second, its_legacy_instance_ranges); + if (!its_legacy_instance_ranges.empty() && !its_legacy_method_ranges.empty()) { + its_instance_method_ranges.insert(std::make_pair(its_legacy_instance_ranges, + its_legacy_method_ranges)); + } + } } } - if (service != 0x0 && instance != 0x0) { + if (service != 0x0 && !its_instance_method_ranges.empty()) { policy->services_.insert( - std::make_pair(service, instance)); + std::make_pair(service, its_instance_method_ranges)); } } } else if (l->first == "offers") { for (auto n = l->second.begin(); n != l->second.end(); ++n) { service_t service = 0x0; instance_t instance = 0x0; + ranges_t its_instance_ranges; for (auto k = n->second.begin(); k != n->second.end(); ++k) { std::stringstream its_converter; if (k->first == "service") { std::string value = k->second.data(); its_converter << std::hex << value; its_converter >> service; - } else if (k->first == "instance") { + } else if (k->first == "instance") { // legacy definition for instances std::string value = k->second.data(); - its_converter << std::hex << value; - its_converter >> instance; + if (value != "any") { + its_converter << std::hex << value; + its_converter >> instance; + if (instance != 0x0) { + its_instance_ranges.insert(std::make_pair(instance, instance)); + } + } else { + its_instance_ranges.insert(std::make_pair(0x01, 0xFFFF)); + } + } else if (k->first == "instances") { // new instances definition + load_instance_ranges(k->second, its_instance_ranges); } } - if (service != 0x0 && instance != 0x0) { + if (service != 0x0 && !its_instance_ranges.empty()) { policy->offers_.insert( - std::make_pair(service, instance)); + std::make_pair(service, its_instance_ranges)); } } } } } else if (i->first == "deny") { if (allow_deny_set) { - VSOMEIP_WARNING << "Security configuration: \"deny\" tag overrides " + VSOMEIP_WARNING << "vSomeIP Security: Security configuration: \"deny\" tag overrides " << "already set \"allow\" tag. " << "Either \"deny\" or \"allow\" is allowed."; } @@ -1822,21 +2210,60 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { for (auto n = l->second.begin(); n != l->second.end(); ++n) { service_t service = 0x0; instance_t instance = 0x0; + ids_t its_instance_method_ranges; for (auto k = n->second.begin(); k != n->second.end(); ++k) { std::stringstream its_converter; if (k->first == "service") { std::string value = k->second.data(); its_converter << std::hex << value; its_converter >> service; - } else if (k->first == "instance") { + } else if (k->first == "instance") { // legacy definition for instances + ranges_t its_instance_ranges; + ranges_t its_method_ranges; std::string value = k->second.data(); - its_converter << std::hex << value; - its_converter >> instance; + if (value != "any") { + its_converter << std::hex << value; + its_converter >> instance; + if (instance != 0x0) { + its_instance_ranges.insert(std::make_pair(instance, instance)); + its_method_ranges.insert(std::make_pair(0x01, 0xFFFF)); + } + } else { + its_instance_ranges.insert(std::make_pair(0x01, 0xFFFF)); + its_method_ranges.insert(std::make_pair(0x01, 0xFFFF)); + } + its_instance_method_ranges.insert(std::make_pair(its_instance_ranges, its_method_ranges)); + } else if (k->first == "instances") { // new instances definition + for (auto p = k->second.begin(); p != k->second.end(); ++p) { + ranges_t its_instance_ranges; + ranges_t its_method_ranges; + for (auto m = p->second.begin(); m != p->second.end(); ++m) { + if (m->first == "ids") { + load_instance_ranges(m->second, its_instance_ranges); + } else if (m->first == "methods") { + load_instance_ranges(m->second, its_method_ranges); + } + if (!its_instance_ranges.empty() && !its_method_ranges.empty()) { + its_instance_method_ranges.insert(std::make_pair(its_instance_ranges, its_method_ranges)); + } + } + } + if (its_instance_method_ranges.empty()) { + ranges_t its_legacy_instance_ranges; + ranges_t its_legacy_method_ranges; + its_legacy_method_ranges.insert(std::make_pair(0x01, 0xFFFF)); + // try to only load instance ranges with any method to be allowed + load_instance_ranges(k->second, its_legacy_instance_ranges); + if (!its_legacy_instance_ranges.empty() && !its_legacy_method_ranges.empty()) { + its_instance_method_ranges.insert(std::make_pair(its_legacy_instance_ranges, + its_legacy_method_ranges)); + } + } } } - if (service != 0x0 && instance != 0x0) { + if (service != 0x0 && !its_instance_method_ranges.empty()) { policy->services_.insert( - std::make_pair(service, instance)); + std::make_pair(service, its_instance_method_ranges)); } } } @@ -1844,21 +2271,31 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { for (auto n = l->second.begin(); n != l->second.end(); ++n) { service_t service = 0x0; instance_t instance = 0x0; + ranges_t its_instance_ranges; for (auto k = n->second.begin(); k != n->second.end(); ++k) { std::stringstream its_converter; if (k->first == "service") { std::string value = k->second.data(); its_converter << std::hex << value; its_converter >> service; - } else if (k->first == "instance") { + } else if (k->first == "instance") { // legacy definition for instances std::string value = k->second.data(); - its_converter << std::hex << value; - its_converter >> instance; + if (value != "any") { + its_converter << std::hex << value; + its_converter >> instance; + if (instance != 0x0) { + its_instance_ranges.insert(std::make_pair(instance, instance)); + } + } else { + its_instance_ranges.insert(std::make_pair(0x01, 0xFFFF)); + } + } else if (k->first == "instances") { // new instances definition + load_instance_ranges(k->second, its_instance_ranges); } } - if (service != 0x0 && instance != 0x0) { + if (service != 0x0 && !its_instance_ranges.empty()) { policy->offers_.insert( - std::make_pair(service, instance)); + std::make_pair(service, its_instance_ranges)); } } } @@ -1867,6 +2304,7 @@ void configuration_impl::load_policy(const boost::property_tree::ptree &_tree) { } if (!has_been_inserted) { + std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_); any_client_policies_.push_back(policy); } } @@ -1882,7 +2320,7 @@ void configuration_impl::load_credential( } else if (its_key == "gid") { load_ranges(j->second, its_gid_ranges); } else { - VSOMEIP_WARNING << "Security configuration: " + VSOMEIP_WARNING << "vSomeIP Security: Security configuration: " << "Malformed credential (contains illegal key \"" << its_key << "\""; } @@ -1892,6 +2330,41 @@ void configuration_impl::load_credential( } } +void configuration_impl::load_security_update_whitelist(const element &_element) { +#ifdef _WIN32 + return; +#endif + try { + auto optional = _element.tree_.get_child_optional("security-update-whitelist"); + if (!optional) { + return; + } + auto found_whitelist = _element.tree_.get_child("security-update-whitelist"); + for (auto its_whitelist = found_whitelist.begin(); + its_whitelist != found_whitelist.end(); ++its_whitelist) { + + if (its_whitelist->first == "uids") { + { + std::lock_guard<std::mutex> its_lock(uid_whitelist_mutex_); + load_ranges(its_whitelist->second, uid_whitelist_); + } + } else if (its_whitelist->first == "services") { + { + std::lock_guard<std::mutex> its_lock(service_interface_whitelist_mutex_); + load_service_ranges(its_whitelist->second, service_interface_whitelist_); + } + } else if (its_whitelist->first == "check-whitelist") { + if (its_whitelist->second.data() == "true") { + check_whitelist_ = true; + } else { + check_whitelist_ = false; + } + } + } + } catch (...) { + } +} + void configuration_impl::load_ranges( const boost::property_tree::ptree &_tree, ranges_t &_range) { ranges_t its_ranges; @@ -1902,7 +2375,6 @@ void configuration_impl::load_ranges( std::stringstream its_converter; its_converter << std::dec << its_data.data(); its_converter >> its_id; - its_ranges.insert(std::make_pair(its_id, its_id)); } else { uint32_t its_first, its_last; @@ -1929,7 +2401,7 @@ void configuration_impl::load_ranges( } has_last = true; } else { - VSOMEIP_WARNING << "Security configuration: " + VSOMEIP_WARNING << "vSomeIP Security: Security configuration: " << " Malformed range. Contains illegal key (" << its_key << ")"; } @@ -1944,6 +2416,128 @@ void configuration_impl::load_ranges( _range = its_ranges; } +void configuration_impl::load_instance_ranges( + const boost::property_tree::ptree &_tree, ranges_t &_range) { + ranges_t its_ranges; + std::string key(_tree.data()); + if (key == "any") { + its_ranges.insert(std::make_pair(0x01, 0xFFFF)); + _range = its_ranges; + return; + } + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + auto its_data = i->second; + if (!its_data.data().empty()) { + uint32_t its_id = 0x0; + std::stringstream its_converter; + its_converter << std::hex << its_data.data(); + its_converter >> its_id; + if (its_id != 0x0) { + its_ranges.insert(std::make_pair(its_id, its_id)); + } + } else { + uint32_t its_first, its_last; + bool has_first(false), has_last(false); + for (auto j = its_data.begin(); j != its_data.end(); ++j) { + std::string its_key(j->first); + std::string its_value(j->second.data()); + if (its_key == "first") { + if (its_value == "max") { + its_first = 0xFFFF; + } else { + std::stringstream its_converter; + its_converter << std::hex << j->second.data(); + its_converter >> its_first; + } + has_first = true; + } else if (its_key == "last") { + if (its_value == "max") { + its_last = 0xFFFF; + } else { + std::stringstream its_converter; + its_converter << std::hex << j->second.data(); + its_converter >> its_last; + } + has_last = true; + } else { + VSOMEIP_WARNING << "vSomeIP Security: Security configuration: " + << " Malformed range. Contains illegal key (" + << its_key << ")"; + } + } + + if (has_first && has_last) { + if( its_last > its_first) { + its_ranges.insert(std::make_pair(its_first, its_last)); + } + } + } + } + + _range = its_ranges; +} + +void configuration_impl::load_service_ranges( + const boost::property_tree::ptree &_tree, std::set<std::pair<service_t, service_t>> &_ranges) { + std::set<std::pair<service_t, service_t>> its_ranges; + std::string key(_tree.data()); + if (key == "any") { + its_ranges.insert(std::make_pair(0x01, 0xFFFF)); + _ranges = its_ranges; + return; + } + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + auto its_data = i->second; + if (!its_data.data().empty()) { + service_t its_id = 0x0; + std::stringstream its_converter; + its_converter << std::hex << its_data.data(); + its_converter >> its_id; + if (its_id != 0x0) { + its_ranges.insert(std::make_pair(its_id, its_id)); + } + } else { + service_t its_first, its_last; + bool has_first(false), has_last(false); + for (auto j = its_data.begin(); j != its_data.end(); ++j) { + std::string its_key(j->first); + std::string its_value(j->second.data()); + if (its_key == "first") { + if (its_value == "max") { + its_first = 0xFFFF; + } else { + std::stringstream its_converter; + its_converter << std::hex << j->second.data(); + its_converter >> its_first; + } + has_first = true; + } else if (its_key == "last") { + if (its_value == "max") { + its_last = 0xFFFF; + } else { + std::stringstream its_converter; + its_converter << std::hex << j->second.data(); + its_converter >> its_last; + } + has_last = true; + } else { + VSOMEIP_WARNING << "vSomeIP Security: Security interface whitelist configuration: " + << " Malformed range. Contains illegal key (" + << its_key << ")"; + } + } + + if (has_first && has_last) { + if( its_last >= its_first) { + its_ranges.insert(std::make_pair(its_first, its_last)); + } + } + } + } + + _ranges = its_ranges; +} + /////////////////////////////////////////////////////////////////////////////// // Internal helper /////////////////////////////////////////////////////////////////////////////// @@ -1994,6 +2588,10 @@ const boost::asio::ip::address & configuration_impl::get_unicast_address() const return unicast_; } +const boost::asio::ip::address& configuration_impl::get_netmask() const { + return netmask_; +} + unsigned short configuration_impl::get_diagnosis_address() const { return diagnosis_; } @@ -2046,8 +2644,9 @@ std::string configuration_impl::get_unicast_address(service_t _service, uint16_t configuration_impl::get_reliable_port(service_t _service, instance_t _instance) const { + std::lock_guard<std::mutex> its_lock(services_mutex_); uint16_t its_reliable(ILLEGAL_PORT); - auto its_service = find_service(_service, _instance); + auto its_service = find_service_unlocked(_service, _instance); if (its_service) its_reliable = its_service->reliable_; @@ -2056,8 +2655,9 @@ uint16_t configuration_impl::get_reliable_port(service_t _service, uint16_t configuration_impl::get_unreliable_port(service_t _service, instance_t _instance) const { + std::lock_guard<std::mutex> its_lock(services_mutex_); uint16_t its_unreliable = ILLEGAL_PORT; - auto its_service = find_service(_service, _instance); + auto its_service = find_service_unlocked(_service, _instance); if (its_service) its_unreliable = its_service->unreliable_; @@ -2174,6 +2774,17 @@ std::size_t configuration_impl::get_io_thread_count(const std::string &_name) co return its_io_thread_count; } +int configuration_impl::get_io_thread_nice_level(const std::string &_name) const { + int its_io_thread_nice_level = VSOMEIP_IO_THREAD_NICE_LEVEL; + + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + its_io_thread_nice_level = std::get<6>(found_application->second); + } + + return its_io_thread_nice_level; +} + std::size_t configuration_impl::get_max_dispatchers( const std::string &_name) const { std::size_t its_max_dispatchers = VSOMEIP_MAX_DISPATCHERS; @@ -2200,6 +2811,7 @@ std::size_t configuration_impl::get_max_dispatch_time( std::set<std::pair<service_t, instance_t> > configuration_impl::get_remote_services() const { + std::lock_guard<std::mutex> its_lock(services_mutex_); std::set<std::pair<service_t, instance_t> > its_remote_services; for (auto i : services_) { for (auto j : i.second) { @@ -2335,8 +2947,9 @@ bool configuration_impl::find_port(uint16_t &_port, uint16_t _remote, bool _reli bool configuration_impl::is_event_reliable(service_t _service, instance_t _instance, event_t _event) const { + std::lock_guard<std::mutex> its_lock(services_mutex_); bool is_reliable(false); - auto its_service = find_service(_service, _instance); + auto its_service = find_service_unlocked(_service, _instance); if (its_service) { auto its_event = its_service->events_.find(_event); if (its_event != its_service->events_.end()) { @@ -2353,6 +2966,12 @@ bool configuration_impl::is_event_reliable(service_t _service, std::shared_ptr<service> configuration_impl::find_service(service_t _service, instance_t _instance) const { + std::lock_guard<std::mutex> its_lock(services_mutex_); + return find_service_unlocked(_service, _instance); +} + +std::shared_ptr<service> configuration_impl::find_service_unlocked(service_t _service, + instance_t _instance) const { std::shared_ptr<service> its_service; auto find_service = services_.find(_service); if (find_service != services_.end()) { @@ -2517,8 +3136,8 @@ uint32_t configuration_impl::get_watchdog_timeout() const { uint32_t configuration_impl::get_allowed_missing_pongs() const { return watchdog_->missing_pongs_allowed_; } -std::uint32_t configuration_impl::get_umask() const { - return umask_; +std::uint32_t configuration_impl::get_permissions_uds() const { + return permissions_uds_; } std::uint32_t configuration_impl::get_permissions_shm() const { @@ -2529,24 +3148,25 @@ bool configuration_impl::is_security_enabled() const { return policy_enabled_; } +bool configuration_impl::is_audit_mode_enabled() const { + return check_credentials_; +} + bool configuration_impl::check_credentials(client_t _client, uint32_t _uid, uint32_t _gid) { if (!policy_enabled_) { return true; } - // store the client -> (uid, gid) mapping - ids_[_client] = std::make_pair(_uid, _gid); - std::vector<std::shared_ptr<policy> > its_policies; bool has_id(false); - auto its_client = policies_.find(_client); - - // Use client specific policy if it does exist - if (its_client != policies_.end()) - its_policies.push_back(its_client->second); - else + auto found_policy = find_client_id_policy(_client); + if (found_policy) { + its_policies.push_back(found_policy); + } else { + std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_); its_policies = any_client_policies_; + } for (const auto &p : its_policies) { for (auto its_credential : p->ids_) { @@ -2571,21 +3191,38 @@ bool configuration_impl::check_credentials(client_t _client, uint32_t _uid, } if ((has_id && p->allow_who_) || (!has_id && !p->allow_who_)) { + if (!store_client_to_uid_gid_mapping(_client,_uid, _gid)) { + std::string security_mode_text = "!"; + if (!check_credentials_) { + security_mode_text = " but will be allowed due to audit mode is active!"; + } + + VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client + << " with UID/GID=" << std::dec << _uid << "/" << _gid + << " : Check credentials failed as existing credentials would be overwritten" + << security_mode_text; + + return !check_credentials_; + } + store_uid_gid_to_client_mapping(_uid, _gid, _client); return true; } } + std::string security_mode_text = " ~> Skip!"; if (!check_credentials_) { - VSOMEIP_INFO << "vSomeIP Security: Check credentials failed for client 0x" - << std::hex << _client << " with UID/GID=" << std::dec << _uid - << "/" << _gid << " but will be allowed due to audit mode is active!"; + security_mode_text = " but will be allowed due to audit mode is active!"; } + VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client + << " with UID/GID=" << std::dec << _uid << "/" << _gid + << " : Check credentials failed" << security_mode_text; + return !check_credentials_; } bool configuration_impl::is_client_allowed(client_t _client, service_t _service, - instance_t _instance) const { + instance_t _instance, method_t _method, bool _is_request_service) const { if (!policy_enabled_) { return true; } @@ -2593,35 +3230,39 @@ bool configuration_impl::is_client_allowed(client_t _client, service_t _service, uint32_t its_uid(0xffffffff), its_gid(0xffffffff); bool must_apply(true); std::vector<std::shared_ptr<policy> > its_policies; - auto its_client = policies_.find(_client); - - // Use client specific policy if it does exist - if (its_client != policies_.end()) - its_policies.push_back(its_client->second); + auto found_policy = find_client_id_policy(_client); + if (found_policy) + its_policies.push_back(found_policy); else { must_apply = false; - its_policies = any_client_policies_; + { + std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_); + its_policies = any_client_policies_; + } + std::lock_guard<std::mutex> its_lock(ids_mutex_); auto found_id = ids_.find(_client); if (found_id != ids_.end()) { its_uid = found_id->second.first; its_gid = found_id->second.second; } else { + std::string security_mode_text = " ~> Skip!"; if (!check_credentials_) { - VSOMEIP_INFO << "vSomeIP Security: Cannot determine uid/gid for" - "client 0x" << std::hex << _client - << ". Therefore it isn't allowed to communicate to service/instance " - << _service << "/" << _instance - << " but will be allowed due to audit mode is active!"; + security_mode_text = " but will be allowed due to audit mode is active!"; } + VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client + << " : Cannot determine uid/gid. Therefore it isn't allowed to communicate to service/instance " + << _service << "/" << _instance + << security_mode_text; + return !check_credentials_; } } for (const auto &p : its_policies) { - bool has_uid(false), has_gid(false); + bool has_uid(false), has_gid(false), has_service(false), has_instance_id(false), has_method_id(false); if (must_apply) { - has_uid = has_gid = p->allow_what_; + has_uid = has_gid = p->allow_who_; } else { for (auto its_credential : p->ids_) { has_uid = has_gid = false; @@ -2643,21 +3284,68 @@ bool configuration_impl::is_client_allowed(client_t _client, service_t _service, } } - auto its_service = p->services_.find(std::make_pair(_service, _instance)); - if (has_uid && has_gid && p->allow_what_ && its_service != p->services_.end()) { - return true; - } else if (!has_uid && !has_gid && !p->allow_what_ && its_service == p->services_.end()) { - return true; + for (auto its_offer : p->services_) { + if (std::get<0>(its_offer) == _service) { + for (auto its_ids : std::get<1>(its_offer)) { + has_service = has_instance_id = has_method_id = false; + for (auto its_instance_range : std::get<0>(its_ids)) { + if (std::get<0>(its_instance_range) <= _instance && _instance <= std::get<1>(its_instance_range)) { + has_instance_id = true; + break; + } + } + if (!_is_request_service) { + for (auto its_method_range : std::get<1>(its_ids)) { + if (std::get<0>(its_method_range) <= _method && _method <= std::get<1>(its_method_range)) { + has_method_id = true; + break; + } + } + } else { + // handle VSOMEIP_REQUEST_SERVICE + has_method_id = true; + } + + if (has_instance_id && has_method_id) { + has_service = true; + break; + } + } + if (has_service) + break; + } + } + + if ((has_uid && has_gid && p->allow_who_) || ((!has_uid || !has_gid) && !p->allow_who_)) { + if (p->allow_what_) { + // allow policy + if (has_service) { + return true; + } + } else { + // deny policy + // allow client if the service / instance / !ANY_METHOD was not found + if ((!has_service && (_method != ANY_METHOD)) + // allow client if the service / instance / ANY_METHOD was not found + // and it is a "deny nothing" policy + || (!has_service && (_method == ANY_METHOD) && p->services_.empty())) { + return true; + } + } } } + std::string security_mode_text = " ~> Skip!"; if (!check_credentials_) { - VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client - << " isn't allowed to communicate with service/instance " - << _service << "/" << _instance - << " but will be allowed due to audit mode is active!"; + security_mode_text = " but will be allowed due to audit mode is active!"; } + VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client + << " with UID/GID=" << std::dec << its_uid << "/" << its_gid + << " : Isn't allowed to communicate with service/instance/(method / event) " << std::hex + << _service << "/" << _instance << "/" << _method + << security_mode_text; + return !check_credentials_; } @@ -2670,35 +3358,39 @@ bool configuration_impl::is_offer_allowed(client_t _client, service_t _service, uint32_t its_uid(0xffffffff), its_gid(0xffffffff); bool must_apply(true); std::vector<std::shared_ptr<policy> > its_policies; - auto its_client = policies_.find(_client); - - // Use client specific policy if it does exist - if (its_client != policies_.end()) - its_policies.push_back(its_client->second); + auto found_policy = find_client_id_policy(_client); + if (found_policy) + its_policies.push_back(found_policy); else { must_apply = false; - its_policies = any_client_policies_; + { + std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_); + its_policies = any_client_policies_; + } + std::lock_guard<std::mutex> its_lock(ids_mutex_); auto found_id = ids_.find(_client); if (found_id != ids_.end()) { its_uid = found_id->second.first; its_gid = found_id->second.second; } else { + std::string audit_mode_text = " ~> Skip offer!"; if (!check_credentials_) { - VSOMEIP_INFO << "vSomeIP Security: Cannot determine uid/gid for" - "client 0x" << std::hex << _client - << ". Therefore it isn't allowed to offer service/instance " - << _service << "/" << _instance - << " but will be allowed due to audit mode is active!"; + audit_mode_text = " but will be allowed due to audit mode is active!"; } + + VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client + << " : Cannot determine uid/gid. Therefore it isn't allowed to offer service/instance " + << _service << "/" << _instance << audit_mode_text; + return !check_credentials_; } } for (const auto &p : its_policies) { - bool has_uid(false), has_gid(false); + bool has_uid(false), has_gid(false), has_offer(false); if (must_apply) { - has_uid = has_gid = p->allow_what_; + has_uid = has_gid = p->allow_who_; } else { for (auto its_credential : p->ids_) { has_uid = has_gid = false; @@ -2720,26 +3412,152 @@ bool configuration_impl::is_offer_allowed(client_t _client, service_t _service, } } - auto its_offer = p->offers_.find(std::make_pair(_service, _instance)); - if (has_uid && has_gid - && p->allow_what_ && its_offer != p->offers_.end()) { - return true; - } else if (!has_uid && !has_gid - && !p->allow_what_ && its_offer == p->offers_.end()) { - return true; + for (auto its_offer : p->offers_) { + has_offer = false; + if (std::get<0>(its_offer) == _service) { + for (auto its_instance_range : std::get<1>(its_offer)) { + if (std::get<0>(its_instance_range) <= _instance && _instance <= std::get<1>(its_instance_range)) { + has_offer = true; + break; + } + } + if (has_offer) + break; + } + } + + if ((has_uid && has_gid && p->allow_who_) || ((!has_uid || !has_gid) && !p->allow_who_)) { + if (p->allow_what_ == has_offer) { + return true; + } } } + std::string security_mode_text = " ~> Skip offer!"; if (!check_credentials_) { - VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client - << " isn't allowed to offer service/instance " - << _service << "/" << _instance - << " but will be allowed due to audit mode is active!"; + security_mode_text = " but will be allowed due to audit mode is active!"; } + VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client + << " with UID/GID=" << std::dec << its_uid << "/" << its_gid + << " isn't allowed to offer service/instance " << std::hex + << _service << "/" << _instance + << security_mode_text; + + return !check_credentials_; } +bool configuration_impl::store_client_to_uid_gid_mapping(client_t _client, + uint32_t _uid, uint32_t _gid) { + { + // store the client -> (uid, gid) mapping + std::lock_guard<std::mutex> its_lock(ids_mutex_); + auto found_client = ids_.find(_client); + if (found_client != ids_.end()) { + if (found_client->second != std::make_pair(_uid, _gid)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << _client << " with UID/GID=" + << std::dec << _uid << "/" << _gid << " : Overwriting existing credentials UID/GID=" + << std::dec << std::get<0>(found_client->second) << "/" + << std::get<1>(found_client->second); + found_client->second = std::make_pair(_uid, _gid); + return true; + } + } else { + ids_[_client] = std::make_pair(_uid, _gid); + } + return true; + } +} + +bool configuration_impl::get_client_to_uid_gid_mapping(client_t _client, std::pair<uint32_t, uint32_t> &_uid_gid) { + { + // get the UID / GID of the client + std::lock_guard<std::mutex> its_lock(ids_mutex_); + if (ids_.find(_client) != ids_.end()) { + _uid_gid = ids_[_client]; + return true; + } + return false; + } +} + +bool configuration_impl::remove_client_to_uid_gid_mapping(client_t _client) { + std::pair<uint32_t, uint32_t> its_uid_gid; + bool client_removed(false); + bool uid_gid_removed(false); + { + std::lock_guard<std::mutex> its_lock(ids_mutex_); + auto found_client = ids_.find(_client); + if (found_client != ids_.end()) { + its_uid_gid = found_client->second; + ids_.erase(found_client); + client_removed = true; + } + } + { + std::lock_guard<std::mutex> its_lock(uid_to_clients_mutex_); + if (client_removed) { + auto found_uid_gid = uid_to_clients_.find(its_uid_gid); + if (found_uid_gid != uid_to_clients_.end()) { + auto its_client = found_uid_gid->second.find(_client); + if (its_client != found_uid_gid->second.end()) { + found_uid_gid->second.erase(its_client); + if (found_uid_gid->second.empty()) { + uid_to_clients_.erase(found_uid_gid); + } + uid_gid_removed = true; + } + } + } else { + for (auto its_uid_gid = uid_to_clients_.begin(); + its_uid_gid != uid_to_clients_.end(); ++its_uid_gid) { + auto its_client = its_uid_gid->second.find(_client); + if (its_client != its_uid_gid->second.end()) { + its_uid_gid->second.erase(its_client); + if (its_uid_gid->second.empty()) { + uid_to_clients_.erase(its_uid_gid); + } + uid_gid_removed = true; + break; + } + } + } + } + return (client_removed && uid_gid_removed); +} + +void configuration_impl::store_uid_gid_to_client_mapping(uint32_t _uid, uint32_t _gid, + client_t _client) { + { + // store the uid gid to clients mapping + std::lock_guard<std::mutex> its_lock(uid_to_clients_mutex_); + std::set<client_t> mapped_clients; + if (uid_to_clients_.find(std::make_pair(_uid, _gid)) != uid_to_clients_.end()) { + mapped_clients = uid_to_clients_[std::make_pair(_uid, _gid)]; + mapped_clients.insert(_client); + uid_to_clients_[std::make_pair(_uid, _gid)] = mapped_clients; + } else { + mapped_clients.insert(_client); + uid_to_clients_[std::make_pair(_uid, _gid)] = mapped_clients; + } + } +} + +bool configuration_impl::get_uid_gid_to_client_mapping(std::pair<uint32_t, uint32_t> _uid_gid, + std::set<client_t> &_clients) { + { + // get the clients corresponding to uid, gid + std::lock_guard<std::mutex> its_lock(uid_to_clients_mutex_); + if (uid_to_clients_.find(_uid_gid) != uid_to_clients_.end()) { + _clients = uid_to_clients_[_uid_gid]; + return true; + } + return false; + } +} + std::map<plugin_type_e, std::set<std::string>> configuration_impl::get_plugins( const std::string &_name) const { std::map<plugin_type_e, std::set<std::string>> result; @@ -2793,8 +3611,8 @@ void configuration_impl::load_e2e_protected(const boost::property_tree::ptree &_ uint16_t data_id(0); std::string variant(""); std::string profile(""); - uint16_t service_id(0); - uint16_t event_id(0); + service_t service_id(0); + event_t event_id(0); uint16_t crc_offset(0); uint8_t data_id_mode(0); @@ -2861,8 +3679,7 @@ void configuration_impl::load_e2e_protected(const boost::property_tree::ptree &_ its_converter >> data_length; } } - e2exf::data_identifier its_data_identifier = {service_id, event_id}; - e2e_configuration_[its_data_identifier] = std::make_shared<cfg::e2e>( + e2e_configuration_[std::make_pair(service_id, event_id)] = std::make_shared<cfg::e2e>( data_id, variant, profile, @@ -2876,7 +3693,7 @@ void configuration_impl::load_e2e_protected(const boost::property_tree::ptree &_ ); } -std::map<e2exf::data_identifier, std::shared_ptr<cfg::e2e>> configuration_impl::get_e2e_configuration() const { +std::map<e2exf::data_identifier_t, std::shared_ptr<cfg::e2e>> configuration_impl::get_e2e_configuration() const { return e2e_configuration_; } @@ -3217,6 +4034,55 @@ void configuration_impl::load_event_debounce_ignore( } } +void configuration_impl::load_offer_acceptance_required( + const element &_element) { + const std::string oar("offer_acceptance_required"); + try { + std::lock_guard<std::mutex> its_lock(offer_acceptance_required_ips_mutex_); + if (_element.tree_.get_child_optional(oar)) { + if (is_configured_[ET_OFFER_ACCEPTANCE_REQUIRED]) { + VSOMEIP_WARNING << "Multiple definitions of " << oar + << " Ignoring definition from " << _element.name_; + } else { + for (const auto& ipe : _element.tree_.get_child(oar)) { + boost::system::error_code ec; + boost::asio::ip::address its_address = + boost::asio::ip::address::from_string(ipe.first.data(), ec); + if (!its_address.is_unspecified()) { + offer_acceptance_required_ips_[its_address] = ipe.second.data(); + } + } + is_configured_[ET_OFFER_ACCEPTANCE_REQUIRED] = true; + } + } + } catch (...) { + // intentionally left empty + } +} + +void configuration_impl::load_udp_receive_buffer_size(const element &_element) { + const std::string urbs("udp-receive-buffer-size"); + try { + if (_element.tree_.get_child_optional(urbs)) { + if (is_configured_[ET_UDP_RECEIVE_BUFFER_SIZE]) { + VSOMEIP_WARNING << "Multiple definitions of " << urbs + << " Ignoring definition from " << _element.name_; + } else { + const std::string s(_element.tree_.get_child(urbs).data()); + try { + udp_receive_buffer_size_ = static_cast<std::uint32_t>(std::stoul( + s.c_str(), NULL, 10)); + } catch (const std::exception &e) { + VSOMEIP_ERROR<< __func__ << ": " << urbs << " " << e.what(); + } + is_configured_[ET_UDP_RECEIVE_BUFFER_SIZE] = true; + } + } + } catch (...) { + // intentionally left empty + } +} + std::shared_ptr<debounce> configuration_impl::get_debounce( service_t _service, instance_t _instance, event_t _event) const { auto found_service = debounces_.find(_service); @@ -3232,5 +4098,296 @@ std::shared_ptr<debounce> configuration_impl::get_debounce( return nullptr; } +void configuration_impl::load_tcp_restart_settings(const element &_element) { + const std::string tcp_restart_aborts_max("tcp-restart-aborts-max"); + const std::string tcp_connect_time_max("tcp-connect-time-max"); + + try { + if (_element.tree_.get_child_optional(tcp_restart_aborts_max)) { + if (is_configured_[ET_TCP_RESTART_ABORTS_MAX]) { + VSOMEIP_WARNING << "Multiple definitions for " + << tcp_restart_aborts_max + << " Ignoring definition from " << _element.name_; + } else { + is_configured_[ET_TCP_RESTART_ABORTS_MAX] = true; + auto mpsl = _element.tree_.get_child( + tcp_restart_aborts_max); + std::string s(mpsl.data()); + try { + tcp_restart_aborts_max_ = + static_cast<std::uint32_t>(std::stoul( + s.c_str(), NULL, 10)); + } catch (const std::exception &e) { + VSOMEIP_ERROR<<__func__ << ": " << tcp_restart_aborts_max + << " " << e.what(); + } + } + } + if (_element.tree_.get_child_optional(tcp_connect_time_max)) { + if (is_configured_[ET_TCP_CONNECT_TIME_MAX]) { + VSOMEIP_WARNING << "Multiple definitions for " + << tcp_connect_time_max + << " Ignoring definition from " << _element.name_; + } else { + is_configured_[ET_TCP_CONNECT_TIME_MAX] = true; + auto mpsl = _element.tree_.get_child(tcp_connect_time_max); + std::string s(mpsl.data()); + try { + tcp_connect_time_max_= + static_cast<std::uint32_t>( + std::stoul(s.c_str(), NULL, 10)); + } catch (const std::exception &e) { + VSOMEIP_ERROR<< __func__ << ": "<< tcp_connect_time_max + << " " << e.what(); + } + } + } + } catch (...) { + } +} + +std::uint32_t configuration_impl::get_max_tcp_restart_aborts() const { + return tcp_restart_aborts_max_; +} + +std::uint32_t configuration_impl::get_max_tcp_connect_time() const { + return tcp_connect_time_max_; +} + +bool configuration_impl::offer_acceptance_required( + const boost::asio::ip::address& _address) const { + std::lock_guard<std::mutex> its_lock(offer_acceptance_required_ips_mutex_); + return offer_acceptance_required_ips_.find(_address) + != offer_acceptance_required_ips_.end(); +} + +void configuration_impl::set_offer_acceptance_required( + const boost::asio::ip::address& _address, const std::string& _path, + bool _enable) { + std::lock_guard<std::mutex> its_lock(offer_acceptance_required_ips_mutex_); + if (_enable) { + const auto found_address = offer_acceptance_required_ips_.find(_address); + if (found_address != offer_acceptance_required_ips_.end()) { + boost::system::error_code ec; + VSOMEIP_WARNING << __func__ << " configuration for: " + << found_address->first.to_string(ec) << " -> " + << found_address->second << " already configured." + << " Won't update with: "<< _path; + } else { + offer_acceptance_required_ips_[_address] = _path; + } + } else { + offer_acceptance_required_ips_.erase(_address); + } +} + +std::map<boost::asio::ip::address, std::string> +configuration_impl::get_offer_acceptance_required() { + std::lock_guard<std::mutex> its_lock(offer_acceptance_required_ips_mutex_); + return offer_acceptance_required_ips_; +} + +std::uint32_t configuration_impl::get_udp_receive_buffer_size() const { + return udp_receive_buffer_size_; +} + +std::shared_ptr<policy> configuration_impl::find_client_id_policy(client_t _client) const { + std::lock_guard<std::mutex> its_lock(policies_mutex_); + for (auto client_id_pair : policies_) { + if (std::get<0>(client_id_pair.first) <= _client + && _client <= std::get<1>(client_id_pair.first)) { + return client_id_pair.second; + } + } + return nullptr; +} + +bool configuration_impl::remove_security_policy(uint32_t _uid, uint32_t _gid) { + std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_); + bool was_removed(false); + if (!any_client_policies_.empty()) { + std::vector<std::shared_ptr<policy>>::iterator p_it = any_client_policies_.begin(); + while (p_it != any_client_policies_.end()) { + bool has_uid(false), has_gid(false); + for (auto its_credential : p_it->get()->ids_) { + has_uid = has_gid = false; + for (auto its_range : std::get<0>(its_credential)) { + if (std::get<0>(its_range) <= _uid && _uid <= std::get<1>(its_range)) { + has_uid = true; + break; + } + } + for (auto its_range : std::get<1>(its_credential)) { + if (std::get<0>(its_range) <= _gid && _gid <= std::get<1>(its_range)) { + has_gid = true; + break; + } + } + // only remove "credentials allow" policies to prevent removal of + // blacklist configured in file + if (has_uid && has_gid && p_it->get()->allow_who_) { + was_removed = true; + break; + } + } + if (was_removed) { + p_it = any_client_policies_.erase(p_it); + break; + } else { + ++p_it; + } + } + } + return was_removed; +} + +void configuration_impl::update_security_policy(uint32_t _uid, uint32_t _gid, ::std::shared_ptr<policy> _policy) { + remove_security_policy(_uid, _gid); + std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_); + any_client_policies_.push_back(_policy); +} + +void configuration_impl::add_security_credentials(uint32_t _uid, uint32_t _gid, + ::std::shared_ptr<policy> _credentials_policy, client_t _client) { + + bool was_found(false); + std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_); + for (auto its_policy : any_client_policies_) { + bool has_uid(false), has_gid(false); + for (auto its_credential : its_policy->ids_) { + has_uid = has_gid = false; + for (auto its_range : std::get<0>(its_credential)) { + if (std::get<0>(its_range) <= _uid && _uid <= std::get<1>(its_range)) { + has_uid = true; + break; + } + } + for (auto its_range : std::get<1>(its_credential)) { + if (std::get<0>(its_range) <= _gid && _gid <= std::get<1>(its_range)) { + has_gid = true; + break; + } + } + if (has_uid && has_gid && its_policy->allow_who_) { + was_found = true; + break; + } + } + if (was_found) { + break; + } + } + // Do not add the new (credentials-only-policy) if a allow credentials policy with same credentials was found + if (!was_found) { + any_client_policies_.push_back(_credentials_policy); + VSOMEIP_INFO << __func__ << " Added security credentials at client: 0x" + << std::hex << _client << std::dec << " with UID: " << _uid << " GID: " << _gid; + } +} + +bool configuration_impl::is_remote_client_allowed() const { + if (!check_credentials_) { + return true; + } + return allow_remote_clients_; +} + +bool configuration_impl::is_policy_update_allowed(uint32_t _uid, std::shared_ptr<policy> &_policy) const { + bool uid_allowed(false); + { + std::lock_guard<std::mutex> its_lock(uid_whitelist_mutex_); + for (auto its_uid_range : uid_whitelist_) { + if (std::get<0>(its_uid_range) <= _uid && _uid <= std::get<1>(its_uid_range)) { + uid_allowed = true; + break; + } + } + } + + if (uid_allowed) { + std::lock_guard<std::mutex> its_lock(service_interface_whitelist_mutex_); + for (auto its_request : _policy->services_) { + auto its_requested_service = std::get<0>(its_request); + bool has_service(false); + for (auto its_service_range : service_interface_whitelist_) { + if (std::get<0>(its_service_range) <= its_requested_service + && its_requested_service <= std::get<1>(its_service_range)) { + has_service = true; + break; + } + } + if (!has_service) { + if (!check_whitelist_) { + VSOMEIP_INFO << "vSomeIP Security: Policy update requesting service ID: " + << std::hex << its_requested_service + << " is not allowed, but will be allowed due to whitelist audit mode is active!"; + } else { + VSOMEIP_WARNING << "vSomeIP Security: Policy update requesting service ID: " + << std::hex << its_requested_service + << " is not allowed! -> ignore update"; + } + return !check_whitelist_; + } + } + return true; + } else { + if (!check_whitelist_) { + VSOMEIP_INFO << "vSomeIP Security: Policy update for UID: " << std::dec << _uid + << " is not allowed, but will be allowed due to whitelist audit mode is active!"; + } else { + VSOMEIP_WARNING << "vSomeIP Security: Policy update for UID: " << std::dec << _uid + << " is not allowed! -> ignore update"; + } + return !check_whitelist_; + } +} + +bool configuration_impl::is_policy_removal_allowed(uint32_t _uid) const { + std::lock_guard<std::mutex> its_lock(uid_whitelist_mutex_); + for (auto its_uid_range : uid_whitelist_) { + if (std::get<0>(its_uid_range) <= _uid && _uid <= std::get<1>(its_uid_range)) { + return true; + } + } + + if (!check_whitelist_) { + VSOMEIP_INFO << "vSomeIP Security: Policy removal for UID: " << std::dec << _uid + << " is not allowed, but will be allowed due to whitelist audit mode is active!"; + } else { + VSOMEIP_WARNING << "vSomeIP Security: Policy removal for UID: " << std::dec << _uid + << " is not allowed! -> ignore removal"; + } + return !check_whitelist_; +} + +bool configuration_impl::check_routing_credentials(client_t _client, uint32_t _uid, uint32_t _gid) const { + if (_client != get_id(routing_host_)) { + return true; + } else { + std::lock_guard<std::mutex> its_lock(routing_credentials_mutex_); + if ( std::get<0>(routing_credentials_) == _uid + && std::get<1>(routing_credentials_) == _gid) { + return true; + } + } + + std::string security_mode_text = "!"; + if (!check_routing_credentials_) { + security_mode_text = " but will be allowed due to audit mode is active!"; + } + VSOMEIP_INFO << "vSomeIP Security: Client 0x" + << std::hex << _client << " and UID/GID=" << std::dec << _uid + << "/" << _gid << " : Check routing credentials failed as " + << "configured routing manager credentials " + << "do not match with routing manager credentials" + << security_mode_text; + + return !check_routing_credentials_; +} + +std::uint32_t configuration_impl::get_shutdown_timeout() const { + return shutdown_timeout_; +} + } // namespace config } // namespace vsomeip diff --git a/implementation/e2e_protection/include/e2exf/config.hpp b/implementation/e2e_protection/include/e2exf/config.hpp index 3667211..bf1fb50 100644 --- a/implementation/e2e_protection/include/e2exf/config.hpp +++ b/implementation/e2e_protection/include/e2exf/config.hpp @@ -6,6 +6,7 @@ #ifndef VSOMEIP_E2EXF_CONFIG_HPP #define VSOMEIP_E2EXF_CONFIG_HPP +#include <vsomeip/primitive_types.hpp> #include "../e2e/profile/profile_interface/checker.hpp" #include "../e2e/profile/profile_interface/protector.hpp" @@ -15,12 +16,9 @@ namespace vsomeip { namespace e2exf { -using session_id = uint16_t; -using instance_id = uint16_t; +using data_identifier_t = std::pair<service_t, event_t>; -using data_identifier = std::pair<session_id, instance_id>; - -std::ostream &operator<<(std::ostream &_os, const e2exf::data_identifier &_data_identifier); +std::ostream &operator<<(std::ostream &_os, const e2exf::data_identifier_t &_data_identifier); } // namespace e2exf } // namespace vsomeip diff --git a/implementation/e2e_protection/src/e2exf/config.cpp b/implementation/e2e_protection/src/e2exf/config.cpp index e210faf..c7df18a 100644 --- a/implementation/e2e_protection/src/e2exf/config.cpp +++ b/implementation/e2e_protection/src/e2exf/config.cpp @@ -8,7 +8,7 @@ namespace vsomeip { -std::ostream &operator<<(std::ostream &_os, const e2exf::data_identifier &_data_identifier) { +std::ostream &operator<<(std::ostream &_os, const e2exf::data_identifier_t &_data_identifier) { _os << _data_identifier.first << _data_identifier.second; return _os; } diff --git a/implementation/endpoints/include/client_endpoint_impl.hpp b/implementation/endpoints/include/client_endpoint_impl.hpp index 97819bc..409bba0 100644 --- a/implementation/endpoints/include/client_endpoint_impl.hpp +++ b/implementation/endpoints/include/client_endpoint_impl.hpp @@ -14,6 +14,7 @@ #include <boost/array.hpp>
#include <boost/asio/io_service.hpp>
+#include <boost/asio/strand.hpp> #include <boost/asio/ip/udp.hpp>
#include <boost/utility.hpp>
#include <vsomeip/constants.hpp>
@@ -53,7 +54,8 @@ public: bool is_client() const;
- bool is_connected() const;
+ bool is_established() const;
+ void set_established(bool _established);
void set_connected(bool _connected);
virtual bool get_remote_address(boost::asio::ip::address &_address) const;
virtual std::uint16_t get_remote_port() const;
@@ -76,6 +78,7 @@ protected: enum class cei_state_e : std::uint8_t {
CLOSED,
CONNECTING,
+ CONNECTED,
ESTABLISHED
};
virtual void send_queued() = 0;
@@ -98,6 +101,7 @@ protected: boost::asio::steady_timer connect_timer_;
std::atomic<uint32_t> connect_timeout_;
std::atomic<cei_state_e> state_;
+ std::atomic<std::uint32_t> reconnect_counter_;
// send data
message_buffer_ptr_t packetizer_;
@@ -110,9 +114,13 @@ protected: std::atomic<std::uint16_t> local_port_;
+ boost::asio::io_service::strand strand_; + private:
virtual void set_local_port() = 0;
virtual std::string get_remote_information() const = 0;
+ virtual std::uint32_t get_max_allowed_reconnects() const = 0;
+ virtual void max_allowed_reconnects_reached() = 0;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/endpoint.hpp b/implementation/endpoints/include/endpoint.hpp index f3bf510..b1204f0 100644 --- a/implementation/endpoints/include/endpoint.hpp +++ b/implementation/endpoints/include/endpoint.hpp @@ -25,7 +25,7 @@ public: virtual void start() = 0;
virtual void stop() = 0;
- virtual bool is_connected() const = 0;
+ virtual bool is_established() const = 0;
virtual bool send(const byte_t *_data, uint32_t _size,
bool _flush = true) = 0;
@@ -57,7 +57,7 @@ public: virtual void print_status() = 0;
- virtual void set_connected(bool _connected) = 0;
+ virtual void set_established(bool _established) = 0;
virtual void set_connected(bool _connected) = 0;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/local_client_endpoint_impl.hpp b/implementation/endpoints/include/local_client_endpoint_impl.hpp index 214a6d0..16b3af5 100644 --- a/implementation/endpoints/include/local_client_endpoint_impl.hpp +++ b/implementation/endpoints/include/local_client_endpoint_impl.hpp @@ -63,6 +63,8 @@ private: std::size_t _bytes); void set_local_port(); std::string get_remote_information() const; + std::uint32_t get_max_allowed_reconnects() const; + void max_allowed_reconnects_reached(); message_buffer_t recv_buffer_; }; diff --git a/implementation/endpoints/include/local_server_endpoint_impl.hpp b/implementation/endpoints/include/local_server_endpoint_impl.hpp index aee73c4..8ff8a10 100644 --- a/implementation/endpoints/include/local_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/local_server_endpoint_impl.hpp @@ -43,7 +43,8 @@ public: boost::asio::io_service &_io, std::uint32_t _max_message_size, std::uint32_t _buffer_shrink_threshold, - configuration::endpoint_queue_limit_t _queue_limit); + configuration::endpoint_queue_limit_t _queue_limit, + std::uint32_t _mode); local_server_endpoint_impl(std::shared_ptr<endpoint_host> _host, endpoint_type _local, @@ -51,7 +52,8 @@ public: std::uint32_t _max_message_size, int native_socket, std::uint32_t _buffer_shrink_threshold, - configuration::endpoint_queue_limit_t _queue_limit); + configuration::endpoint_queue_limit_t _queue_limit, + std::uint32_t _mode); virtual ~local_server_endpoint_impl(); @@ -90,12 +92,14 @@ private: void send_queued(const queue_iterator_type _queue_iterator); void set_bound_client(client_t _client); + client_t get_bound_client() const; + std::size_t get_recv_buffer_capacity() const; private: connection(std::weak_ptr<local_server_endpoint_impl> _server, - std::uint32_t _recv_buffer_size_initial, std::uint32_t _max_message_size, + std::uint32_t _recv_buffer_size_initial, std::uint32_t _buffer_shrink_threshold, boost::asio::io_service &_io_service); @@ -133,6 +137,10 @@ private: typedef std::map<endpoint_type, connection::ptr> connections_t; std::mutex connections_mutex_; connections_t connections_; + + std::mutex client_connections_mutex_; + std::map<client_t, connection::ptr> client_connections_; + const std::uint32_t buffer_shrink_threshold_; private: diff --git a/implementation/endpoints/include/netlink_connector.hpp b/implementation/endpoints/include/netlink_connector.hpp index f71ba88..730874e 100644 --- a/implementation/endpoints/include/netlink_connector.hpp +++ b/implementation/endpoints/include/netlink_connector.hpp @@ -67,7 +67,7 @@ public: /// Get the underlying endpoint in the native type. data_type* data() { - return &sockaddr; + return reinterpret_cast<struct sockaddr*>(&sockaddr); } /// Get the underlying endpoint in the native type. diff --git a/implementation/endpoints/include/server_endpoint_impl.hpp b/implementation/endpoints/include/server_endpoint_impl.hpp index 60e8ff4..68e719b 100644 --- a/implementation/endpoints/include/server_endpoint_impl.hpp +++ b/implementation/endpoints/include/server_endpoint_impl.hpp @@ -38,7 +38,8 @@ public: bool is_client() const;
void restart(bool _force);
- bool is_connected() const;
+ bool is_established() const;
+ void set_established(bool _established);
void set_connected(bool _connected);
bool send(const uint8_t *_data, uint32_t _size, bool _flush);
bool send(const std::vector<byte_t>& _cmd_header, const byte_t *_data,
diff --git a/implementation/endpoints/include/tcp_client_endpoint_impl.hpp b/implementation/endpoints/include/tcp_client_endpoint_impl.hpp index cbadf5a..77cbd39 100644 --- a/implementation/endpoints/include/tcp_client_endpoint_impl.hpp +++ b/implementation/endpoints/include/tcp_client_endpoint_impl.hpp @@ -25,9 +25,11 @@ public: endpoint_type _remote,
boost::asio::io_service &_io,
std::uint32_t _max_message_size,
- std::uint32_t buffer_shrink_threshold,
+ std::uint32_t _buffer_shrink_threshold,
std::chrono::milliseconds _send_timeout,
- configuration::endpoint_queue_limit_t _queue_limit);
+ configuration::endpoint_queue_limit_t _queue_limit,
+ std::uint32_t _tcp_restart_aborts_max,
+ std::uint32_t _tcp_connect_time_max);
virtual ~tcp_client_endpoint_impl();
void start();
@@ -71,6 +73,8 @@ private: service_t _service, method_t _method, client_t _client, session_t _session,
std::chrono::steady_clock::time_point _start);
std::string get_remote_information() const;
+ std::uint32_t get_max_allowed_reconnects() const;
+ void max_allowed_reconnects_reached();
const std::uint32_t recv_buffer_size_initial_;
message_buffer_ptr_t recv_buffer_;
@@ -82,6 +86,11 @@ private: std::chrono::steady_clock::time_point last_cookie_sent_;
const std::chrono::milliseconds send_timeout_;
const std::chrono::milliseconds send_timeout_warning_;
+
+ std::uint32_t tcp_restart_aborts_max_;
+ std::uint32_t tcp_connect_time_max_;
+ std::atomic<uint32_t> aborted_restart_count_;
+ std::chrono::steady_clock::time_point connect_timepoint_;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/udp_client_endpoint_impl.hpp b/implementation/endpoints/include/udp_client_endpoint_impl.hpp index 1866d05..b11da93 100644 --- a/implementation/endpoints/include/udp_client_endpoint_impl.hpp +++ b/implementation/endpoints/include/udp_client_endpoint_impl.hpp @@ -30,14 +30,15 @@ public: endpoint_type _local,
endpoint_type _remote,
boost::asio::io_service &_io,
- configuration::endpoint_queue_limit_t _queue_limit);
+ configuration::endpoint_queue_limit_t _queue_limit,
+ std::uint32_t _udp_receive_buffer_size);
virtual ~udp_client_endpoint_impl();
void start();
void restart(bool _force);
void receive_cbk(boost::system::error_code const &_error,
- std::size_t _bytes);
+ std::size_t _bytes, message_buffer_ptr_t _recv_buffer);
bool get_remote_address(boost::asio::ip::address &_address) const;
std::uint16_t get_remote_port() const;
@@ -51,11 +52,12 @@ private: const std::string get_address_port_remote() const;
const std::string get_address_port_local() const;
std::string get_remote_information() const;
-
- message_buffer_t recv_buffer_;
+ std::uint32_t get_max_allowed_reconnects() const;
+ void max_allowed_reconnects_reached();
const boost::asio::ip::address remote_address_;
const std::uint16_t remote_port_;
+ const std::uint32_t udp_receive_buffer_size_;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/udp_server_endpoint_impl.hpp b/implementation/endpoints/include/udp_server_endpoint_impl.hpp index 48e4935..f1b6959 100644 --- a/implementation/endpoints/include/udp_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/udp_server_endpoint_impl.hpp @@ -26,7 +26,8 @@ public: udp_server_endpoint_impl(std::shared_ptr<endpoint_host> _host,
endpoint_type _local,
boost::asio::io_service &_io,
- configuration::endpoint_queue_limit_t _queue_limit);
+ configuration::endpoint_queue_limit_t _queue_limit,
+ std::uint32_t _udp_receive_buffer_size);
virtual ~udp_server_endpoint_impl();
void start();
@@ -64,6 +65,8 @@ private: std::string get_remote_information(
const queue_iterator_type _queue_iterator) const;
+ const std::string get_address_port_local() const;
+
private:
socket_type socket_;
endpoint_type remote_;
@@ -75,7 +78,7 @@ private: std::atomic<bool> joined_group_;
message_buffer_t recv_buffer_;
- std::mutex socket_mutex_;
+ mutable std::mutex socket_mutex_;
const std::uint16_t local_port_;
};
diff --git a/implementation/endpoints/include/virtual_server_endpoint_impl.hpp b/implementation/endpoints/include/virtual_server_endpoint_impl.hpp index 58619cc..afe56e2 100644 --- a/implementation/endpoints/include/virtual_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/virtual_server_endpoint_impl.hpp @@ -24,7 +24,8 @@ public: void start(); void stop(); - bool is_connected() const; + bool is_established() const; + void set_established(bool _established); void set_connected(bool _connected); bool send(const byte_t *_data, uint32_t _size, bool _flush); diff --git a/implementation/endpoints/src/client_endpoint_impl.cpp b/implementation/endpoints/src/client_endpoint_impl.cpp index b4a6bf9..2f521ea 100644 --- a/implementation/endpoints/src/client_endpoint_impl.cpp +++ b/implementation/endpoints/src/client_endpoint_impl.cpp @@ -38,10 +38,12 @@ client_endpoint_impl<Protocol>::client_endpoint_impl( flush_timer_(_io), connect_timer_(_io),
connect_timeout_(VSOMEIP_DEFAULT_CONNECT_TIMEOUT), // TODO: use config variable
state_(cei_state_e::CLOSED),
+ reconnect_counter_(0),
packetizer_(std::make_shared<message_buffer_t>()),
queue_size_(0),
was_not_connected_(false),
- local_port_(0) {
+ local_port_(0), + strand_(_io) { }
template<typename Protocol>
@@ -54,22 +56,38 @@ bool client_endpoint_impl<Protocol>::is_client() const { }
template<typename Protocol>
-bool client_endpoint_impl<Protocol>::is_connected() const {
+bool client_endpoint_impl<Protocol>::is_established() const {
return state_ == cei_state_e::ESTABLISHED;
}
template<typename Protocol>
+void client_endpoint_impl<Protocol>::set_established(bool _established) {
+ if (_established) {
+ if (state_ != cei_state_e::CONNECTING) {
+ std::lock_guard<std::mutex> its_lock(socket_mutex_);
+ if (socket_->is_open()) {
+ state_ = cei_state_e::ESTABLISHED;
+ } else {
+ state_ = cei_state_e::CLOSED;
+ }
+ }
+ } else {
+ state_ = cei_state_e::CLOSED;
+ }
}
+template<typename Protocol>
void client_endpoint_impl<Protocol>::set_connected(bool _connected) {
if (_connected) {
std::lock_guard<std::mutex> its_lock(socket_mutex_);
if (socket_->is_open()) {
- state_ = cei_state_e::ESTABLISHED;
+ state_ = cei_state_e::CONNECTED;
} else {
state_ = cei_state_e::CLOSED;
}
} else {
state_ = cei_state_e::CLOSED;
- }
}
+ }
+}
+
template<typename Protocol>
void client_endpoint_impl<Protocol>::stop() {
{
std::lock_guard<std::mutex> its_lock(mutex_);
@@ -159,7 +177,8 @@ bool client_endpoint_impl<Protocol>::flush() { template<typename Protocol>
void client_endpoint_impl<Protocol>::connect_cbk(
boost::system::error_code const &_error) {
- if (_error == boost::asio::error::operation_aborted) {
+ if (_error == boost::asio::error::operation_aborted
+ || endpoint_impl<Protocol>::sending_blocked_) {
// endpoint was stopped
shutdown_and_close_socket(false);
return;
@@ -173,7 +192,12 @@ void client_endpoint_impl<Protocol>::connect_cbk( state_ = cei_state_e::CLOSED;
its_host->on_disconnect(this->shared_from_this());
}
- start_connect_timer();
+ if (get_max_allowed_reconnects() == MAX_RECONNECTS_UNLIMITED ||
+ get_max_allowed_reconnects() >= ++reconnect_counter_) {
+ start_connect_timer();
+ } else {
+ max_allowed_reconnects_reached();
+ }
// Double the timeout as long as the maximum allowed is larger
if (connect_timeout_ < VSOMEIP_MAX_CONNECT_TIMEOUT)
connect_timeout_ = (connect_timeout_ << 1);
@@ -183,13 +207,8 @@ void client_endpoint_impl<Protocol>::connect_cbk( connect_timer_.cancel();
}
connect_timeout_ = VSOMEIP_DEFAULT_CONNECT_TIMEOUT; // TODO: use config variable
+ reconnect_counter_ = 0;
set_local_port();
- if (state_ != cei_state_e::ESTABLISHED) {
- its_host->on_connect(this->shared_from_this());
- }
-
- receive();
-
if (was_not_connected_) {
was_not_connected_ = false;
std::lock_guard<std::mutex> its_lock(mutex_);
@@ -199,6 +218,10 @@ void client_endpoint_impl<Protocol>::connect_cbk( << get_remote_information();
}
}
+ if (state_ != cei_state_e::ESTABLISHED) {
+ its_host->on_connect(this->shared_from_this());
+ }
+ receive();
}
}
}
@@ -269,8 +292,17 @@ void client_endpoint_impl<Protocol>::send_cbk( shutdown_and_close_socket(true);
connect();
} else if (_error == boost::asio::error::not_connected
- || _error == boost::asio::error::bad_descriptor) {
+ || _error == boost::asio::error::bad_descriptor
+ || _error == boost::asio::error::no_permission) {
state_ = cei_state_e::CLOSED;
+ if (_error == boost::asio::error::no_permission) {
+ VSOMEIP_WARNING << "cei::send_cbk received error: " << _error.message()
+ << " (" << std::dec << _error.value() << ") "
+ << get_remote_information();
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ queue_.clear();
+ queue_size_ = 0;
+ }
was_not_connected_ = true;
shutdown_and_close_socket(true);
connect();
@@ -332,6 +364,12 @@ template<typename Protocol> void client_endpoint_impl<Protocol>::shutdown_and_close_socket_unlocked(bool _recreate_socket) {
local_port_ = 0;
if (socket_->is_open()) {
+#ifndef _WIN32 + if (-1 == fcntl(socket_->native_handle(), F_GETFD)) { + VSOMEIP_ERROR << "cei::shutdown_and_close_socket_unlocked: socket/handle closed already '" << std::string(std::strerror(errno)) + << "' (" << errno << ") " << get_remote_information(); + } +#endif boost::system::error_code its_error;
socket_->shutdown(Protocol::socket::shutdown_both, its_error);
socket_->close(its_error);
diff --git a/implementation/endpoints/src/credentials.cpp b/implementation/endpoints/src/credentials.cpp index 84f7f08..411fd3f 100644 --- a/implementation/endpoints/src/credentials.cpp +++ b/implementation/endpoints/src/credentials.cpp @@ -17,14 +17,16 @@ namespace vsomeip { void credentials::activate_credentials(const int _fd) { int optval = 1; if (setsockopt(_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) { - VSOMEIP_ERROR << "Activating socket option for receiving credentials failed."; + VSOMEIP_ERROR << "vSomeIP Security: Activating socket option for receiving " + << "credentials failed."; } } void credentials::deactivate_credentials(const int _fd) { int optval = 0; if (setsockopt(_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) { - VSOMEIP_ERROR << "Deactivating socket option for receiving credentials failed."; + VSOMEIP_ERROR << "vSomeIP Security: Deactivating socket option for receiving " + << "credentials failed."; } } @@ -62,13 +64,13 @@ client_t credentials::receive_credentials(const int _fd, uid_t& _uid, gid_t& _gi // Receive client_id plus ancillary data ssize_t nr = recvmsg(_fd, &msgh, 0); if (nr == -1) { - VSOMEIP_ERROR << "Receiving credentials failed. No data."; + VSOMEIP_ERROR << "vSomeIP Security: Receiving credentials failed. No data."; } cmhp = CMSG_FIRSTHDR(&msgh); if (cmhp == NULL || cmhp->cmsg_len != CMSG_LEN(sizeof(struct ucred)) || cmhp->cmsg_level != SOL_SOCKET || cmhp->cmsg_type != SCM_CREDENTIALS) { - VSOMEIP_ERROR << "Receiving credentials failed. Invalid data."; + VSOMEIP_ERROR << "vSomeIP Security: Receiving credentials failed. Invalid data."; } else { ucredp = (struct ucred *) CMSG_DATA(cmhp); _uid = ucredp->uid; diff --git a/implementation/endpoints/src/local_client_endpoint_impl.cpp b/implementation/endpoints/src/local_client_endpoint_impl.cpp index 29d861f..a57c831 100644 --- a/implementation/endpoints/src/local_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/local_client_endpoint_impl.cpp @@ -60,6 +60,8 @@ void local_client_endpoint_impl::restart(bool _force) { std::lock_guard<std::mutex> its_lock(socket_mutex_);
shutdown_and_close_socket_unlocked(true);
}
+ was_not_connected_ = true;
+ reconnect_counter_ = 0;
start_connect_timer();
}
@@ -139,13 +141,14 @@ void local_client_endpoint_impl::connect() { } else {
VSOMEIP_WARNING << "local_client_endpoint::connect: Error opening socket: "
- << its_error.message();
- return;
+ << its_error.message() << " (" << std::dec << its_error.value()
+ << ")";
+ its_connect_error = its_error;
}
}
// call connect_cbk asynchronously
try {
- service_.post(
+ strand_.post( std::bind(&client_endpoint_impl::connect_cbk, shared_from_this(),
its_connect_error));
} catch (const std::exception &e) {
@@ -158,13 +161,15 @@ void local_client_endpoint_impl::receive() { if (socket_->is_open()) {
socket_->async_receive(
boost::asio::buffer(recv_buffer_),
- std::bind(
- &local_client_endpoint_impl::receive_cbk,
- std::dynamic_pointer_cast<
- local_client_endpoint_impl
- >(shared_from_this()),
- std::placeholders::_1,
- std::placeholders::_2
+ strand_.wrap( + std::bind( + &local_client_endpoint_impl::receive_cbk, + std::dynamic_pointer_cast< + local_client_endpoint_impl + >(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2 + ) )
);
}
@@ -232,10 +237,6 @@ void local_client_endpoint_impl::receive_cbk( VSOMEIP_ERROR << "Local endpoint received message ("
<< _error.message() << ")";
}
- // The error handler is set only if the endpoint is hosted by the
- // routing manager. For the routing manager proxies, the corresponding
- // client endpoint (that connect to the same client) are removed
- // after the proxy has received the routing info.
error_handler_t handler;
{
std::lock_guard<std::mutex> its_lock(error_handler_mutex_);
@@ -290,6 +291,10 @@ std::string local_client_endpoint_impl::get_remote_information() const { #endif
}
+std::uint32_t local_client_endpoint_impl::get_max_allowed_reconnects() const {
+ return 13;
+}
+
bool local_client_endpoint_impl::send(const std::vector<byte_t>& _cmd_header,
const byte_t *_data, uint32_t _size,
bool _flush) {
@@ -319,4 +324,16 @@ bool local_client_endpoint_impl::send(const std::vector<byte_t>& _cmd_header, return ret;
}
+void local_client_endpoint_impl::max_allowed_reconnects_reached() {
+ VSOMEIP_ERROR << "local_client_endpoint::max_allowed_reconnects_reached: "
+ << get_remote_information();
+ error_handler_t handler;
+ {
+ std::lock_guard<std::mutex> its_lock(error_handler_mutex_);
+ handler = error_handler_;
+ }
+ if (handler)
+ handler();
+}
+
} // namespace vsomeip
diff --git a/implementation/endpoints/src/local_server_endpoint_impl.cpp b/implementation/endpoints/src/local_server_endpoint_impl.cpp index 6ae9c6c..cfd5c0b 100644 --- a/implementation/endpoints/src/local_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/local_server_endpoint_impl.cpp @@ -30,7 +30,7 @@ local_server_endpoint_impl::local_server_endpoint_impl( endpoint_type _local, boost::asio::io_service &_io, std::uint32_t _max_message_size, std::uint32_t _buffer_shrink_threshold, - configuration::endpoint_queue_limit_t _queue_limit) + configuration::endpoint_queue_limit_t _queue_limit, std::uint32_t _mode) : local_server_endpoint_base_impl(_host, _local, _io, _max_message_size, _queue_limit), acceptor_(_io), @@ -48,8 +48,11 @@ local_server_endpoint_impl::local_server_endpoint_impl( boost::asio::detail::throw_error(ec, "acceptor listen"); #ifndef _WIN32 + if (chmod(_local.path().c_str(), static_cast<mode_t>(_mode)) == -1) { + VSOMEIP_ERROR << __func__ << ": chmod: " << strerror(errno); + } if (_host->get_configuration()->is_security_enabled()) { - credentials::activate_credentials(acceptor_.native()); + credentials::activate_credentials(acceptor_.native_handle()); } #endif } @@ -60,7 +63,7 @@ local_server_endpoint_impl::local_server_endpoint_impl( std::uint32_t _max_message_size, int native_socket, std::uint32_t _buffer_shrink_threshold, - configuration::endpoint_queue_limit_t _queue_limit) + configuration::endpoint_queue_limit_t _queue_limit, std::uint32_t _mode) : local_server_endpoint_base_impl(_host, _local, _io, _max_message_size, _queue_limit), acceptor_(_io), @@ -72,8 +75,11 @@ local_server_endpoint_impl::local_server_endpoint_impl( boost::asio::detail::throw_error(ec, "acceptor assign native socket"); #ifndef _WIN32 + if (chmod(_local.path().c_str(), static_cast<mode_t>(_mode)) == -1) { + VSOMEIP_ERROR << __func__ << ": chmod: " << strerror(errno); + } if (_host->get_configuration()->is_security_enabled()) { - credentials::activate_credentials(acceptor_.native()); + credentials::activate_credentials(acceptor_.native_handle()); } #endif } @@ -127,6 +133,12 @@ void local_server_endpoint_impl::stop() { } connections_.clear(); } +#ifndef _WIN32 + { + std::lock_guard<std::mutex> its_lock(client_connections_mutex_); + client_connections_.clear(); + } +#endif } bool local_server_endpoint_impl::send_to( @@ -178,15 +190,31 @@ bool local_server_endpoint_impl::get_default_target( void local_server_endpoint_impl::remove_connection( local_server_endpoint_impl::connection *_connection) { - std::lock_guard<std::mutex> its_lock(connections_mutex_); - for (auto it = connections_.begin(); it != connections_.end();) { - if (it->second.get() == _connection) { - it = connections_.erase(it); - break; - } else { - ++it; + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + for (auto it = connections_.begin(); it != connections_.end();) { + if (it->second.get() == _connection) { + it = connections_.erase(it); + break; + } else { + ++it; + } } } + +#ifndef _WIN32 + { + std::lock_guard<std::mutex> its_lock(client_connections_mutex_); + for (auto it = client_connections_.begin(); it != client_connections_.end();) { + if (it->second.get() == _connection) { + it = client_connections_.erase(it); + break; + } else { + ++it; + } + } + } +#endif } void local_server_endpoint_impl::accept_cbk( @@ -196,23 +224,62 @@ void local_server_endpoint_impl::accept_cbk( && _error != boost::asio::error::operation_aborted && _error != boost::asio::error::no_descriptors) { start(); + } else if (_error == boost::asio::error::no_descriptors) { + VSOMEIP_ERROR << "local_server_endpoint_impl::accept_cbk: " + << _error.message() << " (" << std::dec << _error.value() + << ") Will try to accept again in 1000ms"; + std::shared_ptr<boost::asio::steady_timer> its_timer = + std::make_shared<boost::asio::steady_timer>(service_, + std::chrono::milliseconds(1000)); + auto its_ep = std::dynamic_pointer_cast<local_server_endpoint_impl>( + shared_from_this()); + its_timer->async_wait([its_timer, its_ep] + (const boost::system::error_code& _error) { + if (!_error) { + its_ep->start(); + } + }); } if (!_error) { #ifndef _WIN32 auto its_host = host_.lock(); + client_t client = 0; if (its_host) { if (its_host->get_configuration()->is_security_enabled()) { std::unique_lock<std::mutex> its_socket_lock(_connection->get_socket_lock()); socket_type &new_connection_socket = _connection->get_socket(); - uid_t uid(0); - gid_t gid(0); - client_t client = credentials::receive_credentials( + uid_t uid(0xffffffff); + gid_t gid(0xffffffff); + client = credentials::receive_credentials( new_connection_socket.native(), uid, gid); + + std::lock_guard<std::mutex> its_client_connection_lock(client_connections_mutex_); + auto found_client = client_connections_.find(client); + if (found_client != client_connections_.end()) { + VSOMEIP_WARNING << std::hex << "vSomeIP Security: Rejecting new connection with client ID 0x" << client + << " uid/gid= " << std::dec << uid << "/" << gid + << " because of already existing connection using same client ID"; + boost::system::error_code er; + new_connection_socket.shutdown(new_connection_socket.shutdown_both, er); + new_connection_socket.close(er); + return; + } + + if (!its_host->get_configuration()->check_routing_credentials(client, uid, gid)) { + VSOMEIP_WARNING << std::hex << "vSomeIP Security: Rejecting new connection with routing manager client ID 0x" << client + << " uid/gid= " << std::dec << uid << "/" << gid + << " because passed credentials do not match with routing manager credentials!"; + boost::system::error_code er; + new_connection_socket.shutdown(new_connection_socket.shutdown_both, er); + new_connection_socket.close(er); + return; + } + if (!its_host->check_credentials(client, uid, gid)) { - VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client() - << " received client credentials from client 0x" << client - << " which violates the security policy : uid/gid=" + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex + << its_host->get_client() << " received client credentials from client 0x" + << client << " which violates the security policy : uid/gid=" << std::dec << uid << "/" << gid; boost::system::error_code er; new_connection_socket.shutdown(new_connection_socket.shutdown_both, er); @@ -234,8 +301,16 @@ void local_server_endpoint_impl::accept_cbk( } if (!its_error) { { - std::lock_guard<std::mutex> its_lock(connections_mutex_); - connections_[remote] = _connection; + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + connections_[remote] = _connection; + } +#ifndef _WIN32 + { + std::lock_guard<std::mutex> its_lock(client_connections_mutex_); + client_connections_[client] = _connection; + } +#endif } _connection->start(); } @@ -271,7 +346,6 @@ local_server_endpoint_impl::connection::create( std::uint32_t _buffer_shrink_threshold, boost::asio::io_service &_io_service) { const std::uint32_t its_initial_buffer_size = VSOMEIP_COMMAND_HEADER_SIZE - + VSOMEIP_MAX_LOCAL_MESSAGE_SIZE + static_cast<std::uint32_t>(sizeof(instance_t) + sizeof(bool) + sizeof(bool)); return ptr(new connection(_server, _max_message_size, its_initial_buffer_size, @@ -334,6 +408,12 @@ void local_server_endpoint_impl::connection::start() { void local_server_endpoint_impl::connection::stop() { std::lock_guard<std::mutex> its_lock(socket_mutex_); if (socket_.is_open()) { +#ifndef _WIN32 + if (-1 == fcntl(socket_.native_handle(), F_GETFD)) { + VSOMEIP_ERROR << "lse: socket/handle closed already '" << std::string(std::strerror(errno)) + << "' (" << errno << ") " << get_path_local(); + } +#endif boost::system::error_code its_error; socket_.shutdown(socket_.shutdown_both, its_error); socket_.close(its_error); @@ -487,19 +567,33 @@ void local_server_endpoint_impl::connection::receive_cbk( // start tag (4 Byte) + command (1 Byte) + client id (2 Byte) // + command size (4 Byte) + data itself + stop tag (4 byte) // = 15 Bytes not covered in command size. - if (its_command_size && its_command_size + 15 > recv_buffer_size_) { + if (its_command_size + 15 > recv_buffer_size_) { missing_capacity_ = its_command_size + 15 - std::uint32_t(recv_buffer_size_); } else if (recv_buffer_size_ < 11) { // to little data to read out the command size // minimal amount of data needed to read out command size = 11 missing_capacity_ = 11 - static_cast<std::uint32_t>(recv_buffer_size_); } else { + std::stringstream local_msg; + for (std::size_t i = its_iteration_gap; + i < recv_buffer_size_ + its_iteration_gap && + i - its_iteration_gap < 32; i++) { + local_msg << std::setw(2) << std::setfill('0') + << std::hex << (int) recv_buffer_[i] << " "; + } VSOMEIP_ERROR << "lse::c<" << this << ">rcb: recv_buffer_size is: " << std::dec << recv_buffer_size_ << " but couldn't read " "out command size. recv_buffer_capacity: " - << recv_buffer_.capacity() - << " its_iteration_gap: " << its_iteration_gap; + << std::dec << recv_buffer_.capacity() + << " its_iteration_gap: " << std::dec + << its_iteration_gap << " bound client: 0x" + << std::hex << bound_client_ << " buffer: " + << local_msg.str(); + recv_buffer_size_ = 0; + missing_capacity_ = 0; + its_iteration_gap = 0; + message_is_empty = true; } } } @@ -525,7 +619,7 @@ void local_server_endpoint_impl::connection::receive_cbk( found_message = true; its_iteration_gap = its_end + 4; } else { - if (!message_is_empty && its_iteration_gap) { + if (its_iteration_gap) { // Message not complete and not in front of the buffer! // Copy last part to front for consume in future receive_cbk call! for (size_t i = 0; i < recv_buffer_size_; ++i) { @@ -545,6 +639,7 @@ void local_server_endpoint_impl::connection::receive_cbk( || _error == boost::asio::error::connection_reset) { stop(); its_server->remove_connection(this); + its_host->get_configuration()->remove_client_to_uid_gid_mapping(bound_client_); } else if (_error != boost::asio::error::bad_descriptor) { start(); } @@ -555,6 +650,11 @@ void local_server_endpoint_impl::connection::set_bound_client(client_t _client) bound_client_ = _client; } +client_t local_server_endpoint_impl::connection::get_bound_client() const { + return bound_client_; +} + + void local_server_endpoint_impl::connection::calculate_shrink_count() { if (buffer_shrink_threshold_) { if (recv_buffer_.capacity() != recv_buffer_size_initial_) { @@ -624,6 +724,12 @@ void local_server_endpoint_impl::connection::handle_recv_buffer_exception( VSOMEIP_ERROR << its_message.str(); recv_buffer_.clear(); if (socket_.is_open()) { +#ifndef _WIN32 + if (-1 == fcntl(socket_.native_handle(), F_GETFD)) { + VSOMEIP_ERROR << "lse: socket/handle closed already '" << std::string(std::strerror(errno)) + << "' (" << errno << ") " << get_path_local(); + } +#endif boost::system::error_code its_error; socket_.shutdown(socket_.shutdown_both, its_error); socket_.close(its_error); diff --git a/implementation/endpoints/src/netlink_connector.cpp b/implementation/endpoints/src/netlink_connector.cpp index 94b75cf..2f9e2e5 100644 --- a/implementation/endpoints/src/netlink_connector.cpp +++ b/implementation/endpoints/src/netlink_connector.cpp @@ -103,7 +103,7 @@ void netlink_connector::receive_cbk(boost::system::error_code const &_error, struct nlmsghdr *nlh = (struct nlmsghdr *)&recv_buffer_[0]; while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) { - char ifname[1024]; + char ifname[IF_NAMESIZE]; switch (nlh->nlmsg_type) { case RTM_NEWADDR: { // New Address information @@ -356,7 +356,7 @@ bool netlink_connector::check_sd_multicast_route_match(struct rtmsg* _routemsg, struct rtattr *retrta; retrta = static_cast<struct rtattr *>(RTM_RTA(_routemsg)); int if_index(0); - char if_name[1024] = "n/a"; + char if_name[IF_NAMESIZE] = "n/a"; char address[INET6_ADDRSTRLEN] = "n/a"; char gateway[INET6_ADDRSTRLEN] = "n/a"; bool matches_sd_multicast(false); diff --git a/implementation/endpoints/src/server_endpoint_impl.cpp b/implementation/endpoints/src/server_endpoint_impl.cpp index 6da5826..915bfc9 100644 --- a/implementation/endpoints/src/server_endpoint_impl.cpp +++ b/implementation/endpoints/src/server_endpoint_impl.cpp @@ -19,6 +19,7 @@ #include "../../logging/include/logger.hpp"
#include "../../utility/include/byteorder.hpp"
#include "../../utility/include/utility.hpp"
+#include "../../service_discovery/include/defines.hpp"
namespace vsomeip {
@@ -54,12 +55,17 @@ void server_endpoint_impl<Protocol>::restart(bool _force) { }
template<typename Protocol>
-bool server_endpoint_impl<Protocol>::is_connected() const {
+bool server_endpoint_impl<Protocol>::is_established() const {
return true;
}
template<typename Protocol>
-void server_endpoint_impl<Protocol>::set_connected(bool _connected) {
(void) _connected;
}
+void server_endpoint_impl<Protocol>::set_established(bool _established) {
(void) _established;
}
+
+template<typename Protocol>
+void server_endpoint_impl<Protocol>::set_connected(bool _connected) {
+ (void) _connected;
+}
template<typename Protocol>
bool server_endpoint_impl<Protocol>::send(const uint8_t *_data,
uint32_t _size, bool _flush) {
#if 0
@@ -102,6 +108,16 @@ template<typename Protocol>
bool server_endpoint_impl<Protocol>::send(const uint VSOMEIP_WARNING << "server_endpoint::send: session_id 0x"
<< std::hex << its_session
<< " not found for client 0x" << its_client;
+ const method_t its_method =
+ VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN],
+ _data[VSOMEIP_METHOD_POS_MAX]);
+ if (its_service == VSOMEIP_SD_SERVICE
+ && its_method == VSOMEIP_SD_METHOD) {
+ VSOMEIP_ERROR << "Clearing clients map as a request was "
+ "received on SD port";
+ clients_.clear();
+ is_valid_target = get_default_target(its_service, its_target);
+ }
}
} else {
is_valid_target = get_default_target(its_service, its_target);
diff --git a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp index cb92619..41254f6 100644 --- a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp @@ -30,7 +30,9 @@ tcp_client_endpoint_impl::tcp_client_endpoint_impl( std::uint32_t _max_message_size,
std::uint32_t _buffer_shrink_threshold,
std::chrono::milliseconds _send_timeout,
- configuration::endpoint_queue_limit_t _queue_limit)
+ configuration::endpoint_queue_limit_t _queue_limit,
+ std::uint32_t _tcp_restart_aborts_max,
+ std::uint32_t _tcp_connect_time_max)
: tcp_client_endpoint_base_impl(_host, _local, _remote, _io,
_max_message_size, _queue_limit),
recv_buffer_size_initial_(VSOMEIP_SOMEIP_HEADER_SIZE),
@@ -41,7 +43,10 @@ tcp_client_endpoint_impl::tcp_client_endpoint_impl( remote_port_(_remote.port()),
last_cookie_sent_(std::chrono::steady_clock::now() - std::chrono::seconds(11)),
send_timeout_(_send_timeout),
- send_timeout_warning_(_send_timeout / 2) {
+ send_timeout_warning_(_send_timeout / 2),
+ tcp_restart_aborts_max_(_tcp_restart_aborts_max),
+ tcp_connect_time_max_(_tcp_connect_time_max),
+ aborted_restart_count_(0) {
is_supporting_magic_cookies_ = true;
}
@@ -62,7 +67,19 @@ void tcp_client_endpoint_impl::start() { void tcp_client_endpoint_impl::restart(bool _force) {
if (!_force && state_ == cei_state_e::CONNECTING) {
- return;
+ std::chrono::steady_clock::time_point its_current
+ = std::chrono::steady_clock::now();
+ long its_connect_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
+ its_current - connect_timepoint_).count();
+ if (aborted_restart_count_ < tcp_restart_aborts_max_
+ && its_connect_duration < tcp_connect_time_max_) {
+ aborted_restart_count_++;
+ return;
+ } else {
+ VSOMEIP_WARNING << "tce::restart: maximum number of aborted restarts ["
+ << tcp_restart_aborts_max_ << "] reached! its_connect_duration: "
+ << its_connect_duration;
+ }
}
state_ = cei_state_e::CONNECTING;
std::string address_port_local;
@@ -72,6 +89,8 @@ void tcp_client_endpoint_impl::restart(bool _force) { shutdown_and_close_socket_unlocked(true);
recv_buffer_ = std::make_shared<message_buffer_t>(recv_buffer_size_initial_, 0);
}
+ was_not_connected_ = true;
+ reconnect_counter_ = 0;
{
std::lock_guard<std::mutex> its_lock(mutex_);
for (const auto&m : queue_) {
@@ -150,7 +169,7 @@ void tcp_client_endpoint_impl::connect() { << " remote:" << get_address_port_remote();
try {
// don't connect on bind error to avoid using a random port
- service_.post(std::bind(&client_endpoint_impl::connect_cbk,
+ strand_.post(std::bind(&client_endpoint_impl::connect_cbk, shared_from_this(), its_bind_error));
} catch (const std::exception &e) {
VSOMEIP_ERROR << "tcp_client_endpoint_impl::connect: "
@@ -160,17 +179,23 @@ void tcp_client_endpoint_impl::connect() { }
}
state_ = cei_state_e::CONNECTING;
+ connect_timepoint_ = std::chrono::steady_clock::now();
+ aborted_restart_count_ = 0;
socket_->async_connect(
remote_,
- std::bind(
- &tcp_client_endpoint_base_impl::connect_cbk,
- shared_from_this(),
- std::placeholders::_1
+ strand_.wrap( + std::bind( + &tcp_client_endpoint_base_impl::connect_cbk, + shared_from_this(), + std::placeholders::_1 + ) )
);
} else {
VSOMEIP_WARNING << "tcp_client_endpoint::connect: Error opening socket: "
<< its_error.message() << " remote:" << get_address_port_remote();
+ strand_.post(std::bind(&tcp_client_endpoint_base_impl::connect_cbk,
+ shared_from_this(), its_error));
}
}
@@ -200,6 +225,12 @@ void tcp_client_endpoint_impl::receive(message_buffer_ptr_t _recv_buffer, if (its_capacity < its_required_capacity) {
_recv_buffer->reserve(its_required_capacity);
_recv_buffer->resize(its_required_capacity, 0x0);
+ if (_recv_buffer->size() > 1048576) {
+ VSOMEIP_INFO << "tce: recv_buffer size is: " <<
+ _recv_buffer->size()
+ << " local: " << get_address_port_local()
+ << " remote: " << get_address_port_remote();
+ }
}
buffer_size = _missing_capacity;
} else if (buffer_shrink_threshold_
@@ -217,13 +248,15 @@ void tcp_client_endpoint_impl::receive(message_buffer_ptr_t _recv_buffer, }
socket_->async_receive(
boost::asio::buffer(&(*_recv_buffer)[_recv_buffer_size], buffer_size),
- std::bind(
- &tcp_client_endpoint_impl::receive_cbk,
- std::dynamic_pointer_cast< tcp_client_endpoint_impl >(shared_from_this()),
- std::placeholders::_1,
- std::placeholders::_2,
- _recv_buffer,
- _recv_buffer_size
+ strand_.wrap( + std::bind( + &tcp_client_endpoint_impl::receive_cbk, + std::dynamic_pointer_cast< tcp_client_endpoint_impl >(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2, + _recv_buffer, + _recv_buffer_size + ) )
);
}
@@ -431,7 +464,7 @@ void tcp_client_endpoint_impl::receive_cbk( return;
}
uint32_t current_message_size = static_cast<uint32_t>(read_message_size);
- has_full_message = (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE
+ has_full_message = (current_message_size > VSOMEIP_RETURN_CODE_POS
&& current_message_size <= _recv_buffer_size);
if (has_full_message) {
bool needs_forwarding(true);
@@ -472,58 +505,125 @@ void tcp_client_endpoint_impl::receive_cbk( _recv_buffer_size -= current_message_size;
its_iteration_gap += current_message_size;
its_missing_capacity = 0;
- } else if (max_message_size_ != MESSAGE_SIZE_UNLIMITED &&
- current_message_size > max_message_size_) {
- _recv_buffer_size = 0;
- _recv_buffer->resize(recv_buffer_size_initial_, 0x0);
- _recv_buffer->shrink_to_fit();
- if (has_enabled_magic_cookies_) {
- VSOMEIP_ERROR << "Received a TCP message which exceeds "
- << "maximum message size ("
- << std::dec << current_message_size
- << "). Magic Cookies are enabled: "
- << "Resetting receiver. local: "
- << get_address_port_local() << " remote: "
- << get_address_port_remote();
- } else {
- VSOMEIP_ERROR << "Received a TCP message which exceeds "
- << "maximum message size ("
- << std::dec << current_message_size
- << ") Magic cookies are disabled: "
- << "Client will be disabled! local: "
- << get_address_port_local() << " remote: "
- << get_address_port_remote();
- return;
- }
- } else if (current_message_size > _recv_buffer_size) {
- its_missing_capacity = current_message_size
- - static_cast<std::uint32_t>(_recv_buffer_size);
- } else if (VSOMEIP_SOMEIP_HEADER_SIZE > _recv_buffer_size) {
- its_missing_capacity = VSOMEIP_SOMEIP_HEADER_SIZE
- - static_cast<std::uint32_t>(_recv_buffer_size);
} else if (has_enabled_magic_cookies_ && _recv_buffer_size > 0) {
- uint32_t its_offset = find_magic_cookie(&(*_recv_buffer)[its_iteration_gap], _recv_buffer_size);
+ const uint32_t its_offset = find_magic_cookie(
+ &(*_recv_buffer)[its_iteration_gap], _recv_buffer_size);
if (its_offset < _recv_buffer_size) {
_recv_buffer_size -= its_offset;
its_iteration_gap += its_offset;
has_full_message = true; // trigger next loop
- } else {
+ VSOMEIP_ERROR << "Detected Magic Cookie within message data."
+ << " Resyncing. local: " << get_address_port_local()
+ << " remote: " << get_address_port_remote();
+ }
+ }
+
+ if (!has_full_message) {
+ if (_recv_buffer_size > VSOMEIP_RETURN_CODE_POS &&
+ ((*recv_buffer_)[its_iteration_gap + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION ||
+ !utility::is_valid_message_type(static_cast<message_type_e>((*recv_buffer_)[its_iteration_gap + VSOMEIP_MESSAGE_TYPE_POS])) ||
+ !utility::is_valid_return_code(static_cast<return_code_e>((*recv_buffer_)[its_iteration_gap + VSOMEIP_RETURN_CODE_POS]))
+ )) {
+ if ((*recv_buffer_)[its_iteration_gap + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) {
+ VSOMEIP_ERROR << "tce: Wrong protocol version: 0x"
+ << std::hex << std::setw(2) << std::setfill('0')
+ << std::uint32_t((*recv_buffer_)[its_iteration_gap + VSOMEIP_PROTOCOL_VERSION_POS])
+ << " local: " << get_address_port_local()
+ << " remote: " << get_address_port_remote();
+ // ensure to send back a message w/ wrong protocol version
+ its_lock.unlock();
+ its_host->on_message(&(*_recv_buffer)[its_iteration_gap],
+ VSOMEIP_SOMEIP_HEADER_SIZE + 8, this,
+ boost::asio::ip::address(),
+ VSOMEIP_ROUTING_CLIENT,
+ remote_address_,
+ remote_port_);
+ its_lock.lock();
+ } else if (!utility::is_valid_message_type(static_cast<message_type_e>(
+ (*recv_buffer_)[its_iteration_gap + VSOMEIP_MESSAGE_TYPE_POS]))) {
+ VSOMEIP_ERROR << "tce: Invalid message type: 0x"
+ << std::hex << std::setw(2) << std::setfill('0')
+ << std::uint32_t((*recv_buffer_)[its_iteration_gap + VSOMEIP_MESSAGE_TYPE_POS])
+ << " local: " << get_address_port_local()
+ << " remote: " << get_address_port_remote();
+ } else if (!utility::is_valid_return_code(static_cast<return_code_e>(
+ (*recv_buffer_)[its_iteration_gap + VSOMEIP_RETURN_CODE_POS]))) {
+ VSOMEIP_ERROR << "tce: Invalid return code: 0x"
+ << std::hex << std::setw(2) << std::setfill('0')
+ << std::uint32_t((*recv_buffer_)[its_iteration_gap + VSOMEIP_RETURN_CODE_POS])
+ << " local: " << get_address_port_local()
+ << " remote: " << get_address_port_remote();
+ }
+ state_ = cei_state_e::CONNECTING;
+ shutdown_and_close_socket_unlocked(false);
+ its_lock.unlock();
+ its_host->on_disconnect(shared_from_this());
+ restart(true);
+ return;
+ } else if (max_message_size_ != MESSAGE_SIZE_UNLIMITED &&
+ current_message_size > max_message_size_) {
+ _recv_buffer_size = 0;
+ _recv_buffer->resize(recv_buffer_size_initial_, 0x0);
+ _recv_buffer->shrink_to_fit();
+ if (has_enabled_magic_cookies_) {
+ VSOMEIP_ERROR << "Received a TCP message which exceeds "
+ << "maximum message size ("
+ << std::dec << current_message_size
+ << "). Magic Cookies are enabled: "
+ << "Resetting receiver. local: "
+ << get_address_port_local() << " remote: "
+ << get_address_port_remote();
+ } else {
+ VSOMEIP_ERROR << "Received a TCP message which exceeds "
+ << "maximum message size ("
+ << std::dec << current_message_size
+ << ") Magic cookies are disabled, "
+ << "Restarting connection. "
+ << "local: " << get_address_port_local()
+ << " remote: " << get_address_port_remote();
+ state_ = cei_state_e::CONNECTING;
+ shutdown_and_close_socket_unlocked(false);
+ its_lock.unlock();
+ its_host->on_disconnect(shared_from_this());
+ restart(true);
+ return;
+ }
+ } else if (current_message_size > _recv_buffer_size) {
+ its_missing_capacity = current_message_size
+ - static_cast<std::uint32_t>(_recv_buffer_size);
+ } else if (VSOMEIP_SOMEIP_HEADER_SIZE > _recv_buffer_size) {
+ its_missing_capacity = VSOMEIP_SOMEIP_HEADER_SIZE
+ - static_cast<std::uint32_t>(_recv_buffer_size);
+ } else if (has_enabled_magic_cookies_ && _recv_buffer_size > 0) {
+ // no need to check for magic cookie here again: has_full_message
+ // would have been set to true if there was one present in the data
_recv_buffer_size = 0;
+ _recv_buffer->resize(recv_buffer_size_initial_, 0x0);
+ _recv_buffer->shrink_to_fit();
its_missing_capacity = 0;
+ VSOMEIP_ERROR << "tce::c<" << this
+ << ">rcb: recv_buffer_capacity: "
+ << _recv_buffer->capacity()
+ << " local: " << get_address_port_local()
+ << " remote: " << get_address_port_remote()
+ << ". Didn't find magic cookie in broken data, trying to resync.";
+ } else {
+ VSOMEIP_ERROR << "tce::c<" << this
+ << ">rcb: recv_buffer_size is: " << std::dec
+ << _recv_buffer_size << " but couldn't read "
+ "out message_size. recv_buffer_capacity: "
+ << _recv_buffer->capacity()
+ << " its_iteration_gap: " << its_iteration_gap
+ << " local: " << get_address_port_local()
+ << " remote: " << get_address_port_remote()
+ << ". Restarting connection due to missing/broken data TCP stream.";
+ state_ = cei_state_e::CONNECTING;
+ shutdown_and_close_socket_unlocked(false);
+ its_lock.unlock();
+ its_host->on_disconnect(shared_from_this());
+ restart(true);
+ return;
}
- } else {
- VSOMEIP_ERROR << "tce::c<" << this
- << ">rcb: recv_buffer_size is: " << std::dec
- << _recv_buffer_size << " but couldn't read "
- "out message_size. recv_buffer_capacity: "
- << _recv_buffer->capacity()
- << " its_iteration_gap: " << its_iteration_gap
- << " local: " << get_address_port_local()
- << " remote: " << get_address_port_remote()
- << ". Restarting connection due to missing/broken data TCP stream.";
- its_lock.unlock();
- restart(true);
- return;
}
} while (has_full_message && _recv_buffer_size);
if (its_iteration_gap) {
@@ -555,7 +655,6 @@ void tcp_client_endpoint_impl::receive_cbk( VSOMEIP_WARNING << "tcp_client_endpoint receive_cbk restarting."; state_ = cei_state_e::CONNECTING;
shutdown_and_close_socket_unlocked(false);
- was_not_connected_ = true;
its_lock.unlock();
its_host->on_disconnect(shared_from_this());
restart(true);
@@ -705,7 +804,6 @@ void tcp_client_endpoint_impl::send_cbk(boost::system::error_code const &_error, } else {
state_ = cei_state_e::CONNECTING;
shutdown_and_close_socket(false);
- was_not_connected_ = true;
std::shared_ptr<endpoint_host> its_host = host_.lock();
if (its_host) {
its_host->on_disconnect(shared_from_this());
@@ -742,4 +840,12 @@ void tcp_client_endpoint_impl::send_cbk(boost::system::error_code const &_error, }
}
+std::uint32_t tcp_client_endpoint_impl::get_max_allowed_reconnects() const {
+ return MAX_RECONNECTS_UNLIMITED;
+}
+
+void tcp_client_endpoint_impl::max_allowed_reconnects_reached() {
+ return;
+}
+
} // namespace vsomeip
diff --git a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp index 9c2998f..30402c5 100644 --- a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp @@ -188,6 +188,21 @@ void tcp_server_endpoint_impl::accept_cbk(connection::ptr _connection, && _error != boost::asio::error::operation_aborted && _error != boost::asio::error::no_descriptors) { start(); + } else if (_error == boost::asio::error::no_descriptors) { + VSOMEIP_ERROR<< "tcp_server_endpoint_impl::accept_cbk: " + << _error.message() << " (" << std::dec << _error.value() + << ") Will try to accept again in 1000ms"; + std::shared_ptr<boost::asio::steady_timer> its_timer = + std::make_shared<boost::asio::steady_timer>(service_, + std::chrono::milliseconds(1000)); + auto its_ep = std::dynamic_pointer_cast<tcp_server_endpoint_impl>( + shared_from_this()); + its_timer->async_wait([its_timer, its_ep] + (const boost::system::error_code& _error) { + if (!_error) { + its_ep->start(); + } + }); } } @@ -205,7 +220,7 @@ bool tcp_server_endpoint_impl::is_reliable() const { tcp_server_endpoint_impl::connection::connection( std::weak_ptr<tcp_server_endpoint_impl> _server, std::uint32_t _max_message_size, - std::uint32_t _initial_recv_buffer_size, + std::uint32_t _recv_buffer_size_initial, std::uint32_t _buffer_shrink_threshold, bool _magic_cookies_enabled, boost::asio::io_service &_io_service, @@ -213,8 +228,8 @@ tcp_server_endpoint_impl::connection::connection( socket_(_io_service), server_(_server), max_message_size_(_max_message_size), - recv_buffer_size_initial_(_initial_recv_buffer_size), - recv_buffer_(_initial_recv_buffer_size, 0), + recv_buffer_size_initial_(_recv_buffer_size_initial), + recv_buffer_(_recv_buffer_size_initial, 0), recv_buffer_size_(0), missing_capacity_(0), shrink_count_(0), @@ -235,8 +250,7 @@ tcp_server_endpoint_impl::connection::create( boost::asio::io_service & _io_service, std::chrono::milliseconds _send_timeout) { const std::uint32_t its_initial_receveive_buffer_size = - VSOMEIP_SOMEIP_HEADER_SIZE + 8 + MAGIC_COOKIE_SIZE + 8 - + VSOMEIP_MAX_TCP_MESSAGE_SIZE; + VSOMEIP_SOMEIP_HEADER_SIZE + 8 + MAGIC_COOKIE_SIZE + 8; return ptr(new connection(_server, _max_message_size, its_initial_receveive_buffer_size, _buffer_shrink_threshold, _magic_cookies_enabled, @@ -272,6 +286,12 @@ void tcp_server_endpoint_impl::connection::receive() { if (its_capacity < its_required_capacity) { recv_buffer_.reserve(its_required_capacity); recv_buffer_.resize(its_required_capacity, 0x0); + if (recv_buffer_.size() > 1048576) { + VSOMEIP_INFO << "tse: recv_buffer size is: " << + recv_buffer_.size() + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } } buffer_size = missing_capacity_; missing_capacity_ = 0; @@ -412,7 +432,7 @@ void tcp_server_endpoint_impl::connection::receive_cbk( return; } uint32_t current_message_size = static_cast<uint32_t>(read_message_size); - has_full_message = (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE + has_full_message = (current_message_size > VSOMEIP_RETURN_CODE_POS && current_message_size <= recv_buffer_size_); if (has_full_message) { bool needs_forwarding(true); @@ -424,7 +444,12 @@ void tcp_server_endpoint_impl::connection::receive_cbk( = its_server->find_magic_cookie(&recv_buffer_[its_iteration_gap], recv_buffer_size_); if (its_offset < current_message_size) { - VSOMEIP_ERROR << "Detected Magic Cookie within message data. Resyncing."; + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "Detected Magic Cookie within message data. Resyncing." + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } if (!is_magic_cookie(its_iteration_gap)) { its_host->on_error(&recv_buffer_[its_iteration_gap], static_cast<length_t>(recv_buffer_size_),its_server.get(), @@ -443,14 +468,16 @@ void tcp_server_endpoint_impl::connection::receive_cbk( std::memcpy(&its_client, &recv_buffer_[its_iteration_gap + VSOMEIP_CLIENT_POS_MIN], sizeof(client_t)); - session_t its_session; - std::memcpy(&its_session, - &recv_buffer_[its_iteration_gap + VSOMEIP_SESSION_POS_MIN], - sizeof(session_t)); - its_server->clients_mutex_.lock(); - its_server->clients_[its_client][its_session] = remote_; - its_server->endpoint_to_client_[remote_] = its_client; - its_server->clients_mutex_.unlock(); + if (its_client != MAGIC_COOKIE_NETWORK_BYTE_ORDER) { + session_t its_session; + std::memcpy(&its_session, + &recv_buffer_[its_iteration_gap + VSOMEIP_SESSION_POS_MIN], + sizeof(session_t)); + its_server->clients_mutex_.lock(); + its_server->clients_[its_client][its_session] = remote_; + its_server->endpoint_to_client_[remote_] = its_client; + its_server->clients_mutex_.unlock(); + } } if (!magic_cookies_enabled_) { its_host->on_message(&recv_buffer_[its_iteration_gap], @@ -478,7 +505,12 @@ void tcp_server_endpoint_impl::connection::receive_cbk( its_server->find_magic_cookie(&recv_buffer_[its_iteration_gap], recv_buffer_size_); if (its_offset < recv_buffer_size_) { - VSOMEIP_ERROR << "Detected Magic Cookie within message data. Resyncing."; + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "Detected Magic Cookie within message data. Resyncing." + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } if (!is_magic_cookie(its_iteration_gap)) { its_host->on_error(&recv_buffer_[its_iteration_gap], static_cast<length_t>(recv_buffer_size_), its_server.get(), @@ -496,7 +528,53 @@ void tcp_server_endpoint_impl::connection::receive_cbk( } if (!has_full_message) { - if (max_message_size_ != MESSAGE_SIZE_UNLIMITED + if (recv_buffer_size_ > VSOMEIP_RETURN_CODE_POS && + (recv_buffer_[its_iteration_gap + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION || + !utility::is_valid_message_type(static_cast<message_type_e>(recv_buffer_[its_iteration_gap + VSOMEIP_MESSAGE_TYPE_POS])) || + !utility::is_valid_return_code(static_cast<return_code_e>(recv_buffer_[its_iteration_gap + VSOMEIP_RETURN_CODE_POS])) + )) { + if (recv_buffer_[its_iteration_gap + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) { + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "tse: Wrong protocol version: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(recv_buffer_[its_iteration_gap + VSOMEIP_PROTOCOL_VERSION_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << ". Closing connection due to missing/broken data TCP stream."; + } + // ensure to send back a error message w/ wrong protocol version + its_host->on_message(&recv_buffer_[its_iteration_gap], + VSOMEIP_SOMEIP_HEADER_SIZE + 8, its_server.get(), + boost::asio::ip::address(), + VSOMEIP_ROUTING_CLIENT, + remote_address_, remote_port_); + } else if (!utility::is_valid_message_type(static_cast<message_type_e>( + recv_buffer_[its_iteration_gap + VSOMEIP_MESSAGE_TYPE_POS]))) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "tse: Invalid message type: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(recv_buffer_[its_iteration_gap + VSOMEIP_MESSAGE_TYPE_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << ". Closing connection due to missing/broken data TCP stream."; + } else if (!utility::is_valid_return_code(static_cast<return_code_e>( + recv_buffer_[its_iteration_gap + VSOMEIP_RETURN_CODE_POS]))) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "tse: Invalid return code: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(recv_buffer_[its_iteration_gap + VSOMEIP_RETURN_CODE_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << ". Closing connection due to missing/broken data TCP stream."; + } + { + std::lock_guard<std::mutex> its_lock(its_server->connections_mutex_); + stop(); + } + its_server->remove_connection(this); + return; + } else if (max_message_size_ != MESSAGE_SIZE_UNLIMITED && current_message_size > max_message_size_) { std::lock_guard<std::mutex> its_lock(socket_mutex_); recv_buffer_size_ = 0; @@ -517,9 +595,14 @@ void tcp_server_endpoint_impl::connection::receive_cbk( << std::dec << current_message_size << " > " << std::dec << max_message_size_ << ") Magic cookies are disabled: " - << "Connection will be disabled! local: " + << "Connection will be closed! local: " << get_address_port_local() << " remote: " << get_address_port_remote(); + { + std::lock_guard<std::mutex> its_lock(its_server->connections_mutex_); + stop(); + } + its_server->remove_connection(this); return; } } else if (current_message_size > recv_buffer_size_) { @@ -528,6 +611,18 @@ void tcp_server_endpoint_impl::connection::receive_cbk( } else if (VSOMEIP_SOMEIP_HEADER_SIZE > recv_buffer_size_) { missing_capacity_ = VSOMEIP_SOMEIP_HEADER_SIZE - static_cast<std::uint32_t>(recv_buffer_size_); + } else if (magic_cookies_enabled_ && recv_buffer_size_ > 0) { + // no need to check for magic cookie here again: has_full_message + // would have been set to true if there was one present in the data + recv_buffer_size_ = 0; + recv_buffer_.resize(recv_buffer_size_initial_, 0x0); + recv_buffer_.shrink_to_fit(); + missing_capacity_ = 0; + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "Didn't find magic cookie in broken" + << " data, trying to resync." + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); } else { { std::lock_guard<std::mutex> its_lock(socket_mutex_); diff --git a/implementation/endpoints/src/udp_client_endpoint_impl.cpp b/implementation/endpoints/src/udp_client_endpoint_impl.cpp index 7be55f4..67c9703 100644 --- a/implementation/endpoints/src/udp_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/udp_client_endpoint_impl.cpp @@ -20,12 +20,13 @@ udp_client_endpoint_impl::udp_client_endpoint_impl( endpoint_type _local,
endpoint_type _remote,
boost::asio::io_service &_io,
- configuration::endpoint_queue_limit_t _queue_limit)
+ configuration::endpoint_queue_limit_t _queue_limit,
+ std::uint32_t _udp_receive_buffer_size)
: udp_client_endpoint_base_impl(_host, _local, _remote, _io,
VSOMEIP_MAX_UDP_MESSAGE_SIZE, _queue_limit),
- recv_buffer_(VSOMEIP_MAX_UDP_MESSAGE_SIZE, 0),
remote_address_(_remote.address()),
- remote_port_(_remote.port()) {
+ remote_port_(_remote.port()),
+ udp_receive_buffer_size_(_udp_receive_buffer_size) {
}
udp_client_endpoint_impl::~udp_client_endpoint_impl() {
@@ -53,6 +54,26 @@ void udp_client_endpoint_impl::connect() { << "SO_REUSEADDR: " << its_error.message() << " remote:"
<< get_address_port_remote();
}
+ socket_->set_option(boost::asio::socket_base::receive_buffer_size(
+ udp_receive_buffer_size_), its_error);
+ if (its_error) {
+ VSOMEIP_WARNING << "udp_client_endpoint_impl::connect: couldn't set "
+ << "SO_RCVBUF: " << its_error.message() << " to: "
+ << std::dec << udp_receive_buffer_size_ << " remote:"
+ << get_address_port_remote();
+ } else {
+ boost::asio::socket_base::receive_buffer_size its_option;
+ socket_->get_option(its_option, its_error);
+ if (its_error) {
+ VSOMEIP_WARNING << "udp_client_endpoint_impl::connect: couldn't get "
+ << "SO_RCVBUF: " << its_error.message() << " remote:"
+ << get_address_port_remote();
+ } else {
+ VSOMEIP_INFO << "udp_client_endpoint_impl::connect: SO_RCVBUF is: "
+ << std::dec << its_option.value();
+ }
+ }
+
// In case a client endpoint port was configured,
// bind to it before connecting
if (local_.port() != ILLEGAL_PORT) {
@@ -64,7 +85,7 @@ void udp_client_endpoint_impl::connect() { << " remote:" << get_address_port_remote();
try {
// don't connect on bind error to avoid using a random port
- service_.post(std::bind(&client_endpoint_impl::connect_cbk,
+ strand_.post(std::bind(&client_endpoint_impl::connect_cbk, shared_from_this(), its_bind_error));
} catch (const std::exception &e) {
VSOMEIP_ERROR << "udp_client_endpoint_impl::connect: "
@@ -76,15 +97,19 @@ void udp_client_endpoint_impl::connect() { state_ = cei_state_e::CONNECTING;
socket_->async_connect(
remote_,
- std::bind(
- &udp_client_endpoint_base_impl::connect_cbk,
- shared_from_this(),
- std::placeholders::_1
+ strand_.wrap( + std::bind( + &udp_client_endpoint_base_impl::connect_cbk, + shared_from_this(), + std::placeholders::_1 + ) )
);
} else {
VSOMEIP_WARNING << "udp_client_endpoint::connect: Error opening socket: "
<< its_error.message() << " remote:" << get_address_port_remote();
+ strand_.post(std::bind(&udp_client_endpoint_base_impl::connect_cbk,
+ shared_from_this(), its_error));
}
}
@@ -107,6 +132,8 @@ void udp_client_endpoint_impl::restart(bool _force) { local = get_address_port_local();
}
shutdown_and_close_socket(false);
+ was_not_connected_ = true;
+ reconnect_counter_ = 0;
VSOMEIP_WARNING << "uce::restart: local: " << local
<< " remote: " << get_address_port_remote();
start_connect_timer();
@@ -148,16 +175,20 @@ void udp_client_endpoint_impl::receive() { if (!socket_->is_open()) {
return;
}
+ message_buffer_ptr_t its_buffer = std::make_shared<message_buffer_t>(VSOMEIP_MAX_UDP_MESSAGE_SIZE);
socket_->async_receive_from(
- boost::asio::buffer(&recv_buffer_[0], max_message_size_),
+ boost::asio::buffer(*its_buffer),
remote_,
- std::bind(
- &udp_client_endpoint_impl::receive_cbk,
- std::dynamic_pointer_cast<
- udp_client_endpoint_impl
- >(shared_from_this()),
- std::placeholders::_1,
- std::placeholders::_2
+ strand_.wrap(
+ std::bind(
+ &udp_client_endpoint_impl::receive_cbk,
+ std::dynamic_pointer_cast<
+ udp_client_endpoint_impl
+ >(shared_from_this()),
+ std::placeholders::_1,
+ std::placeholders::_2,
+ its_buffer
+ )
)
);
}
@@ -190,7 +221,8 @@ std::uint16_t udp_client_endpoint_impl::get_remote_port() const { }
void udp_client_endpoint_impl::receive_cbk(
- boost::system::error_code const &_error, std::size_t _bytes) {
+ boost::system::error_code const &_error, std::size_t _bytes,
+ message_buffer_ptr_t _recv_buffer) {
if (_error == boost::asio::error::operation_aborted) {
// endpoint was stopped
return;
@@ -202,7 +234,7 @@ void udp_client_endpoint_impl::receive_cbk( msg << "ucei::rcb(" << _error.message() << "): ";
for (std::size_t i = 0; i < _bytes + recv_buffer_size_; ++i)
msg << std::hex << std::setw(2) << std::setfill('0')
- << (int) recv_buffer_[i] << " ";
+ << (int) (*_recv_buffer)[i] << " ";
VSOMEIP_INFO << msg.str();
#endif
std::size_t remaining_bytes = _bytes;
@@ -210,7 +242,7 @@ void udp_client_endpoint_impl::receive_cbk( do {
uint64_t read_message_size
- = utility::get_message_size(&this->recv_buffer_[i],
+ = utility::get_message_size(&(*_recv_buffer)[i],
remaining_bytes);
if (read_message_size > MESSAGE_SIZE_UNLIMITED) {
VSOMEIP_ERROR << "Message size exceeds allowed maximum!";
@@ -222,10 +254,45 @@ void udp_client_endpoint_impl::receive_cbk( if (remaining_bytes - current_message_size > remaining_bytes) {
VSOMEIP_ERROR << "buffer underflow in udp client endpoint ~> abort!";
return;
+ } else if (current_message_size > VSOMEIP_RETURN_CODE_POS &&
+ ((*_recv_buffer)[i + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION ||
+ !utility::is_valid_message_type(static_cast<message_type_e>((*_recv_buffer)[i + VSOMEIP_MESSAGE_TYPE_POS])) ||
+ !utility::is_valid_return_code(static_cast<return_code_e>((*_recv_buffer)[i + VSOMEIP_RETURN_CODE_POS]))
+ )) {
+ if ((*_recv_buffer)[i + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) {
+ VSOMEIP_ERROR << "uce: Wrong protocol version: 0x"
+ << std::hex << std::setw(2) << std::setfill('0')
+ << std::uint32_t((*_recv_buffer)[i + VSOMEIP_PROTOCOL_VERSION_POS])
+ << " local: " << get_address_port_local()
+ << " remote: " << get_address_port_remote();
+ // ensure to send back a message w/ wrong protocol version
+ its_host->on_message(&(*_recv_buffer)[i],
+ VSOMEIP_SOMEIP_HEADER_SIZE + 8, this,
+ boost::asio::ip::address(),
+ VSOMEIP_ROUTING_CLIENT,
+ remote_address_,
+ remote_port_);
+ } else if (!utility::is_valid_message_type(static_cast<message_type_e>(
+ (*_recv_buffer)[i + VSOMEIP_MESSAGE_TYPE_POS]))) {
+ VSOMEIP_ERROR << "uce: Invalid message type: 0x"
+ << std::hex << std::setw(2) << std::setfill('0')
+ << std::uint32_t((*_recv_buffer)[i + VSOMEIP_MESSAGE_TYPE_POS])
+ << " local: " << get_address_port_local()
+ << " remote: " << get_address_port_remote();
+ } else if (!utility::is_valid_return_code(static_cast<return_code_e>(
+ (*_recv_buffer)[i + VSOMEIP_RETURN_CODE_POS]))) {
+ VSOMEIP_ERROR << "uce: Invalid return code: 0x"
+ << std::hex << std::setw(2) << std::setfill('0')
+ << std::uint32_t((*_recv_buffer)[i + VSOMEIP_RETURN_CODE_POS])
+ << " local: " << get_address_port_local()
+ << " remote: " << get_address_port_remote();
+ }
+ receive();
+ return;
}
remaining_bytes -= current_message_size;
- its_host->on_message(&recv_buffer_[i], current_message_size,
+ its_host->on_message(&(*_recv_buffer)[i], current_message_size,
this, boost::asio::ip::address(),
VSOMEIP_ROUTING_CLIENT, remote_address_,
remote_port_);
@@ -304,4 +371,12 @@ std::string udp_client_endpoint_impl::get_remote_information() const { + std::to_string(remote_.port());
}
+std::uint32_t udp_client_endpoint_impl::get_max_allowed_reconnects() const {
+ return MAX_RECONNECTS_UNLIMITED;
+}
+
+void udp_client_endpoint_impl::max_allowed_reconnects_reached() {
+ return;
+}
+
} // namespace vsomeip
diff --git a/implementation/endpoints/src/udp_server_endpoint_impl.cpp b/implementation/endpoints/src/udp_server_endpoint_impl.cpp index 6da5b32..6ad7ce8 100644 --- a/implementation/endpoints/src/udp_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/udp_server_endpoint_impl.cpp @@ -8,6 +8,8 @@ #include <boost/asio/ip/multicast.hpp> +#include <vsomeip/constants.hpp> + #include "../include/endpoint_definition.hpp" #include "../include/endpoint_host.hpp" #include "../include/udp_server_endpoint_impl.hpp" @@ -25,7 +27,8 @@ udp_server_endpoint_impl::udp_server_endpoint_impl( std::shared_ptr< endpoint_host > _host, endpoint_type _local, boost::asio::io_service &_io, - configuration::endpoint_queue_limit_t _queue_limit) + configuration::endpoint_queue_limit_t _queue_limit, + std::uint32_t _udp_receive_buffer_size) : server_endpoint_impl<ip::udp_ext>( _host, _local, _io, VSOMEIP_MAX_UDP_MESSAGE_SIZE, _queue_limit), socket_(_io, _local.protocol()), @@ -60,6 +63,27 @@ udp_server_endpoint_impl::udp_server_endpoint_impl( socket_.set_option(option, ec); boost::asio::detail::throw_error(ec, "broadcast option"); + socket_.set_option(boost::asio::socket_base::receive_buffer_size( + _udp_receive_buffer_size), ec); + if (ec) { + VSOMEIP_WARNING << "udp_server_endpoint_impl:: couldn't set " + << "SO_RCVBUF: " << ec.message() << " to: " << std::dec + << _udp_receive_buffer_size << " local port: " << std::dec + << local_port_; + } else { + boost::asio::socket_base::receive_buffer_size its_option; + socket_.get_option(its_option, ec); + if (ec) { + VSOMEIP_WARNING << "udp_server_endpoint_impl: couldn't get " + << "SO_RCVBUF: " << ec.message() << " local port:" + << std::dec << local_port_; + } else { + VSOMEIP_INFO << "udp_server_endpoint_impl: SO_RCVBUF is: " + << std::dec << its_option.value(); + } + } + + #ifdef _WIN32 const char* optval("0001"); ::setsockopt(socket_.native(), IPPROTO_IP, IP_PKTINFO, @@ -167,8 +191,7 @@ bool udp_server_endpoint_impl::is_joined( void udp_server_endpoint_impl::join(const std::string &_address) { bool has_received(false); - std::function<void(const std::string &)> join_func = - [this](const std::string &_address) { + auto join_func = [this](const std::string &_address) { try { bool is_v4(false); bool is_v6(false); @@ -318,6 +341,41 @@ void udp_server_endpoint_impl::receive_cbk( if (remaining_bytes - current_message_size > remaining_bytes) { VSOMEIP_ERROR << "buffer underflow in udp client endpoint ~> abort!"; return; + } else if (current_message_size > VSOMEIP_RETURN_CODE_POS && + (recv_buffer_[i + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION || + !utility::is_valid_message_type(static_cast<message_type_e>(recv_buffer_[i + VSOMEIP_MESSAGE_TYPE_POS])) || + !utility::is_valid_return_code(static_cast<return_code_e>(recv_buffer_[i + VSOMEIP_RETURN_CODE_POS])) + )) { + if (recv_buffer_[i + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) { + VSOMEIP_ERROR << "use: Wrong protocol version: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(recv_buffer_[i + VSOMEIP_PROTOCOL_VERSION_POS]) + << " local: " << get_address_port_local() + << " remote: " << its_remote_address << ":" << std::dec << its_remote_port; + // ensure to send back a message w/ wrong protocol version + its_host->on_message(&recv_buffer_[i], + VSOMEIP_SOMEIP_HEADER_SIZE + 8, this, + _destination, + VSOMEIP_ROUTING_CLIENT, + its_remote_address, + its_remote_port); + } else if (!utility::is_valid_message_type(static_cast<message_type_e>( + recv_buffer_[i + VSOMEIP_MESSAGE_TYPE_POS]))) { + VSOMEIP_ERROR << "use: Invalid message type: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(recv_buffer_[i + VSOMEIP_MESSAGE_TYPE_POS]) + << " local: " << get_address_port_local() + << " remote: " << its_remote_address << ":" << std::dec << its_remote_port; + } else if (!utility::is_valid_return_code(static_cast<return_code_e>( + recv_buffer_[i + VSOMEIP_RETURN_CODE_POS]))) { + VSOMEIP_ERROR << "use: Invalid return code: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(recv_buffer_[i + VSOMEIP_RETURN_CODE_POS]) + << " local: " << get_address_port_local() + << " remote: " << its_remote_address << ":" << std::dec << its_remote_port; + } + receive(); + return; } remaining_bytes -= current_message_size; service_t its_service = VSOMEIP_BYTES_TO_WORD(recv_buffer_[i + VSOMEIP_SERVICE_POS_MIN], @@ -328,14 +386,16 @@ void udp_server_endpoint_impl::receive_cbk( std::memcpy(&its_client, &recv_buffer_[i + VSOMEIP_CLIENT_POS_MIN], sizeof(client_t)); - session_t its_session; - std::memcpy(&its_session, - &recv_buffer_[i + VSOMEIP_SESSION_POS_MIN], - sizeof(session_t)); - clients_mutex_.lock(); - clients_[its_client][its_session] = remote_; - endpoint_to_client_[remote_] = its_client; - clients_mutex_.unlock(); + if (its_client != MAGIC_COOKIE_NETWORK_BYTE_ORDER) { + session_t its_session; + std::memcpy(&its_session, + &recv_buffer_[i + VSOMEIP_SESSION_POS_MIN], + sizeof(session_t)); + clients_mutex_.lock(); + clients_[its_client][its_session] = remote_; + endpoint_to_client_[remote_] = its_client; + clients_mutex_.unlock(); + } } else if (its_service != VSOMEIP_SD_SERVICE && utility::is_notification(recv_buffer_[i + VSOMEIP_MESSAGE_TYPE_POS]) && joined_group_) { @@ -424,4 +484,20 @@ std::string udp_server_endpoint_impl::get_remote_information( + std::to_string(_queue_iterator->first.port()); } +const std::string udp_server_endpoint_impl::get_address_port_local() const { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + std::string its_address_port; + its_address_port.reserve(21); + boost::system::error_code ec; + if (socket_.is_open()) { + endpoint_type its_local_endpoint = socket_.local_endpoint(ec); + if (!ec) { + its_address_port += its_local_endpoint.address().to_string(ec); + its_address_port += ":"; + its_address_port += std::to_string(its_local_endpoint.port()); + } + } + return its_address_port; +} + } // namespace vsomeip diff --git a/implementation/endpoints/src/virtual_server_endpoint_impl.cpp b/implementation/endpoints/src/virtual_server_endpoint_impl.cpp index 30862df..20d40d7 100644 --- a/implementation/endpoints/src/virtual_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/virtual_server_endpoint_impl.cpp @@ -24,10 +24,14 @@ void virtual_server_endpoint_impl::start() { void virtual_server_endpoint_impl::stop() { } -bool virtual_server_endpoint_impl::is_connected() const { +bool virtual_server_endpoint_impl::is_established() const { return false; } +void virtual_server_endpoint_impl::set_established(bool _established) { + (void) _established; +} + void virtual_server_endpoint_impl::set_connected(bool _connected) { (void) _connected; } diff --git a/implementation/message/include/deserializer.hpp b/implementation/message/include/deserializer.hpp index 7449f9b..4c01c79 100644 --- a/implementation/message/include/deserializer.hpp +++ b/implementation/message/include/deserializer.hpp @@ -29,7 +29,7 @@ public: VSOMEIP_EXPORT std::size_t get_available() const;
VSOMEIP_EXPORT std::size_t get_remaining() const;
- VSOMEIP_EXPORT void set_remaining(std::size_t _length);
+ VSOMEIP_EXPORT void set_remaining(std::size_t _remaining);
// to be used by applications to deserialize a message
VSOMEIP_EXPORT message * deserialize_message();
@@ -41,6 +41,7 @@ public: VSOMEIP_EXPORT bool deserialize(uint32_t& _value,
bool _omit_last_byte = false);
VSOMEIP_EXPORT bool deserialize(uint8_t *_data, std::size_t _length);
+ VSOMEIP_EXPORT bool deserialize(std::string& _target, std::size_t _length);
VSOMEIP_EXPORT bool deserialize(std::vector<uint8_t>& _value);
VSOMEIP_EXPORT bool look_ahead(std::size_t _index, uint8_t &_value) const;
diff --git a/implementation/message/include/message_base_impl.hpp b/implementation/message/include/message_base_impl.hpp index ad42261..efd5ffe 100644 --- a/implementation/message/include/message_base_impl.hpp +++ b/implementation/message/include/message_base_impl.hpp @@ -42,10 +42,10 @@ public: VSOMEIP_EXPORT void set_session(session_t _session);
VSOMEIP_EXPORT protocol_version_t get_protocol_version() const;
- VSOMEIP_EXPORT void set_protocol_version(protocol_version_t _version);
+ VSOMEIP_EXPORT void set_protocol_version(protocol_version_t _protocol_version);
VSOMEIP_EXPORT interface_version_t get_interface_version() const;
- VSOMEIP_EXPORT void set_interface_version(interface_version_t _version);
+ VSOMEIP_EXPORT void set_interface_version(interface_version_t _interface_version);
VSOMEIP_EXPORT message_type_e get_message_type() const;
VSOMEIP_EXPORT void set_message_type(message_type_e _type);
diff --git a/implementation/message/include/message_header_impl.hpp b/implementation/message/include/message_header_impl.hpp index 5768bbe..8cd4b00 100644 --- a/implementation/message/include/message_header_impl.hpp +++ b/implementation/message/include/message_header_impl.hpp @@ -18,7 +18,7 @@ class message_base; class message_header_impl: virtual public serializable {
public:
VSOMEIP_EXPORT message_header_impl();
- VSOMEIP_EXPORT message_header_impl(const message_header_impl& header);
+ VSOMEIP_EXPORT message_header_impl(const message_header_impl& _header);
VSOMEIP_EXPORT bool serialize(serializer *_to) const;
VSOMEIP_EXPORT bool deserialize(deserializer *_from);
diff --git a/implementation/message/include/payload_impl.hpp b/implementation/message/include/payload_impl.hpp index f9b05a2..2eb67e9 100644 --- a/implementation/message/include/payload_impl.hpp +++ b/implementation/message/include/payload_impl.hpp @@ -18,7 +18,7 @@ class payload_impl: public payload { public:
VSOMEIP_EXPORT payload_impl();
VSOMEIP_EXPORT payload_impl(const byte_t *_data, uint32_t _size);
- VSOMEIP_EXPORT payload_impl(const std::vector< byte_t > &_value);
+ VSOMEIP_EXPORT payload_impl(const std::vector< byte_t > &_data);
VSOMEIP_EXPORT payload_impl(const payload_impl& _payload);
VSOMEIP_EXPORT virtual ~payload_impl();
diff --git a/implementation/message/src/deserializer.cpp b/implementation/message/src/deserializer.cpp index 8a3c891..b416199 100644 --- a/implementation/message/src/deserializer.cpp +++ b/implementation/message/src/deserializer.cpp @@ -111,6 +111,17 @@ bool deserializer::deserialize(uint8_t *_data, std::size_t _length) { return true;
}
+bool deserializer::deserialize(std::string& _target, std::size_t _length) {
+ if (_length > remaining_ || _length > _target.capacity()) {
+ return false;
+ }
+ _target.assign(position_, position_ + _length);
+ position_ += _length;
+ remaining_ -= _length;
+
+ return true;
+}
+
bool deserializer::deserialize(std::vector< uint8_t >& _value) {
if (_value.capacity() > remaining_)
return false;
diff --git a/implementation/plugin/include/plugin_manager.hpp b/implementation/plugin/include/plugin_manager.hpp index 98afd72..7d2d7f0 100644 --- a/implementation/plugin/include/plugin_manager.hpp +++ b/implementation/plugin/include/plugin_manager.hpp @@ -46,7 +46,7 @@ private: std::map<plugin_type_e, std::map<std::string, std::shared_ptr<plugin> > > plugins_; std::map<plugin_type_e, std::map<std::string, void*> > handles_; - std::mutex plugins_mutex_; + std::recursive_mutex plugins_mutex_; static std::shared_ptr<plugin_manager> the_plugin_manager__; }; diff --git a/implementation/plugin/src/plugin_manager.cpp b/implementation/plugin/src/plugin_manager.cpp index e922fd6..3b9b3f7 100644 --- a/implementation/plugin/src/plugin_manager.cpp +++ b/implementation/plugin/src/plugin_manager.cpp @@ -62,7 +62,7 @@ void plugin_manager::load_plugins() { } } - std::lock_guard<std::mutex> its_lock_start_stop(plugins_mutex_); + std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_); // Load plug-in info from libraries parsed before for (auto plugin_name : plugins) { void* handle = load_library(plugin_name); @@ -105,7 +105,7 @@ void plugin_manager::load_plugins() { } std::shared_ptr<plugin> plugin_manager::get_plugin(plugin_type_e _type, std::string _name) { - std::lock_guard<std::mutex> its_lock_start_stop(plugins_mutex_); + std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_); auto its_type = plugins_.find(_type); if (its_type != plugins_.end()) { auto its_name = its_type->second.find(_name); @@ -142,7 +142,7 @@ std::shared_ptr<plugin> plugin_manager::load_plugin(const std::string _library, } bool plugin_manager::unload_plugin(plugin_type_e _type) { - std::lock_guard<std::mutex> its_lock_start_stop(plugins_mutex_); + std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_); const auto found_handle = handles_.find(_type); if (found_handle != handles_.end()) { for (auto its_name : found_handle->second) { diff --git a/implementation/routing/include/event.hpp b/implementation/routing/include/event.hpp index 674f41b..668bbf4 100644 --- a/implementation/routing/include/event.hpp +++ b/implementation/routing/include/event.hpp @@ -72,7 +72,7 @@ public: void set_change_resets_cycle(bool _change_resets_cycle); // SIP_RPC_358 - void set_update_on_change(bool _is_on); + void set_update_on_change(bool _is_active); // SIP_RPC_359 (epsilon change) void set_epsilon_change_function(const epsilon_change_func_t &_epsilon_change_func); @@ -126,6 +126,9 @@ private: 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(const std::shared_ptr<endpoint_definition> &_target, bool _flush); + void notify_one_unlocked(client_t _client, bool _flush); + private: routing_manager *routing_; mutable std::mutex mutex_; diff --git a/implementation/routing/include/routing_manager.hpp b/implementation/routing/include/routing_manager.hpp index f02c533..9ab09f4 100644 --- a/implementation/routing/include/routing_manager.hpp +++ b/implementation/routing/include/routing_manager.hpp @@ -15,6 +15,7 @@ #include <vsomeip/function_types.hpp> #include <vsomeip/message.hpp> #include <vsomeip/handler.hpp> +#include "types.hpp" namespace vsomeip { @@ -62,7 +63,9 @@ public: bool _flush) = 0; virtual bool send(client_t _client, const byte_t *_data, uint32_t _size, - instance_t _instance, bool _flush, bool _reliable, bool _is_valid_crc = true) = 0; + instance_t _instance, bool _flush, bool _reliable, + client_t _bound_client = VSOMEIP_ROUTING_CLIENT, + bool _is_valid_crc = true, bool _sent_from_remote = false) = 0; virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message>, bool _flush) = 0; @@ -94,7 +97,7 @@ public: virtual void notify_one(service_t _service, instance_t _instance, event_t _event, std::shared_ptr<payload> _payload, - client_t _client, bool _force, bool _flush) = 0; + client_t _client, bool _force, bool _flush, bool _remote_subscriber) = 0; virtual void on_identify_response(client_t _client, service_t _service, instance_t _instance, bool _reliable) = 0; diff --git a/implementation/routing/include/routing_manager_base.hpp b/implementation/routing/include/routing_manager_base.hpp index 7bf3a4d..6bee10c 100644 --- a/implementation/routing/include/routing_manager_base.hpp +++ b/implementation/routing/include/routing_manager_base.hpp @@ -23,18 +23,13 @@ #include "../../configuration/include/configuration.hpp" #include "../../endpoints/include/endpoint_host.hpp" +namespace vsomeip { #ifdef USE_DLT -#include "../../tracing/include/trace_connector.hpp" -#endif - -#ifdef USE_DLT -namespace tc { -class trace_connector; -} // namespace tc +namespace trace { +class connector_impl; +} // namespace trace #endif -namespace vsomeip { - class serializer; class routing_manager_base : public routing_manager, @@ -90,13 +85,15 @@ public: virtual void notify_one(service_t _service, instance_t _instance, event_t _event, std::shared_ptr<payload> _payload, - client_t _client, bool _force, bool _flush); + client_t _client, bool _force, bool _flush, bool _remote_subscriber); virtual bool send(client_t _client, std::shared_ptr<message> _message, bool _flush); virtual bool send(client_t _client, const byte_t *_data, uint32_t _size, - instance_t _instance, bool _flush, bool _reliable, bool _is_valid_crc = true) = 0; + instance_t _instance, bool _flush, bool _reliable, + client_t _bound_client = VSOMEIP_ROUTING_CLIENT, + bool _is_valid_crc = true, bool _sent_from_remote = false) = 0; // Endpoint host ~> will be implemented by routing_manager_impl/_proxy/ virtual void on_connect(std::shared_ptr<endpoint> _endpoint) = 0; @@ -125,6 +122,8 @@ public: virtual void send_get_offered_services_info(client_t _client, offer_type_e _offer_type) = 0; + std::set<client_t> find_local_clients(service_t _service, instance_t _instance); + protected: std::shared_ptr<serviceinfo> find_service(service_t _service, instance_t _instance) const; std::shared_ptr<serviceinfo> create_service_info(service_t _service, @@ -133,14 +132,16 @@ protected: void clear_service_info(service_t _service, instance_t _instance, bool _reliable); services_t get_services() const; + services_t get_services_remote() const; bool is_available(service_t _service, instance_t _instance, major_version_t _major); client_t find_local_client(service_t _service, instance_t _instance); std::shared_ptr<endpoint> create_local(client_t _client); std::shared_ptr<endpoint> find_or_create_local(client_t _client); - void remove_local(client_t _client); + void remove_local(client_t _client, bool _remove_uid); void remove_local(client_t _client, - const std::set<std::tuple<service_t, instance_t, eventgroup_t>>& _subscribed_eventgroups); + const std::set<std::tuple<service_t, instance_t, eventgroup_t>>& _subscribed_eventgroups, + bool _remove_uid); std::shared_ptr<endpoint> find_local(client_t _client); std::shared_ptr<endpoint> find_local(service_t _service, @@ -182,7 +183,7 @@ protected: eventgroup_t _eventgroup, event_t _event); void send_pending_notify_ones(service_t _service, instance_t _instance, - eventgroup_t _eventgroup, client_t _client); + eventgroup_t _eventgroup, client_t _client, bool _remote_subscriber = false); void unset_all_eventpayloads(service_t _service, instance_t _instance); void unset_all_eventpayloads(service_t _service, instance_t _instance, @@ -200,6 +201,23 @@ protected: std::set<std::tuple<service_t, instance_t, eventgroup_t>> get_subscriptions(const client_t _client); + + std::vector<event_t> find_events(service_t _service, instance_t _instance) const; + + bool is_response_allowed(client_t _sender, service_t _service, + instance_t _instance, method_t _method); + bool is_subscribe_to_any_event_allowed(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup); + + void set_incoming_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, subscription_state_e _state); + + subscription_state_e get_incoming_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + + void erase_incoming_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + private: std::shared_ptr<endpoint> create_local_unlocked(client_t _client); std::shared_ptr<endpoint> find_local_unlocked(client_t _client); @@ -224,6 +242,7 @@ protected: std::mutex local_services_mutex_; std::map<service_t, std::map<instance_t, std::tuple< major_version_t, minor_version_t, client_t> > > local_services_; + std::map<service_t, std::map<instance_t, std::set<client_t> > > local_services_history_; // Eventgroups mutable std::mutex eventgroups_mutex_; @@ -236,7 +255,7 @@ protected: std::map<instance_t, std::map<event_t, std::shared_ptr<event> > > > events_; #ifdef USE_DLT - std::shared_ptr<tc::trace_connector> tc_; + std::shared_ptr<trace::connector_impl> tc_; #endif struct subscription_data_t { @@ -263,7 +282,7 @@ protected: std::set<subscription_data_t> pending_subscriptions_; services_t services_remote_; - std::mutex services_remote_mutex_; + mutable std::mutex services_remote_mutex_; private: services_t services_; @@ -276,7 +295,18 @@ private: std::map<instance_t, std::map<eventgroup_t, std::shared_ptr<message> > > > pending_notify_ones_; - std::mutex pending_notify_ones_mutex_; + std::recursive_mutex pending_notify_ones_mutex_; + + std::mutex event_registration_mutex_; + + std::map<client_t, + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::map<event_t, + subscription_state_e> > > > > incoming_subscription_state_; + std::recursive_mutex incoming_subscription_state_mutex_; + }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_impl.hpp b/implementation/routing/include/routing_manager_impl.hpp index 2e90077..40abf73 100644 --- a/implementation/routing/include/routing_manager_impl.hpp +++ b/implementation/routing/include/routing_manager_impl.hpp @@ -84,8 +84,10 @@ public: bool send(client_t _client, std::shared_ptr<message> _message, bool _flush); - bool send(client_t _client, const byte_t *_data, uint32_t _size, - instance_t _instance, bool _flush, bool _reliable, bool _is_valid_crc = true); + virtual bool send(client_t _client, const byte_t *_data, uint32_t _size, + instance_t _instance, bool _flush, bool _reliable, + client_t _bound_client = VSOMEIP_ROUTING_CLIENT, + bool _is_valid_crc = true, bool _sent_from_remote = false); bool send_to(const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message> _message, bool _flush); @@ -115,7 +117,7 @@ public: void notify_one(service_t _service, instance_t _instance, event_t _event, std::shared_ptr<payload> _payload, - client_t _client, bool _force, bool _flush); + client_t _client, bool _force, bool _flush, bool _remote_subscriber); void on_subscribe_nack(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event, @@ -137,7 +139,7 @@ public: return routing_manager_base::find_or_create_local(_client); } - void remove_local(client_t _client); + void remove_local(client_t _client, bool _remove_uid); void on_stop_offer_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor); @@ -159,18 +161,27 @@ public: void on_error(const byte_t *_data, length_t _length, endpoint *_receiver, const boost::asio::ip::address &_remote_address, std::uint16_t _remote_port); - void on_message(const byte_t *_data, length_t _length, endpoint *_receiver, + void on_message(const byte_t *_data, length_t _size, endpoint *_receiver, const boost::asio::ip::address &_destination, client_t _bound_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, bool _is_valid_crc = true); + const byte_t *_data, length_t _size, bool _reliable, + client_t _bound_client, bool _is_valid_crc = true, + bool _is_from_remote = false); void on_notification(client_t _client, service_t _service, instance_t _instance, const byte_t *_data, length_t _size, bool _notify_one); void release_port(uint16_t _port, bool _reliable); + bool offer_service_remotely(service_t _service, instance_t _instance, + std::uint16_t _port, bool _reliable, + bool _magic_cookies_enabled); + bool stop_offer_service_remotely(service_t _service, instance_t _instance, + std::uint16_t _port, bool _reliable, + 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; @@ -210,7 +221,7 @@ public: void expire_subscriptions(const boost::asio::ip::address &_address); void expire_services(const boost::asio::ip::address &_address); - std::chrono::steady_clock::time_point expire_subscriptions(); + std::chrono::steady_clock::time_point expire_subscriptions(bool _force); bool has_identified(client_t _client, service_t _service, instance_t _instance, bool _reliable); @@ -230,11 +241,28 @@ public: eventgroup_t _eventgroup, const std::shared_ptr<endpoint_definition> &_subscriber); + void register_offer_acceptance_handler(offer_acceptance_handler_t _handler) const; + void register_reboot_notification_handler(reboot_notification_handler_t _handler) const; + void register_routing_ready_handler(routing_ready_handler_t _handler); + void register_routing_state_handler(routing_state_handler_t _handler); + void offer_acceptance_enabled(boost::asio::ip::address _address); + + void on_resend_provided_events_response(pending_remote_offer_id_t _id); + bool update_security_policy_configuration(uint32_t _uid, uint32_t _gid, ::std::shared_ptr<policy> _policy, + std::shared_ptr<payload> _payload, security_update_handler_t _handler); + bool remove_security_policy_configuration(uint32_t _uid, uint32_t _gid, security_update_handler_t _handler); + void on_security_update_response(pending_security_update_id_t _id, client_t _client); + std::set<client_t> find_local_clients(service_t _service, instance_t _instance); + bool is_subscribe_to_any_event_allowed(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup); + private: - bool deliver_message(const byte_t *_data, length_t _length, - instance_t _instance, bool _reliable, bool _is_valid_crc = true); + bool deliver_message(const byte_t *_data, length_t _size, + instance_t _instance, bool _reliable, client_t _bound_client, + bool _is_valid_crc = true, bool _is_from_remote = false); bool deliver_notification(service_t _service, instance_t _instance, - const byte_t *_data, length_t _length, bool _reliable, bool _is_valid_crc = true); + const byte_t *_data, length_t _length, bool _reliable, client_t _bound_client, + bool _is_valid_crc = true, bool _is_from_remote = false); instance_t find_instance(service_t _service, endpoint *_endpoint); @@ -273,6 +301,9 @@ private: std::set<eventgroup_t> get_subscribed_eventgroups(service_t _service, instance_t _instance); + + void clear_targets_and_pending_sub_from_eventgroups(service_t _service, instance_t _instance); + void clear_remote_subscriber(service_t _service, instance_t _instance); private: return_code_e check_error(const byte_t *_data, length_t _size, instance_t _instance); @@ -371,7 +402,31 @@ private: service_t _service, instance_t _instance, eventgroup_t _eventgroup, pending_subscription_id_t _pending_unsubscription_id); + void cleanup_server_endpoint(service_t _service, + const std::shared_ptr<endpoint>& _endpoint); + + pending_remote_offer_id_t pending_remote_offer_add(service_t _service, + instance_t _instance); + + std::pair<service_t, instance_t> pending_remote_offer_remove( + pending_remote_offer_id_t _id); + + void on_security_update_timeout( + const boost::system::error_code& _error, + pending_security_update_id_t _id, + std::shared_ptr<boost::asio::steady_timer> _timer); + + pending_security_update_id_t pending_security_update_add( + std::unordered_set<client_t> _clients); + + std::unordered_set<client_t> pending_security_update_get( + pending_security_update_id_t _id); + bool pending_security_update_remove( + pending_security_update_id_t _id, client_t _client); + + bool is_pending_security_update_finished( + pending_security_update_id_t _id); std::shared_ptr<routing_manager_stub> stub_; std::shared_ptr<sd::service_discovery> discovery_; @@ -454,14 +509,34 @@ private: std::map<std::tuple<service_t, instance_t, eventgroup_t, client_t>, subscription_state_e> remote_subscription_state_; - std::map<e2exf::data_identifier, std::shared_ptr<e2e::profile_interface::protector>> custom_protectors; - std::map<e2exf::data_identifier, std::shared_ptr<e2e::profile_interface::checker>> custom_checkers; + std::map<e2exf::data_identifier_t, std::shared_ptr<e2e::profile_interface::protector>> custom_protectors; + std::map<e2exf::data_identifier_t, std::shared_ptr<e2e::profile_interface::checker>> custom_checkers; std::mutex status_log_timer_mutex_; boost::asio::steady_timer status_log_timer_; std::mutex memory_log_timer_mutex_; boost::asio::steady_timer memory_log_timer_; + + routing_ready_handler_t routing_ready_handler_; + routing_state_handler_t routing_state_handler_; + + std::mutex pending_remote_offers_mutex_; + pending_remote_offer_id_t pending_remote_offer_id_; + std::map<pending_remote_offer_id_t, std::pair<service_t, instance_t>> pending_remote_offers_; + + std::mutex last_resume_mutex_; + std::chrono::steady_clock::time_point last_resume_; + + 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_; + + std::recursive_mutex security_update_handlers_mutex_; + std::map<pending_security_update_id_t, security_update_handler_t> security_update_handlers_; + + std::mutex security_update_timers_mutex_; + std::map<pending_security_update_id_t, std::shared_ptr<boost::asio::steady_timer>> security_update_timers_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_proxy.hpp index 94d290c..fbe775d 100644 --- a/implementation/routing/include/routing_manager_proxy.hpp +++ b/implementation/routing/include/routing_manager_proxy.hpp @@ -61,7 +61,9 @@ public: eventgroup_t _eventgroup, event_t _event); bool send(client_t _client, const byte_t *_data, uint32_t _size, - instance_t _instance, bool _flush = true, bool _reliable = false, bool _is_valid_crc= true); + instance_t _instance, bool _flush, bool _reliable, + client_t _bound_client = VSOMEIP_ROUTING_CLIENT, + bool _is_valid_crc = true, bool _sent_from_remote = false); bool send_to(const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message> _message, bool _flush); @@ -82,7 +84,7 @@ public: void on_connect(std::shared_ptr<endpoint> _endpoint); void on_disconnect(std::shared_ptr<endpoint> _endpoint); - void on_message(const byte_t *_data, length_t _length, endpoint *_receiver, + void on_message(const byte_t *_data, length_t _size, endpoint *_receiver, const boost::asio::ip::address &_destination, client_t _bound_client, const boost::asio::ip::address &_remote_address, @@ -119,7 +121,7 @@ private: instance_t _instance); void send_register_event(client_t _client, service_t _service, instance_t _instance, event_t _event, - const std::set<eventgroup_t> &_eventgroup, + const std::set<eventgroup_t> &_eventgroups, bool _is_field, bool _is_provided); void send_subscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, @@ -183,6 +185,13 @@ private: eventgroup_t _eventgroup, pending_subscription_id_t _subscription_id); + void resend_provided_event_registrations(); + void send_resend_provided_event_response(pending_remote_offer_id_t _id); + + 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); + private: enum class inner_state_type_e : std::uint8_t { ST_REGISTERED = 0x0, diff --git a/implementation/routing/include/routing_manager_stub.hpp b/implementation/routing/include/routing_manager_stub.hpp index f97aab5..d586518 100644 --- a/implementation/routing/include/routing_manager_stub.hpp +++ b/implementation/routing/include/routing_manager_stub.hpp @@ -14,6 +14,7 @@ #include <set> #include <thread> #include <atomic> +#include <unordered_set> #include <boost/asio/io_service.hpp> #include <boost/asio/steady_timer.hpp> @@ -43,7 +44,7 @@ public: void on_connect(std::shared_ptr<endpoint> _endpoint); void on_disconnect(std::shared_ptr<endpoint> _endpoint); - void on_message(const byte_t *_data, length_t _length, endpoint *_receiver, + void on_message(const byte_t *_data, length_t _size, endpoint *_receiver, const boost::asio::ip::address &_destination, client_t _bound_client, const boost::asio::ip::address &_remote_address, @@ -82,6 +83,7 @@ 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 send_identify_request_command(std::shared_ptr<vsomeip::endpoint> _target, @@ -95,12 +97,31 @@ public: void update_registration(client_t _client, registration_type_e _type); void print_endpoint_status() const; + + bool send_provided_event_resend_request(client_t _client, + pending_remote_offer_id_t _id); + + bool is_policy_cached(uint32_t _uid); + + void policy_cache_add(uint32_t _uid, std::shared_ptr<payload> _payload); + + void policy_cache_remove(uint32_t _uid); + + bool send_update_security_policy_request(client_t _client, pending_security_update_id_t _update_id, + uint32_t _uid, std::shared_ptr<payload> _payload); + bool send_remove_security_policy_request(client_t _client, pending_security_update_id_t _update_id, + uint32_t _uid, uint32_t _gid); + + bool send_cached_security_policies(client_t _client); + 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 distribute_credentials(client_t _hoster, service_t _service, instance_t _instance); + 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, @@ -138,6 +159,10 @@ private: 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); + void on_client_id_timer_expired(boost::system::error_code const &_error); private: @@ -182,6 +207,12 @@ private: 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 updated_security_policies_mutex_; + std::map<uint32_t, std::shared_ptr<payload>> updated_security_policies_; + }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_stub_host.hpp b/implementation/routing/include/routing_manager_stub_host.hpp index a6d461e..5c474fb 100644 --- a/implementation/routing/include/routing_manager_stub_host.hpp +++ b/implementation/routing/include/routing_manager_stub_host.hpp @@ -61,7 +61,8 @@ public: pending_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, bool _is_valid_crc = true) = 0; + const byte_t *_data, length_t _size, bool _reliable, client_t _bound_client, + bool _is_valid_crc = true, bool _is_from_remote = false) = 0; virtual void on_notification(client_t _client, service_t _service, instance_t _instance, @@ -78,7 +79,7 @@ public: virtual std::shared_ptr<endpoint> find_or_create_local( client_t _client) = 0; - virtual void remove_local(client_t _client) = 0; + virtual void remove_local(client_t _client, bool _remove_local) = 0; virtual boost::asio::io_service & get_io() = 0; virtual client_t get_client() const = 0; @@ -91,6 +92,15 @@ public: virtual void handle_client_error(client_t _client) = 0; virtual void set_routing_state(routing_state_e _routing_state) = 0; + + virtual void on_resend_provided_events_response(pending_remote_offer_id_t _id) = 0; + + virtual void on_security_update_response(pending_security_update_id_t _id, client_t _client) = 0; + + virtual std::set<client_t> find_local_clients(service_t _service, instance_t _instance) = 0; + + virtual bool is_subscribe_to_any_event_allowed(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) = 0; }; } // namespace vsomeip diff --git a/implementation/routing/include/serviceinfo.hpp b/implementation/routing/include/serviceinfo.hpp index 7eab1ec..72be585 100644 --- a/implementation/routing/include/serviceinfo.hpp +++ b/implementation/routing/include/serviceinfo.hpp @@ -24,6 +24,7 @@ class serviceinfo { public: VSOMEIP_EXPORT serviceinfo(major_version_t _major, minor_version_t _minor, ttl_t _ttl, bool _is_local); + VSOMEIP_EXPORT serviceinfo(const serviceinfo& _other); VSOMEIP_EXPORT ~serviceinfo(); VSOMEIP_EXPORT servicegroup * get_group() const; @@ -36,7 +37,7 @@ public: VSOMEIP_EXPORT void set_ttl(ttl_t _ttl); VSOMEIP_EXPORT std::chrono::milliseconds get_precise_ttl() const; - VSOMEIP_EXPORT void set_precise_ttl(std::chrono::milliseconds _ttl); + VSOMEIP_EXPORT void set_precise_ttl(std::chrono::milliseconds _precise_ttl); VSOMEIP_EXPORT std::shared_ptr<endpoint> get_endpoint(bool _reliable) const; VSOMEIP_EXPORT void set_endpoint(std::shared_ptr<endpoint> _endpoint, diff --git a/implementation/routing/include/types.hpp b/implementation/routing/include/types.hpp index f33a944..59acfa3 100644 --- a/implementation/routing/include/types.hpp +++ b/implementation/routing/include/types.hpp @@ -118,6 +118,8 @@ enum remote_subscription_state_e : std::uint8_t { SUBSCRIPTION_ERROR }; +typedef std::uint32_t pending_remote_offer_id_t; + } // namespace vsomeip diff --git a/implementation/routing/src/event.cpp b/implementation/routing/src/event.cpp index 13cd36e..ce78a65 100644 --- a/implementation/routing/src/event.cpp +++ b/implementation/routing/src/event.cpp @@ -138,7 +138,7 @@ void event::set_payload(const std::shared_ptr<payload> &_payload, client_t _clie if (set_payload_helper(_payload, _force)) { reset_payload(_payload); if (is_updating_on_change_) { - notify_one(_client, _flush); + notify_one_unlocked(_client, _flush); } } } else { @@ -155,7 +155,7 @@ void event::set_payload(const std::shared_ptr<payload> &_payload, if (set_payload_helper(_payload, _force)) { reset_payload(_payload); if (is_updating_on_change_) { - notify_one(_target, _flush); + notify_one_unlocked(_target, _flush); } } } else { @@ -244,7 +244,7 @@ void event::update_cbk(boost::system::error_code const &_error) { std::lock_guard<std::mutex> its_lock(mutex_); cycle_timer_.expires_from_now(cycle_); notify(true); - std::function<void(boost::system::error_code const &)> its_handler = + auto its_handler = std::bind(&event::update_cbk, shared_from_this(), std::placeholders::_1); cycle_timer_.async_wait(its_handler); @@ -261,6 +261,11 @@ void event::notify(bool _flush) { } void event::notify_one(const std::shared_ptr<endpoint_definition> &_target, bool _flush) { + std::lock_guard<std::mutex> its_lock(mutex_); + notify_one_unlocked(_target, _flush); +} + +void event::notify_one_unlocked(const std::shared_ptr<endpoint_definition> &_target, bool _flush) { if (is_set_) { routing_->send_to(_target, message_, _flush); } else { @@ -270,6 +275,11 @@ void event::notify_one(const std::shared_ptr<endpoint_definition> &_target, bool } void event::notify_one(client_t _client, bool _flush) { + std::lock_guard<std::mutex> its_lock(mutex_); + notify_one_unlocked(_client, _flush); +} + +void event::notify_one_unlocked(client_t _client, bool _flush) { if (is_set_) { routing_->send(_client, message_, _flush); } else { @@ -421,7 +431,7 @@ void event::set_cache_placeholder(bool _is_cache_place_holder) { void event::start_cycle() { if (std::chrono::milliseconds::zero() != cycle_) { cycle_timer_.expires_from_now(cycle_); - std::function<void(boost::system::error_code const &)> its_handler = + auto its_handler = std::bind(&event::update_cbk, shared_from_this(), std::placeholders::_1); cycle_timer_.async_wait(its_handler); diff --git a/implementation/routing/src/routing_manager_base.cpp b/implementation/routing/src/routing_manager_base.cpp index 62ae6f2..517ccdb 100644 --- a/implementation/routing/src/routing_manager_base.cpp +++ b/implementation/routing/src/routing_manager_base.cpp @@ -13,6 +13,9 @@ #include "../../logging/include/logger.hpp" #include "../../endpoints/include/local_client_endpoint_impl.hpp" #include "../../endpoints/include/local_server_endpoint_impl.hpp" +#ifdef USE_DLT +#include "../../tracing/include/connector_impl.hpp" +#endif namespace vsomeip { @@ -25,7 +28,7 @@ routing_manager_base::routing_manager_base(routing_manager_host *_host) : std::make_shared<serializer>( configuration_->get_buffer_shrink_threshold())) #ifdef USE_DLT - , tc_(tc::trace_connector::get()) + , tc_(trace::connector_impl::get()) #endif { const uint32_t its_buffer_shrink_threshold = @@ -153,6 +156,16 @@ void routing_manager_base::release_service(client_t _client, service_t _service, if (its_info) { its_info->remove_client(_client); } + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + auto found_service = local_services_history_.find(_service); + if (found_service != local_services_history_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + local_services_history_.erase(_service); + } + } + } } void routing_manager_base::register_event(client_t _client, service_t _service, instance_t _instance, @@ -160,6 +173,7 @@ void routing_manager_base::register_event(client_t _client, service_t _service, std::chrono::milliseconds _cycle, bool _change_resets_cycle, epsilon_change_func_t _epsilon_change_func, bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) { + std::lock_guard<std::mutex> its_event_reg_lock(event_registration_mutex_); std::shared_ptr<event> its_event = find_event(_service, _instance, _event); bool transfer_subscriptions_from_any_event(false); if (its_event) { @@ -438,6 +452,83 @@ std::set<std::shared_ptr<event>> routing_manager_base::find_events( return (its_events); } +std::vector<event_t> routing_manager_base::find_events( + service_t _service, instance_t _instance) const { + std::vector<event_t> its_events; + std::lock_guard<std::mutex> its_lock(events_mutex_); + const auto found_service = events_.find(_service); + if (found_service != events_.end()) { + const auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto& e : found_instance->second) { + its_events.push_back(e.first); + } + } + } + return (its_events); +} + +bool routing_manager_base::is_response_allowed(client_t _sender, service_t _service, + instance_t _instance, method_t _method) { + if (!configuration_->is_security_enabled()) { + return true; + } + + if (_sender == find_local_client(_service, _instance)) { + // sender is still offering the service + return true; + } + + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + auto found_service = local_services_history_.find(_service); + if (found_service != local_services_history_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_client = found_instance->second.find(_sender); + if (found_client != found_instance->second.end()) { + // sender was offering the service and is still connected + return true; + } + } + } + + // service is now offered by another client + // or service is not offered at all + std::string security_mode_text = "!"; + if (!configuration_->is_audit_mode_enabled()) { + security_mode_text = ", but will be allowed due to audit mode is active!"; + } + + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_base::is_response_allowed: " + << "received a response from client 0x" << _sender + << " which does not offer service/instance/method " + << _service << "/" << _instance << "/" << _method + << security_mode_text; + + return !configuration_->is_audit_mode_enabled(); +} + +bool routing_manager_base::is_subscribe_to_any_event_allowed(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + bool is_allowed(true); + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + for (auto e : its_eventgroup->get_events()) { + if (!configuration_->is_client_allowed(_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 " + << _service << "/" << _instance << "/" << e->get_event() + << " which violates the security policy!"; + is_allowed = false; + break; + } + } + } + return is_allowed; +} + void routing_manager_base::subscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, event_t _event, @@ -486,13 +577,14 @@ void routing_manager_base::notify(service_t _service, instance_t _instance, void routing_manager_base::notify_one(service_t _service, instance_t _instance, event_t _event, std::shared_ptr<payload> _payload, - client_t _client, bool _force, bool _flush) { + client_t _client, bool _force, bool _flush, bool _remote_subscriber) { std::shared_ptr<event> its_event = find_event(_service, _instance, _event); if (its_event) { // Event is valid for service/instance bool found_eventgroup(false); bool already_subscribed(false); eventgroup_t valid_group = 0; + subscription_state_e its_subscription_state(subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED); // Iterate over all groups of the event to ensure at least // one valid eventgroup for service/instance exists. for (auto its_group : its_event->get_eventgroups()) { @@ -501,10 +593,13 @@ void routing_manager_base::notify_one(service_t _service, instance_t _instance, // Eventgroup is valid for service/instance found_eventgroup = true; valid_group = its_group; + its_subscription_state = get_incoming_subscription_state(_client, _service, + _instance, valid_group, _event); if (find_local(_client)) { already_subscribed = its_event->has_subscriber(its_group, _client); - } else { - // Remotes always needs to be marked as subscribed here + } else if (subscription_state_e::IS_SUBSCRIBING != its_subscription_state + || _remote_subscriber) { + // Remotes always needs to be marked as subscribed here if they are not currently subscribing already_subscribed = true; } break; @@ -514,19 +609,29 @@ void routing_manager_base::notify_one(service_t _service, instance_t _instance, if (already_subscribed) { its_event->set_payload(_payload, _client, _force, _flush); } else { - std::shared_ptr<message> its_notification - = runtime::get()->create_notification(); - its_notification->set_service(_service); - its_notification->set_instance(_instance); - its_notification->set_method(_event); - its_notification->set_payload(_payload); - auto service_info = find_service(_service, _instance); - if (service_info) { - its_notification->set_interface_version(service_info->get_major()); - } - { - std::lock_guard<std::mutex> its_lock(pending_notify_ones_mutex_); - pending_notify_ones_[_service][_instance][valid_group] = its_notification; + // cache notification if subscription is in progress + if (subscription_state_e::IS_SUBSCRIBING == its_subscription_state) { + VSOMEIP_INFO << "routing_manager_base::notify_one(" + << 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') << valid_group << "." + << std::hex << std::setw(4) << std::setfill('0') << _event << "]" + << " insert pending notification!"; + std::shared_ptr<message> its_notification + = runtime::get()->create_notification(); + its_notification->set_service(_service); + its_notification->set_instance(_instance); + its_notification->set_method(_event); + its_notification->set_payload(_payload); + auto service_info = find_service(_service, _instance); + if (service_info) { + its_notification->set_interface_version(service_info->get_major()); + } + { + std::lock_guard<std::recursive_mutex> its_lock(pending_notify_ones_mutex_); + pending_notify_ones_[_service][_instance][valid_group] = its_notification; + } } } } @@ -538,16 +643,23 @@ void routing_manager_base::notify_one(service_t _service, instance_t _instance, } void routing_manager_base::send_pending_notify_ones(service_t _service, instance_t _instance, - eventgroup_t _eventgroup, client_t _client) { - std::lock_guard<std::mutex> its_lock(pending_notify_ones_mutex_); + eventgroup_t _eventgroup, client_t _client, bool _remote_subscriber) { + std::lock_guard<std::recursive_mutex> its_lock(pending_notify_ones_mutex_); auto its_service = pending_notify_ones_.find(_service); if (its_service != pending_notify_ones_.end()) { auto its_instance = its_service->second.find(_instance); if (its_instance != its_service->second.end()) { auto its_group = its_instance->second.find(_eventgroup); if (its_group != its_instance->second.end()) { + VSOMEIP_INFO << "routing_manager_base::send_pending_notify_ones(" + << 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') << _eventgroup << "." + << std::hex << std::setw(4) << std::setfill('0') << its_group->second->get_method() << "]"; + notify_one(_service, _instance, its_group->second->get_method(), - its_group->second->get_payload(), _client, false, true); + its_group->second->get_payload(), _client, false, true, _remote_subscriber); its_instance->second.erase(_eventgroup); } } @@ -623,18 +735,18 @@ void routing_manager_base::notify_one_current_value( } } -bool routing_manager_base::send(client_t its_client, +bool routing_manager_base::send(client_t _client, std::shared_ptr<message> _message, bool _flush) { bool is_sent(false); if (utility::is_request(_message->get_message_type())) { - _message->set_client(its_client); + _message->set_client(_client); } std::lock_guard<std::mutex> its_lock(serialize_mutex_); if (serializer_->serialize(_message.get())) { - is_sent = send(its_client, serializer_->get_data(), + is_sent = send(_client, serializer_->get_data(), serializer_->get_size(), _message->get_instance(), - _flush, _message->is_reliable()); + _flush, _message->is_reliable(), get_client(), true, false); serializer_->reset(); } else { VSOMEIP_ERROR << "Failed to serialize message. Check message size!"; @@ -715,6 +827,11 @@ services_t routing_manager_base::get_services() const { return services_; } +services_t routing_manager_base::get_services_remote() const { + std::lock_guard<std::mutex> its_lock(services_remote_mutex_); + return services_remote_; +} + bool routing_manager_base::is_available(service_t _service, instance_t _instance, major_version_t _major) { bool available(false); @@ -737,6 +854,25 @@ bool routing_manager_base::is_available(service_t _service, instance_t _instance return available; } +std::set<client_t> routing_manager_base::find_local_clients(service_t _service, instance_t _instance) { + std::set<client_t> its_clients; + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + auto its_service = local_services_.find(_service); + if (its_service != local_services_.end()) { + if (_instance == ANY_INSTANCE) { + for (auto its_instance : its_service->second) { + its_clients.insert(std::get<2>(its_instance.second)); + } + } else { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + its_clients.insert(std::get<2>(its_instance->second)); + } + } + } + return its_clients; +} + client_t routing_manager_base::find_local_client(service_t _service, instance_t _instance) { std::lock_guard<std::mutex> its_lock(local_services_mutex_); client_t its_client(VSOMEIP_ROUTING_CLIENT); @@ -814,12 +950,16 @@ std::shared_ptr<endpoint> routing_manager_base::find_or_create_local(client_t _c return (its_endpoint); } -void routing_manager_base::remove_local(client_t _client) { - remove_local(_client, get_subscriptions(_client)); +void routing_manager_base::remove_local(client_t _client, bool _remove_uid) { + remove_local(_client, get_subscriptions(_client), _remove_uid); } void routing_manager_base::remove_local(client_t _client, - const std::set<std::tuple<service_t, instance_t, eventgroup_t>>& _subscribed_eventgroups) { + const std::set<std::tuple<service_t, instance_t, eventgroup_t>>& _subscribed_eventgroups, + bool _remove_uid) { + if (_remove_uid) { + configuration_->remove_client_to_uid_gid_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, false, [](const bool _subscription_accepted){ (void)_subscription_accepted; }); @@ -854,6 +994,25 @@ void routing_manager_base::remove_local(client_t _client, if (local_services_[si.first].size() == 0) local_services_.erase(si.first); } + + // remove disconnected client from offer service history + std::set<std::tuple<service_t, instance_t, client_t>> its_clients; + for (auto& s : local_services_history_) { + for (auto& i : s.second) { + for (auto& c : i.second) { + if (c == _client) { + its_clients.insert(std::make_tuple(s.first, i.first, c)); + } + } + } + } + + 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_.erase(std::get<0>(sic)); + } + } } } @@ -985,7 +1144,7 @@ bool routing_manager_base::send_local_notification(client_t _client, const uint16_t its_data_size = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - tc::trace_header its_header; + trace::header its_header; if (its_header.prepare(nullptr, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); @@ -1202,4 +1361,71 @@ routing_manager_base::get_local_endpoints() { return local_endpoints_; } +void routing_manager_base::set_incoming_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, subscription_state_e _state) { + std::lock_guard<std::recursive_mutex> its_lock(incoming_subscription_state_mutex_); + incoming_subscription_state_[_client][_service][_instance][_eventgroup][_event] = _state; +} + +subscription_state_e routing_manager_base::get_incoming_subscription_state(client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) { + std::lock_guard<std::recursive_mutex> its_lock(incoming_subscription_state_mutex_); + const auto its_client = incoming_subscription_state_.find(_client); + if (its_client != incoming_subscription_state_.end()) { + const auto its_service = its_client->second.find(_service); + if (its_service != its_client->second.end()) { + const auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + const auto its_group = its_instance->second.find(_eventgroup); + if (its_group != its_instance->second.end()) { + const auto its_event = its_group->second.find(_event); + if (its_event != its_group->second.end()) { + return its_event->second; + } + // If a specific event was not found, check if there is a remote subscriber to ANY_EVENT + const auto its_any_event = its_group->second.find(ANY_EVENT); + if (its_any_event != its_group->second.end()) { + return its_any_event->second; + } + } + } + } + } + return subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED; +} + +void routing_manager_base::erase_incoming_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) { + std::lock_guard<std::recursive_mutex> its_lock(incoming_subscription_state_mutex_); + const auto its_client = incoming_subscription_state_.find(_client); + if (its_client != incoming_subscription_state_.end()) { + const auto its_service = its_client->second.find(_service); + if (its_service != its_client->second.end()) { + const auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + const auto its_group = its_instance->second.find(_eventgroup); + if (its_group != its_instance->second.end()) { + const auto its_event = its_group->second.find(_event); + if (its_event != its_group->second.end()) { + its_group->second.erase(_event); + if (its_group->second.empty()) { + its_instance->second.erase(its_group); + if (its_instance->second.empty()) { + its_service->second.erase(its_instance); + if (its_service->second.empty()) { + its_client->second.erase(its_service); + if (its_client->second.empty()) { + incoming_subscription_state_.erase(its_client); + } + } + } + } + } + } + } + } + } +} + } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_impl.cpp b/implementation/routing/src/routing_manager_impl.cpp index faf5282..f8dbd14 100644 --- a/implementation/routing/src/routing_manager_impl.cpp +++ b/implementation/routing/src/routing_manager_impl.cpp @@ -51,6 +51,9 @@ #include "../../utility/include/byteorder.hpp" #include "../../utility/include/utility.hpp" #include "../../plugin/include/plugin_manager.hpp" +#ifdef USE_DLT +#include "../../tracing/include/connector_impl.hpp" +#endif #include "../../e2e_protection/include/buffer/buffer.hpp" #include "../../e2e_protection/include/e2exf/config.hpp" @@ -75,7 +78,10 @@ routing_manager_impl::routing_manager_impl(routing_manager_host *_host) : watchdog_timer_(_host->get_io()), #endif status_log_timer_(_host->get_io()), - memory_log_timer_(_host->get_io()) + memory_log_timer_(_host->get_io()), + pending_remote_offer_id_(0), + last_resume_(std::chrono::steady_clock::now().min()), + pending_security_update_id_(0) { } @@ -90,6 +96,16 @@ client_t routing_manager_impl::get_client() const { return routing_manager_base::get_client(); } +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); +} + +bool routing_manager_impl::is_subscribe_to_any_event_allowed(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + return routing_manager_base::is_subscribe_to_any_event_allowed(_client, + _service, _instance, _eventgroup); +} + void routing_manager_impl::init() { routing_manager_base::init(); @@ -106,7 +122,7 @@ void routing_manager_impl::init() { plugin_type_e::SD_RUNTIME_PLUGIN, VSOMEIP_SD_LIBRARY); if (its_plugin) { VSOMEIP_INFO << "Service Discovery module loaded."; - discovery_ = std::dynamic_pointer_cast<sd::runtime>(its_plugin)->create_service_discovery(this); + discovery_ = std::dynamic_pointer_cast<sd::runtime>(its_plugin)->create_service_discovery(this, configuration_); discovery_->init(); } else { VSOMEIP_ERROR << "Service Discovery module could not be loaded!"; @@ -116,11 +132,11 @@ void routing_manager_impl::init() { if( configuration_->is_e2e_enabled()) { VSOMEIP_INFO << "E2E protection enabled."; - std::map<e2exf::data_identifier, std::shared_ptr<cfg::e2e>> its_e2e_configuration = configuration_->get_e2e_configuration(); + std::map<e2exf::data_identifier_t, std::shared_ptr<cfg::e2e>> its_e2e_configuration = configuration_->get_e2e_configuration(); for (auto &identifier : its_e2e_configuration) { auto its_cfg = identifier.second; if(its_cfg->profile == "CRC8") { - e2exf::data_identifier its_data_identifier = {its_cfg->service_id, its_cfg->event_id}; + e2exf::data_identifier_t its_data_identifier = {its_cfg->service_id, its_cfg->event_id}; e2e::profile01::profile_config its_profile_config = e2e::profile01::profile_config(its_cfg->crc_offset, its_cfg->data_id, (e2e::profile01::p01_data_id_mode) its_cfg->data_id_mode, its_cfg->data_length, its_cfg->counter_offset, its_cfg->data_id_nibble_offset); if ((its_cfg->variant == "protector") || (its_cfg->variant == "both")) { @@ -130,7 +146,7 @@ void routing_manager_impl::init() { custom_checkers[its_data_identifier] = std::make_shared<e2e::profile01::profile_01_checker>(its_profile_config); } } else if(its_cfg->profile == "CRC32") { - e2exf::data_identifier its_data_identifier = {its_cfg->service_id, its_cfg->event_id}; + e2exf::data_identifier_t its_data_identifier = {its_cfg->service_id, its_cfg->event_id}; e2e::profile_custom::profile_config its_profile_config = e2e::profile_custom::profile_config(its_cfg->crc_offset); if ((its_cfg->variant == "protector") || (its_cfg->variant == "both")) { @@ -237,7 +253,7 @@ void routing_manager_impl::stop() { for (auto client: get_connected_clients()) { if (client != VSOMEIP_ROUTING_CLIENT) { - remove_local(client); + remove_local(client, true); } } } @@ -296,22 +312,35 @@ void routing_manager_impl::stop_offer_service(client_t _client, << std::hex << std::setw(4) << std::setfill('0') << _service << "." << std::hex << std::setw(4) << std::setfill('0') << _instance << ":" << std::dec << int(_major) << "." << _minor << "]"; - + bool is_local(false); { - std::lock_guard<std::mutex> its_lock(pending_sd_offers_mutex_); - for (auto it = pending_sd_offers_.begin(); it != pending_sd_offers_.end(); ) { - if (it->first == _service && it->second == _instance) { - it = pending_sd_offers_.erase(it); - break; - } else { - ++it; + std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); + is_local = (its_info && its_info->is_local()); + } + if (is_local) { + { + std::lock_guard<std::mutex> its_lock(pending_sd_offers_mutex_); + for (auto it = pending_sd_offers_.begin(); it != pending_sd_offers_.end(); ) { + if (it->first == _service && it->second == _instance) { + it = pending_sd_offers_.erase(it); + break; + } else { + ++it; + } } } - } - 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); + 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); + } else { + VSOMEIP_WARNING << __func__ << " received STOP_OFFER(" + << 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::dec << int(_major) << "." << _minor << "] " + << "for remote service --> ignore"; + } } void routing_manager_impl::request_service(client_t _client, service_t _service, @@ -435,6 +464,8 @@ void routing_manager_impl::subscribe(client_t _client, service_t _service, << std::dec << (uint16_t)_major << "]"; const client_t its_local_client = find_local_client(_service, _instance); if (get_client() == its_local_client) { + routing_manager_base::set_incoming_subscription_state(_client, _service, _instance, + _eventgroup, _event, subscription_state_e::IS_SUBSCRIBING); auto self = shared_from_this(); host_->on_subscription(_service, _instance, _eventgroup, _client, true, [this, self, _client, _service, _instance, _eventgroup, @@ -452,6 +483,8 @@ void routing_manager_impl::subscribe(client_t _client, service_t _service, } routing_manager_base::subscribe(_client, _service, _instance, _eventgroup, _major, _event, _subscription_type); send_pending_notify_ones(_service, _instance, _eventgroup, _client); + routing_manager_base::erase_incoming_subscription_state(_client, _service, _instance, + _eventgroup, _event); }); } else { if (discovery_) { @@ -581,8 +614,8 @@ bool routing_manager_impl::send(client_t _client, } bool routing_manager_impl::send(client_t _client, const byte_t *_data, - length_t _size, instance_t _instance, - bool _flush, bool _reliable, bool _is_valid_crc) { + length_t _size, instance_t _instance, bool _flush, bool _reliable, + client_t _bound_client, bool _is_valid_crc, bool _sent_from_remote) { bool is_sent(false); if (_size > VSOMEIP_MESSAGE_TYPE_POS) { std::shared_ptr<endpoint> its_target; @@ -616,12 +649,12 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, const uint16_t its_data_size = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - tc::trace_header its_header; + 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); #endif - deliver_message(_data, _size, _instance, _reliable, _is_valid_crc); + deliver_message(_data, _size, _instance, _reliable, _bound_client, _is_valid_crc, _sent_from_remote); return true; } its_target = find_local(_client); @@ -634,7 +667,7 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, const uint16_t its_data_size = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - tc::trace_header its_header; + 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); @@ -648,7 +681,7 @@ 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, _is_valid_crc); + is_sent = deliver_message(_data, _size, _instance, _reliable, _bound_client, _is_valid_crc, _sent_from_remote); } else { e2e_buffer outputBuffer; if( configuration_->is_e2e_enabled()) { @@ -675,7 +708,7 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, const uint16_t its_data_size = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - tc::trace_header its_header; + 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); @@ -754,7 +787,7 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, const uint16_t its_data_size = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - tc::trace_header its_header; + trace::header its_header; if (its_header.prepare(nullptr, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); @@ -786,7 +819,7 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, const uint16_t its_data_size = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - tc::trace_header its_header; + 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); @@ -869,7 +902,7 @@ bool routing_manager_impl::send_to( const uint16_t its_data_size = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - tc::trace_header its_header; + 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); @@ -892,7 +925,7 @@ bool routing_manager_impl::send_to( const uint16_t its_data_size = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - tc::trace_header its_header; + 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); @@ -911,8 +944,10 @@ void routing_manager_impl::register_event( bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) { auto its_event = find_event(_service, _instance, _event); bool is_first(false); - if (its_event && !its_event->has_ref(_client, _is_provided)) { - is_first = true; + if (its_event) { + if (!its_event->has_ref(_client, _is_provided)) { + is_first = true; + } } else { is_first = true; } @@ -950,10 +985,10 @@ void routing_manager_impl::unregister_shadow_event(client_t _client, void routing_manager_impl::notify_one(service_t _service, instance_t _instance, event_t _event, std::shared_ptr<payload> _payload, client_t _client, - bool _force, bool _flush) { + bool _force, bool _flush, bool _remote_subscriber) { if (find_local(_client)) { routing_manager_base::notify_one(_service, _instance, _event, _payload, - _client, _force, _flush); + _client, _force, _flush, _remote_subscriber); } else { std::shared_ptr<event> its_event = find_event(_service, _instance, _event); if (its_event) { @@ -1034,6 +1069,113 @@ void routing_manager_impl::release_port(uint16_t _port, bool _reliable) { used_client_ports_[_reliable].erase(_port); } +bool routing_manager_impl::offer_service_remotely(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled) { + bool ret = true; + + if(!is_available(_service, _instance, ANY_MAJOR)) { + VSOMEIP_ERROR << __func__ << ": Service [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance + << "] is not offered locally! Won't offer it remotely."; + ret = false; + } else { + // update service info in configuration + if (!configuration_->remote_offer_info_add(_service, _instance, _port, + _reliable, _magic_cookies_enabled)) { + ret = false; + } else { + // trigger event registration again to create shadow events + const client_t its_offering_client = find_local_client(_service, _instance); + if (its_offering_client == VSOMEIP_ROUTING_CLIENT) { + VSOMEIP_ERROR << __func__ << " didn't find offering client for service [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance + << "]"; + ret = false; + } else { + if (!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) + << std::setfill('0') << its_offering_client << " providing service [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance + << "]"; + + ret = false; + } + } + } + } + return ret; +} + +bool routing_manager_impl::stop_offer_service_remotely(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled) { + bool ret = true; + bool service_still_offered_remote(false); + // update service configuration + if (!configuration_->remote_offer_info_remove(_service, _instance, _port, + _reliable, _magic_cookies_enabled, &service_still_offered_remote)) { + VSOMEIP_ERROR << __func__ << " couldn't remove remote offer info for service [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance + << "] from configuration"; + ret = false; + } + std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); + std::shared_ptr<endpoint> its_server_endpoint; + if (its_info) { + its_server_endpoint = its_info->get_endpoint(_reliable); + } + // don't deregister events if the service is still offered remotely + if (!service_still_offered_remote) { + const client_t its_offering_client = find_local_client(_service, _instance); + major_version_t its_major(0); + minor_version_t its_minor(0); + if (its_info) { + its_major = its_info->get_major(); + its_minor = its_info->get_minor(); + } + // unset payload and clear subcribers + routing_manager_base::stop_offer_service(its_offering_client, + _service, _instance, its_major, its_minor); + // unregister events + for (const event_t its_event_id : find_events(_service, _instance)) { + unregister_shadow_event(its_offering_client, _service, _instance, + its_event_id, true); + } + clear_targets_and_pending_sub_from_eventgroups(_service, _instance); + clear_remote_subscriber(_service, _instance); + + if (discovery_ && its_info) { + discovery_->stop_offer_service(_service, _instance, its_info); + its_info->set_endpoint(std::shared_ptr<endpoint>(), _reliable); + } + } else { + // service is still partly offered + if (discovery_ && its_info) { + std::shared_ptr<serviceinfo> its_copied_info = + std::make_shared<serviceinfo>(*its_info); + its_info->set_endpoint(std::shared_ptr<endpoint>(), _reliable); + // 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(_service, _instance, its_copied_info); + } + } + + cleanup_server_endpoint(_service, its_server_endpoint); + return ret; +} + 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, @@ -1119,6 +1261,9 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, client_t requester = VSOMEIP_BYTES_TO_WORD( _data[VSOMEIP_CLIENT_POS_MIN], _data[VSOMEIP_CLIENT_POS_MAX]); + its_method = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_METHOD_POS_MIN], + _data[VSOMEIP_METHOD_POS_MAX]); if (!configuration_->is_offered_remote(its_service, its_instance)) { VSOMEIP_WARNING << std::hex << "Security: Received a remote request " << "for service/instance " << its_service << "/" << its_instance @@ -1131,11 +1276,13 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, << " which is already used locally ~> Skip message!"; return; } - if (!configuration_->is_client_allowed(requester, its_service, its_instance)) { - VSOMEIP_WARNING << std::hex << "Security: Received a remote request " - << "from client 0x" << requester << " for service/instance " + if (!configuration_->is_remote_client_allowed()) { + // check if policy allows remote requests. + VSOMEIP_WARNING << "routing_manager_impl::on_message: " + << std::hex << "Security: Remote client with client ID 0x" << requester + << " is not allowed to communicate with service/instance/method " << its_service << "/" << its_instance - << " which violates the security policy ~> Skip message!"; + << "/" << its_method; return; } } @@ -1167,7 +1314,8 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, #ifdef USE_DLT is_forwarded = #endif - on_message(its_service, its_instance, _data, _size, _receiver->is_reliable(), its_is_crc_valid); + on_message(its_service, its_instance, _data, _size, _receiver->is_reliable(), + _bound_client, its_is_crc_valid, true); } } @@ -1177,14 +1325,14 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, const uint16_t its_data_size = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - tc::trace_header its_header; + trace::header its_header; const boost::asio::ip::address_v4 its_remote_address = _remote_address.is_v4() ? _remote_address.to_v4() : boost::asio::ip::address_v4::from_string("6.6.6.6"); - tc::protocol_e its_protocol = - _receiver->is_local() ? tc::protocol_e::local : - _receiver->is_reliable() ? tc::protocol_e::tcp : - tc::protocol_e::udp; + trace::protocol_e its_protocol = + _receiver->is_local() ? trace::protocol_e::local : + _receiver->is_reliable() ? trace::protocol_e::tcp : + 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, @@ -1196,7 +1344,9 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, bool routing_manager_impl::on_message( service_t _service, instance_t _instance, const byte_t *_data, length_t _size, - bool _reliable, bool _is_valid_crc) { + bool _reliable, client_t _bound_client, + bool _is_valid_crc, + bool _is_from_remote) { #if 0 std::stringstream msg; msg << "rmi::on_message(" @@ -1219,11 +1369,13 @@ bool routing_manager_impl::on_message( if (its_client == VSOMEIP_ROUTING_CLIENT && utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { - is_forwarded = deliver_notification(_service, _instance, _data, _size, _reliable, _is_valid_crc); + is_forwarded = deliver_notification(_service, _instance, _data, _size, + _reliable, _bound_client, _is_valid_crc, _is_from_remote); } else if (its_client == host_->get_client()) { - deliver_message(_data, _size, _instance, _reliable, _is_valid_crc); + deliver_message(_data, _size, _instance, + _reliable, _bound_client, _is_valid_crc, _is_from_remote); } else { - send(its_client, _data, _size, _instance, true, _reliable, _is_valid_crc); //send to proxy + send(its_client, _data, _size, _instance, true, _reliable, _bound_client, _is_valid_crc, _is_from_remote); //send to proxy } return is_forwarded; } @@ -1244,7 +1396,7 @@ void routing_manager_impl::on_notification(client_t _client, its_length); if (_notify_one) { - notify_one(_service, _instance, its_event->get_event(), its_payload, _client, true, true); + notify_one(_service, _instance, its_event->get_event(), its_payload, _client, true, true, false); } else { if (its_event->is_field()) { if (its_event->is_set()) { @@ -1311,6 +1463,13 @@ void routing_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) { bool reliable_; std::shared_ptr<endpoint> endpoint_; }; + + // Set to state CONNECTED as connection is not yet fully established in remote side POV + // but endpoint is ready to send / receive. Set to ESTABLISHED after timer expires + // to prevent inserting subscriptions twice or send out subscription before remote side + // is finished with TCP 3 way handshake + _endpoint->set_connected(true); + std::forward_list<struct service_info> services_to_report_; { std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); @@ -1324,7 +1483,7 @@ void routing_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) { if (found_endpoint->second.get() == _endpoint.get()) { std::shared_ptr<serviceinfo> its_info(find_service(its_service.first, its_instance.first)); if (!its_info) { - _endpoint->set_connected(true); + _endpoint->set_established(true); return; } services_to_report_.push_front( @@ -1340,7 +1499,7 @@ void routing_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) { if (found_endpoint->second.get() == _endpoint.get()) { std::shared_ptr<serviceinfo> its_info(find_service(its_service.first, its_instance.first)); if (!its_info) { - _endpoint->set_connected(true); + _endpoint->set_established(true); return; } services_to_report_.push_front( @@ -1356,6 +1515,7 @@ void routing_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) { } } } + for (const auto &s : services_to_report_) { on_availability(s.service_id_, s.instance_id_, true, s.major_, s.minor_); if (s.reliable_) { @@ -1379,7 +1539,7 @@ void routing_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) { } } if (services_to_report_.empty()) { - _endpoint->set_connected(true); + _endpoint->set_established(true); } } @@ -1488,7 +1648,6 @@ void routing_manager_impl::on_stop_offer_service(client_t _client, service_t _se if (discovery_) { if (its_info) { if (its_info->get_major() == _major && its_info->get_minor() == _minor) { - its_info->set_ttl(0); discovery_->stop_offer_service(_service, _instance, its_info); } } @@ -1498,59 +1657,21 @@ void routing_manager_impl::on_stop_offer_service(client_t _client, service_t _se // Cleanup reliable & unreliable server endpoints hold before if (its_info) { - std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); - std::shared_ptr<endpoint> its_empty_endpoint; - bool reliable = true; - - // Loop over reliable/unreliable and cleanup if needed - for (uint8_t i = 0; i < 2; ++i) { - std::shared_ptr<endpoint> its_endpoint; - if (reliable) { - its_endpoint = its_reliable_endpoint; - } else { - its_endpoint = its_unreliable_endpoint; - } - if (!its_endpoint) { - reliable = !reliable; - continue; - } - - // Check whether any service still uses this endpoint - its_endpoint->decrement_use_count(); - bool isLastService = (its_endpoint->get_use_count() == 0); - - // Clear service_instances_ - if (1 >= service_instances_[_service].size()) { - service_instances_.erase(_service); - } else { - service_instances_[_service].erase(its_endpoint.get()); - } - - // Clear server endpoint if no service remains using it - if (isLastService) { - uint16_t port = its_endpoint->get_local_port(); - if (server_endpoints_.find(port) != server_endpoints_.end()) { - server_endpoints_[port].erase(reliable); - if (server_endpoints_[port].find(!reliable) == server_endpoints_[port].end()) { - server_endpoints_.erase(port); - } - } - - // Stop endpoint (close socket) to release its async_handlers! - its_endpoint->stop(); - } - + if (its_unreliable_endpoint) { + cleanup_server_endpoint(_service, its_unreliable_endpoint); // Clear service info and service group - clear_service_info(_service, _instance, reliable); - - // Invert reliable flag and loop again - reliable = !reliable; + clear_service_info(_service, _instance, false); + } + if (its_reliable_endpoint) { + cleanup_server_endpoint(_service, its_reliable_endpoint); + // Clear service info and service group + clear_service_info(_service, _instance, true); } } } bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, - instance_t _instance, bool _reliable, bool _is_valid_crc) { + instance_t _instance, bool _reliable, client_t _bound_client, bool _is_valid_crc, bool _is_from_remote) { bool is_delivered(false); auto a_deserializer = get_deserializer(); @@ -1563,6 +1684,109 @@ 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_is_valid_crc(_is_valid_crc); + + if (!_is_from_remote) { + 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_impl::deliver_message: " + << std::hex << " 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 false; + } else { + if (!configuration_->is_client_allowed(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_impl::deliver_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 false; + } + } + } else if (utility::is_request(its_message->get_message_type())) { + if (configuration_->is_security_enabled() + && its_message->get_client() != _bound_client) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_impl::deliver_message:" + << " 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 false; + } + + if (!configuration_->is_client_allowed(its_message->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_impl::deliver_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 false; + } + } 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_impl::deliver_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 false; + } else { + if (!configuration_->is_client_allowed(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_impl::deliver_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 false; + } + } + } + } else { + if (!configuration_->is_remote_client_allowed()) { + // if the message is from remote, check if + // policy allows remote requests. + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_impl::deliver_message: " + << std::hex << "Remote clients 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 false; + } else if (utility::is_notification(its_message->get_message_type())) { + if (!configuration_->is_client_allowed(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_impl::deliver_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 client" + << " ~> Skip message!"; + return false; + } + } + } + host_->on_message(std::move(its_message)); is_delivered = true; } else { @@ -1575,7 +1799,8 @@ 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, bool _is_valid_crc) { + bool _reliable, client_t _bound_client, + bool _is_valid_crc, bool _is_from_remote) { method_t its_method = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN], _data[VSOMEIP_METHOD_POS_MAX]); @@ -1605,6 +1830,10 @@ bool routing_manager_impl::deliver_notification( } } 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); @@ -1616,7 +1845,7 @@ bool routing_manager_impl::deliver_notification( for (const auto its_local_client : its_event->get_subscribers()) { if (its_local_client == host_->get_client()) { - deliver_message(_data, _length, _instance, _reliable, _is_valid_crc); + deliver_message(_data, _length, _instance, _reliable, _bound_client, _is_valid_crc, _is_from_remote); } else { std::shared_ptr<endpoint> its_local_target = find_local(its_local_client); if (its_local_target) { @@ -1809,9 +2038,12 @@ std::shared_ptr<endpoint> routing_manager_impl::create_client_endpoint( configuration_->get_max_message_size_reliable( _address.to_string(), _remote_port), configuration_->get_buffer_shrink_threshold(), + // send timeout after 2/3 of configured ttl, warning after 1/3 std::chrono::milliseconds(configuration_->get_sd_ttl() * 666), configuration_->get_endpoint_queue_limit( - _address.to_string(), _remote_port)); + _address.to_string(), _remote_port), + configuration_->get_max_tcp_restart_aborts(), + configuration_->get_max_tcp_connect_time()); if (configuration_->has_enabled_magic_cookies(_address.to_string(), _remote_port)) { @@ -1827,7 +2059,8 @@ std::shared_ptr<endpoint> routing_manager_impl::create_client_endpoint( _local_port), boost::asio::ip::udp::endpoint(_address, _remote_port), io_, configuration_->get_endpoint_queue_limit( - _address.to_string(), _remote_port)); + _address.to_string(), _remote_port), + configuration_->get_udp_receive_buffer_size()); } } catch (...) { host_->on_error(error_code_e::CLIENT_ENDPOINT_CREATION_FAILED); @@ -1850,6 +2083,7 @@ std::shared_ptr<endpoint> routing_manager_impl::create_server_endpoint( configuration_->get_max_message_size_reliable( its_unicast.to_string(), _port), configuration_->get_buffer_shrink_threshold(), + // send timeout after 2/3 of configured ttl, warning after 1/3 std::chrono::milliseconds(configuration_->get_sd_ttl() * 666), configuration_->get_endpoint_queue_limit( its_unicast.to_string(), _port)); @@ -1872,7 +2106,8 @@ std::shared_ptr<endpoint> routing_manager_impl::create_server_endpoint( #endif boost::asio::ip::udp::endpoint ep(its_unicast, _port); its_endpoint = std::make_shared<udp_server_endpoint_impl>( - shared_from_this(), ep, io_, its_limit); + shared_from_this(), ep, io_, its_limit, + configuration_->get_udp_receive_buffer_size()); } } else { @@ -1917,7 +2152,7 @@ std::shared_ptr<endpoint> routing_manager_impl::find_or_create_server_endpoint( return (its_endpoint); } -void routing_manager_impl::remove_local(client_t _client) { +void routing_manager_impl::remove_local(client_t _client, bool _remove_uid) { auto clients_subscriptions = get_subscriptions(_client); { std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); @@ -1925,7 +2160,7 @@ void routing_manager_impl::remove_local(client_t _client) { remote_subscription_state_.erase(std::tuple_cat(s, std::make_tuple(_client))); } } - routing_manager_base::remove_local(_client, clients_subscriptions); + routing_manager_base::remove_local(_client, clients_subscriptions, _remove_uid); std::forward_list<std::pair<service_t, instance_t>> services_to_release_; { @@ -2300,7 +2535,7 @@ void routing_manager_impl::add_routing_info( its_info->get_minor()); if (discovery_) { std::shared_ptr<endpoint> ep = its_info->get_endpoint(true); - if (ep && ep->is_connected()) { + if (ep && ep->is_established()) { discovery_->on_endpoint_connected( _service, _instance, ep); @@ -2361,7 +2596,7 @@ void routing_manager_impl::add_routing_info( } if (discovery_) { std::shared_ptr<endpoint> ep = its_info->get_endpoint(false); - if (ep && ep->is_connected()) { + if (ep && ep->is_established()) { discovery_->on_endpoint_connected(_service, _instance, ep); } } @@ -2391,7 +2626,7 @@ void routing_manager_impl::add_routing_info( its_info->get_minor()); if (discovery_) { std::shared_ptr<endpoint> ep = its_info->get_endpoint(false); - if (ep && ep->is_connected()) { + if (ep && ep->is_established()) { discovery_->on_endpoint_connected( _service, _instance, ep); @@ -2417,33 +2652,12 @@ void routing_manager_impl::del_routing_info(service_t _service, instance_t _inst on_availability(_service, _instance, false, its_info->get_major(), its_info->get_minor()); stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, its_info->get_major(), its_info->get_minor()); // Implicit unsubscribe - { - std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); - auto found_service = eventgroups_.find(_service); - if (found_service != eventgroups_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - for (auto &its_eventgroup : found_instance->second) { - its_eventgroup.second->clear_targets(); - its_eventgroup.second->clear_pending_subscriptions(); - } - } - } - } + clear_targets_and_pending_sub_from_eventgroups(_service, _instance); clear_identified_clients( _service, _instance); clear_identifying_clients( _service, _instance); - { - std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_); - auto found_service = remote_subscribers_.find(_service); - if (found_service != remote_subscribers_.end()) { - if (found_service->second.erase(_instance) > 0 && - !found_service->second.size()) { - remote_subscribers_.erase(found_service); - } - } - } + clear_remote_subscriber(_service, _instance); if (_has_reliable) { clear_client_endpoints(_service, _instance, true); @@ -2509,11 +2723,8 @@ void routing_manager_impl::update_routing_info(std::chrono::milliseconds _elapse void routing_manager_impl::expire_services(const boost::asio::ip::address &_address) { std::map<service_t, std::vector<instance_t> > its_expired_offers; - for (auto &s : get_services()) { + for (auto &s : get_services_remote()) { for (auto &i : s.second) { - if (find_local_client(s.first, i.first) != VSOMEIP_ROUTING_CLIENT) { - continue; //don't expire local services - } bool is_gone(false); boost::asio::ip::address its_address; std::shared_ptr<client_endpoint> its_client_endpoint = @@ -2919,7 +3130,14 @@ void routing_manager_impl::on_subscribe_ack(client_t _client, if (specific_endpoint_client) { if (_client == get_client()) { host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/); - host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); + if (_event == ANY_EVENT) { + 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*/); + } } else { stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup, _event); @@ -3068,7 +3286,7 @@ bool routing_manager_impl::deliver_specific_endpoint_message(service_t _service, _receiver->is_reliable(), VSOMEIP_SEND); } } else { - deliver_message(_data, _size, _instance, _receiver->is_reliable()); + deliver_message(_data, _size, _instance, _receiver->is_reliable(), VSOMEIP_ROUTING_CLIENT, true, true); } return true; } @@ -3484,7 +3702,7 @@ void routing_manager_impl::clear_remote_subscriber( } std::chrono::steady_clock::time_point -routing_manager_impl::expire_subscriptions() { +routing_manager_impl::expire_subscriptions(bool _force) { struct subscriptions_info { service_t service_id_; instance_t instance_id_; @@ -3507,10 +3725,14 @@ routing_manager_impl::expire_subscriptions() { for (auto &its_eventgroup : its_instance.second) { std::set<std::shared_ptr<endpoint_definition>> its_expired_endpoints; for (auto &its_target : its_eventgroup.second->get_targets()) { - if (its_target.expiration_ < now) { + if (_force) { its_expired_endpoints.insert(its_target.endpoint_); - } else if (its_target.expiration_ < next_expiration) { - next_expiration = its_target.expiration_; + } else { + if (its_target.expiration_ < now) { + its_expired_endpoints.insert(its_target.endpoint_); + } else if (its_target.expiration_ < next_expiration) { + next_expiration = its_target.expiration_; + } } } @@ -3576,7 +3798,8 @@ routing_manager_impl::expire_subscriptions() { << std::hex << std::setfill('0') << std::setw(4) << s.eventgroup_id_ << "] from " << s.invalid_endpoint_->get_address() << ":" << std::dec << s.invalid_endpoint_->get_port() - << "(" << std::hex << std::setfill('0') << std::setw(4) << s.client_ << ")"; + << "(" << std::hex << std::setfill('0') << std::setw(4) << s.client_ << ") " + << _force; } } return next_expiration; @@ -3593,8 +3816,18 @@ void routing_manager_impl::log_version_timer_cbk(boost::system::error_code const if (discovery_) { is_diag_mode = discovery_->get_diagnosis_mode(); } + std::stringstream its_last_resume; + { + std::lock_guard<std::mutex> its_lock(last_resume_mutex_); + if (last_resume_ != std::chrono::steady_clock::time_point::min()) { + its_last_resume << " | " << std::dec + << std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::steady_clock::now() - last_resume_).count() << "s"; + } + } VSOMEIP_INFO << "vSomeIP " << VSOMEIP_VERSION << " | (" - << ((is_diag_mode == true) ? "diagnosis)" : "default)"); + << ((is_diag_mode == true) ? "diagnosis)" : "default)") + << its_last_resume.str(); { std::lock_guard<std::mutex> its_lock(version_log_timer_mutex_); version_log_timer_.expires_from_now( @@ -3838,6 +4071,8 @@ 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() + << " handles a client error(" << std::hex << _client << ")"; if (stub_) stub_->update_registration(_client, registration_type_e::DEREGISTER_ON_ERROR); @@ -4023,14 +4258,26 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { // stop processing of incoming SD messages discovery_->stop(); + // remove all remote subscriptions to remotely offered services on this node + expire_subscriptions(true); + // 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) { - its_instance.second->set_ttl(0); + if (its_instance.second->get_endpoint(true) || its_instance.second->get_endpoint(false)) { + const client_t its_client(find_local_client(its_service.first, its_instance.first)); + VSOMEIP_WARNING << "service " + << std::hex << std::setw(4) << std::setfill('0') << its_service.first << "." + << 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_service.first, its_instance.first, its_instance.second); } } - + { + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + remote_subscription_state_.clear(); + } // mark all external services as offline services_t its_remote_services; { @@ -4065,6 +4312,10 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { { VSOMEIP_INFO << "Set routing to resume mode, diagnosis mode was " << ((discovery_->get_diagnosis_mode() == true) ? "active." : "inactive."); + { + std::lock_guard<std::mutex> its_lock(last_resume_mutex_); + last_resume_ = std::chrono::steady_clock::now(); + } // Reset relevant in service info for (const auto &its_service : get_offered_services()) { @@ -4076,6 +4327,10 @@ void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { // Switch SD back to normal operation discovery_->set_diagnosis_mode(false); + if (routing_state_handler_) { + routing_state_handler_(_routing_state); + } + // start processing of SD messages (incoming remote offers should lead to new subscribe messages) discovery_->start(); @@ -4098,7 +4353,6 @@ 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)) { - its_instance.second->set_ttl(0); discovery_->stop_offer_service( its_service.first, its_instance.first, its_instance.second); } @@ -4192,6 +4446,9 @@ void routing_manager_impl::on_net_interface_or_route_state_changed( } void routing_manager_impl::start_ip_routing() { + if (routing_ready_handler_) { + routing_ready_handler_(); + } if (discovery_) { discovery_->start(); } else { @@ -4262,6 +4519,62 @@ routing_manager_impl::get_subscribed_eventgroups( return its_eventgroups; } +void routing_manager_impl::clear_targets_and_pending_sub_from_eventgroups( + service_t _service, instance_t _instance) { + std::vector<std::shared_ptr<event>> its_events; + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto &its_eventgroup : found_instance->second) { + // As the service is gone, all subscriptions to its events + // 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(); + for (const auto its_subscriber : its_subscribers) { + if (its_subscriber != get_client()) { + its_event->remove_subscriber( + its_eventgroup.first, its_subscriber); + } + + client_t its_client = is_specific_endpoint_client(its_subscriber, _service, _instance); + { + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + const auto its_tuple = + std::make_tuple(found_service->first, found_instance->first, + its_eventgroup.first, its_client); + remote_subscription_state_.erase(its_tuple); + } + } + its_events.push_back(its_event); + } + its_eventgroup.second->clear_targets(); + its_eventgroup.second->clear_pending_subscriptions(); + } + } + } + } + for (const auto& e : its_events) { + e->unset_payload(true); + } +} + +void routing_manager_impl::clear_remote_subscriber(service_t _service, + instance_t _instance) { + std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_); + auto found_service = remote_subscribers_.find(_service); + if (found_service != remote_subscribers_.end()) { + if (found_service->second.erase(_instance) > 0 && + !found_service->second.size()) { + remote_subscribers_.erase(found_service); + } + } +} + + void routing_manager_impl::call_sd_endpoint_connected( const boost::system::error_code& _error, service_t _service, instance_t _instance, @@ -4271,7 +4584,7 @@ void routing_manager_impl::call_sd_endpoint_connected( if (_error) { return; } - _endpoint->set_connected(true); + _endpoint->set_established(true); if (discovery_) { discovery_->on_endpoint_connected(_service, _instance, _endpoint); @@ -4423,6 +4736,39 @@ void routing_manager_impl::send_initial_events( } } +void routing_manager_impl::register_offer_acceptance_handler( + vsomeip::offer_acceptance_handler_t _handler) const { + if (discovery_) { + discovery_->register_offer_acceptance_handler(_handler); + } +} + +void routing_manager_impl::register_reboot_notification_handler( + vsomeip::reboot_notification_handler_t _handler) const { + if (discovery_) { + discovery_->register_reboot_notification_handler(_handler); + } +} + +void routing_manager_impl::register_routing_ready_handler( + routing_ready_handler_t _handler) { + routing_ready_handler_ = _handler; +} + +void routing_manager_impl::register_routing_state_handler( + routing_state_handler_t _handler) { + routing_state_handler_ = _handler; +} + +void routing_manager_impl::offer_acceptance_enabled( + boost::asio::ip::address _address) { + boost::system::error_code ec; + VSOMEIP_INFO << "ipsec-plugin-mgu: expire subscriptions and services: " + << _address.to_string(ec); + expire_subscriptions(_address); + expire_services(_address); +} + void routing_manager_impl::memory_log_timer_cbk( boost::system::error_code const & _error) { if (_error) { @@ -4707,4 +5053,374 @@ void routing_manager_impl::send_subscription( } } +void routing_manager_impl::cleanup_server_endpoint( + service_t _service, const std::shared_ptr<endpoint>& _endpoint) { + if (_endpoint) { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + bool reliable = _endpoint->is_reliable(); + // Check whether any service still uses this endpoint + _endpoint->decrement_use_count(); + bool isLastService = (_endpoint->get_use_count() == 0); + + // Clear service_instances_ + if (1 >= service_instances_[_service].size()) { + service_instances_.erase(_service); + } else { + service_instances_[_service].erase(_endpoint.get()); + } + + // Clear server endpoint if no service remains using it + if (isLastService) { + const uint16_t port = _endpoint->get_local_port(); + if (server_endpoints_.find(port) != server_endpoints_.end()) { + server_endpoints_[port].erase(reliable); + if (server_endpoints_[port].find(!reliable) == server_endpoints_[port].end()) { + server_endpoints_.erase(port); + } + } + + // Stop endpoint (close socket) to release its async_handlers! + _endpoint->stop(); + } + } +} + +pending_remote_offer_id_t routing_manager_impl::pending_remote_offer_add( + service_t _service, instance_t _instance) { + std::lock_guard<std::mutex> its_lock(pending_remote_offers_mutex_); + if (++pending_remote_offer_id_ == 0) { + pending_remote_offer_id_++; + } + pending_remote_offers_[pending_remote_offer_id_] = std::make_pair(_service, + _instance); + return pending_remote_offer_id_; +} + +std::pair<service_t, instance_t> routing_manager_impl::pending_remote_offer_remove( + pending_remote_offer_id_t _id) { + std::lock_guard<std::mutex> its_lock(pending_remote_offers_mutex_); + std::pair<service_t, instance_t> ret = std::make_pair(ANY_SERVICE, + ANY_INSTANCE); + auto found_si = pending_remote_offers_.find(_id); + if (found_si != pending_remote_offers_.end()) { + ret = found_si->second; + pending_remote_offers_.erase(found_si); + } + return ret; +} + +void routing_manager_impl::on_resend_provided_events_response( + pending_remote_offer_id_t _id) { + const std::pair<service_t, instance_t> its_service = + pending_remote_offer_remove(_id); + if (its_service.first != ANY_SERVICE) { + // create server endpoint + std::shared_ptr<serviceinfo> its_info = find_service(its_service.first, + its_service.second); + if (its_info) { + its_info->set_ttl(DEFAULT_TTL); + init_service_info(its_service.first, its_service.second, true); + } + } +} + +void routing_manager_impl::on_security_update_timeout( + const boost::system::error_code& _error, + pending_security_update_id_t _id, + std::shared_ptr<boost::asio::steady_timer> _timer) { + (void)_timer; + if (_error) { + // timer was cancelled + return; + } + security_update_state_e its_state = security_update_state_e::SU_UNKNOWN_USER_ID; + std::unordered_set<client_t> its_missing_clients = pending_security_update_get(_id); + { + // erase timer + std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_); + security_update_timers_.erase(_id); + } + { + // print missing responses and check if some clients did not respond because they already disconnected + if (!its_missing_clients.empty()) { + for (auto its_client : its_missing_clients) { + VSOMEIP_INFO << __func__ << ": Client 0x" << std::hex << its_client + << " did not respond to the policy update / removal with ID: 0x" << std::hex << _id; + if (!find_local(its_client)) { + VSOMEIP_INFO << __func__ << ": Client 0x" << std::hex << its_client + << " is not connected anymore, do not expect answer for policy update / removal with ID: 0x" + << std::hex << _id; + pending_security_update_remove(_id, its_client); + } + } + } + + its_missing_clients = pending_security_update_get(_id); + if (its_missing_clients.empty()) { + VSOMEIP_INFO << __func__ << ": Received all responses for " + "security update/removal ID: 0x" << std::hex << _id; + its_state = security_update_state_e::SU_SUCCESS; + } + { + // erase pending security update + std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_); + pending_security_updates_.erase(_id); + } + + // call handler with error on timeout or with SUCCESS if missing clients are not connected + std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_); + const auto found_handler = security_update_handlers_.find(_id); + if (found_handler != security_update_handlers_.end()) { + found_handler->second(its_state); + security_update_handlers_.erase(found_handler); + } else { + VSOMEIP_WARNING << __func__ << ": Callback not found for security update / removal with ID: 0x" + << std::hex << _id; + } + } +} + +bool routing_manager_impl::update_security_policy_configuration( + uint32_t _uid, uint32_t _gid, + ::std::shared_ptr<policy> _policy, std::shared_ptr<payload> _payload, security_update_handler_t _handler) { + bool ret(true); + // cache security policy payload for later distribution to new registering clients + stub_->policy_cache_add(_uid, _payload); + + // update security policy from configuration + configuration_->update_security_policy(_uid, _gid, _policy); + + // determine currently connected clients + std::unordered_set<client_t> its_clients_to_inform = get_connected_clients(); + + // add handler + pending_security_update_id_t its_id; + if (!its_clients_to_inform.empty()) { + its_id = pending_security_update_add(its_clients_to_inform); + { + std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_); + security_update_handlers_[its_id] = _handler; + } + + { + std::shared_ptr<boost::asio::steady_timer> its_timer = + std::make_shared<boost::asio::steady_timer>(io_); + boost::system::error_code ec; + its_timer->expires_from_now(std::chrono::milliseconds(3000), ec); + if (!ec) { + its_timer->async_wait( + std::bind( + &routing_manager_impl::on_security_update_timeout, + std::static_pointer_cast<routing_manager_impl>( + shared_from_this()), + std::placeholders::_1, its_id, its_timer)); + } else { + VSOMEIP_ERROR << __func__ << ": timer creation: " << ec.message(); + } + std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_); + security_update_timers_[its_id] = its_timer; + } + + // trigger all currently connected clients to update the security policy + uint32_t sent_counter(0); + uint32_t its_tranche = + uint32_t(its_clients_to_inform.size() >= 10 ? (its_clients_to_inform.size() / 10) : 1); + VSOMEIP_INFO << __func__ << ": Informing [" << std::dec << its_clients_to_inform.size() + << "] currently connected clients about policy update for UID: " + << std::dec << _uid << " with update ID: 0x" << std::hex << its_id; + for (auto its_client : its_clients_to_inform) { + if (!stub_->send_update_security_policy_request(its_client, its_id, _uid, _payload)) { + VSOMEIP_INFO << __func__ << ": Couldn't send update security policy " + << "request to client 0x" << std::hex << std::setw(4) + << std::setfill('0') << its_client << " policy UID: " + << std::hex << std::setw(4) << std::setfill('0') << _uid << " GID: " + << std::hex << std::setw(4) << std::setfill('0') << _gid + << " with update ID: 0x" << std::hex << its_id + << " as client already disconnected"; + // remove client from expected answer list + pending_security_update_remove(its_id, its_client); + } + sent_counter++; + // Prevent burst + if (sent_counter % its_tranche == 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + } else { + // if routing manager has no client call the handler directly + _handler(security_update_state_e::SU_SUCCESS); + } + return ret; +} + +bool routing_manager_impl::remove_security_policy_configuration( + uint32_t _uid, uint32_t _gid, security_update_handler_t _handler) { + bool ret(true); + + // remove security policy from configuration (only if there was a updateACL call before) + if (stub_->is_policy_cached(_uid)) { + if (!configuration_->remove_security_policy(_uid, _gid)) { + _handler(vsomeip::security_update_state_e::SU_UNKNOWN_USER_ID); + ret = false; + } else { + // remove policy from cache to prevent sending it to registering clients + stub_->policy_cache_remove(_uid); + + // add handler + pending_security_update_id_t its_id; + + // determine currently connected clients + std::unordered_set<client_t> its_clients_to_inform = get_connected_clients(); + + if (!its_clients_to_inform.empty()) { + its_id = pending_security_update_add(its_clients_to_inform); + { + std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_); + security_update_handlers_[its_id] = _handler; + } + + { + std::shared_ptr<boost::asio::steady_timer> its_timer = + std::make_shared<boost::asio::steady_timer>(io_); + boost::system::error_code ec; + its_timer->expires_from_now(std::chrono::milliseconds(3000), ec); + if (!ec) { + its_timer->async_wait( + std::bind( + &routing_manager_impl::on_security_update_timeout, + std::static_pointer_cast<routing_manager_impl>( + shared_from_this()), + std::placeholders::_1, its_id, its_timer)); + } else { + VSOMEIP_ERROR << __func__ << ": timer creation: " << ec.message(); + } + std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_); + security_update_timers_[its_id] = its_timer; + } + + // trigger all clients to remove the security policy + uint32_t sent_counter(0); + uint32_t its_tranche = + uint32_t(its_clients_to_inform.size() >= 10 ? (its_clients_to_inform.size() / 10) : 1); + VSOMEIP_INFO << __func__ << ": Informing [" << std::dec << its_clients_to_inform.size() + << "] currently connected clients about policy removal for UID: " + << std::dec << _uid << " with update ID: " << its_id; + for (auto its_client : its_clients_to_inform) { + if (!stub_->send_remove_security_policy_request(its_client, its_id, _uid, _gid)) { + VSOMEIP_INFO << __func__ << ": Couldn't send remove security policy " + << "request to client 0x" << std::hex << std::setw(4) + << std::setfill('0') << its_client << " policy UID: " + << std::hex << std::setw(4) << std::setfill('0') << _uid << " GID: " + << std::hex << std::setw(4) << std::setfill('0') << _gid + << " with update ID: 0x" << std::hex << its_id + << " as client already disconnected"; + // remove client from expected answer list + pending_security_update_remove(its_id, its_client); + } + sent_counter++; + // Prevent burst + if (sent_counter % its_tranche == 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + } else { + // if routing manager has no client call the handler directly + _handler(security_update_state_e::SU_SUCCESS); + } + } + } + else { + _handler(vsomeip::security_update_state_e::SU_UNKNOWN_USER_ID); + ret = false; + } + return ret; +} + +pending_security_update_id_t routing_manager_impl::pending_security_update_add( + std::unordered_set<client_t> _clients) { + std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_); + if (++pending_security_update_id_ == 0) { + pending_security_update_id_++; + } + pending_security_updates_[pending_security_update_id_] = _clients; + return pending_security_update_id_; +} + +std::unordered_set<client_t> routing_manager_impl::pending_security_update_get( + pending_security_update_id_t _id) { + std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_); + std::unordered_set<client_t> its_missing_clients; + auto found_si = pending_security_updates_.find(_id); + if (found_si != pending_security_updates_.end()) { + its_missing_clients = pending_security_updates_[_id]; + } + return its_missing_clients; +} + +bool routing_manager_impl::pending_security_update_remove( + pending_security_update_id_t _id, client_t _client) { + std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_); + auto found_si = pending_security_updates_.find(_id); + if (found_si != pending_security_updates_.end()) { + if (found_si->second.erase(_client)) { + return true; + } + } + return false; +} + +bool routing_manager_impl::is_pending_security_update_finished( + pending_security_update_id_t _id) { + std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_); + bool ret(false); + auto found_si = pending_security_updates_.find(_id); + if (found_si != pending_security_updates_.end()) { + if (!found_si->second.size()) { + ret = true; + } + } + if (ret) { + pending_security_updates_.erase(_id); + } + return ret; +} + +void routing_manager_impl::on_security_update_response( + pending_security_update_id_t _id, client_t _client) { + if (pending_security_update_remove(_id, _client)) { + if (is_pending_security_update_finished(_id)) { + // cancel timeout timer + { + std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_); + auto found_timer = security_update_timers_.find(_id); + if (found_timer != security_update_timers_.end()) { + boost::system::error_code ec; + found_timer->second->cancel(ec); + security_update_timers_.erase(found_timer); + } else { + VSOMEIP_WARNING << __func__ << ": Received all responses " + "for security update/removal ID: 0x" + << std::hex << _id << " but timeout already happened"; + } + } + + // call handler + { + std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_); + auto found_handler = security_update_handlers_.find(_id); + if (found_handler != security_update_handlers_.end()) { + found_handler->second(security_update_state_e::SU_SUCCESS); + security_update_handlers_.erase(found_handler); + VSOMEIP_INFO << __func__ << ": Received all responses for " + "security update/removal ID: 0x" << std::hex << _id; + } else { + VSOMEIP_WARNING << __func__ << ": Received all responses " + "for security update/removal ID: 0x" + << std::hex << _id << " but didn't find handler"; + } + } + } + } +} + } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_proxy.cpp b/implementation/routing/src/routing_manager_proxy.cpp index 8d48b25..d439654 100644 --- a/implementation/routing/src/routing_manager_proxy.cpp +++ b/implementation/routing/src/routing_manager_proxy.cpp @@ -10,12 +10,6 @@ #include <future> #include <forward_list> -#ifndef _WIN32 -// for umask -#include <sys/types.h> -#include <sys/stat.h> -#endif - #include <vsomeip/constants.hpp> #include <vsomeip/runtime.hpp> @@ -32,6 +26,10 @@ #include "../../service_discovery/include/runtime.hpp" #include "../../utility/include/byteorder.hpp" #include "../../utility/include/utility.hpp" +#include "../../configuration/include/policy.hpp" +#ifdef USE_DLT +#include "../../tracing/include/connector_impl.hpp" +#endif namespace vsomeip { @@ -94,8 +92,10 @@ void routing_manager_proxy::stop() { 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, std::chrono::milliseconds(1000)); + 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; @@ -106,7 +106,7 @@ void routing_manager_proxy::stop() { 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, std::chrono::milliseconds(1000)); + 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; @@ -137,7 +137,7 @@ void routing_manager_proxy::stop() { for (auto client: get_connected_clients()) { if (client != VSOMEIP_ROUTING_CLIENT) { - remove_local(client); + remove_local(client, true); } } @@ -437,6 +437,27 @@ void routing_manager_proxy::subscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, event_t _event, subscription_type_e _subscription_type) { { + if (_event == ANY_EVENT) { + if (!is_subscribe_to_any_event_allowed(_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 (!configuration_->is_client_allowed(_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, @@ -617,8 +638,12 @@ bool routing_manager_proxy::send(client_t _client, const byte_t *_data, length_t _size, instance_t _instance, bool _flush, bool _reliable, - bool _is_valid_crc) { + client_t _bound_client, + bool _is_valid_crc, + bool _sent_from_remote) { (void)_client; + (void)_bound_client; + (void)_sent_from_remote; bool is_sent(false); bool has_remote_subscribers(false); { @@ -697,7 +722,7 @@ bool routing_manager_proxy::send(client_t _client, const byte_t *_data, const uint16_t its_data_size = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - tc::trace_header its_header; + trace::header its_header; if (its_header.prepare(nullptr, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); @@ -741,7 +766,7 @@ bool routing_manager_proxy::send(client_t _client, const byte_t *_data, const uint16_t its_data_size = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); - tc::trace_header its_header; + trace::header its_header; if (its_header.prepare(nullptr, true, _instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, _data, its_data_size); @@ -780,6 +805,7 @@ bool routing_manager_proxy::send_to( void routing_manager_proxy::on_connect(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_) { @@ -864,7 +890,16 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, std::memcpy(&its_length, &_data[VSOMEIP_COMMAND_SIZE_POS_MIN], sizeof(its_length)); - if (configuration_->is_security_enabled() && _bound_client != routing_host_id && + bool message_from_routing(false); + if (configuration_->is_security_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 (configuration_->is_security_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 @@ -877,20 +912,34 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, 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; - bool its_is_vslid_crc; + bool its_is_valid_crc; 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_is_vslid_crc, &_data[VSOMEIP_SEND_COMMAND_VALID_CRC_POS], - sizeof(its_is_vslid_crc)); + std::memcpy(&its_is_valid_crc, &_data[VSOMEIP_SEND_COMMAND_VALID_CRC_POS], + sizeof(its_is_valid_crc)); // 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); @@ -901,36 +950,110 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, if (its_message) { its_message->set_instance(its_instance); its_message->set_reliable(its_reliable); - its_message->set_is_valid_crc(its_is_vslid_crc); - if (utility::is_notification(its_message->get_message_type())) { - if (!configuration_->is_client_allowed(get_client(), its_message->get_service(), - its_message->get_instance())) { - VSOMEIP_WARNING << std::hex << "Security: Client 0x" << get_client() - << " isn't allow receive a notification from to service/instance " - << its_message->get_service() << "/" << its_message->get_instance() - << " respectively from client 0x" << its_client - << " : Skip message!"; - return; - } - cache_event_payload(its_message); - } else if (utility::is_request(its_message->get_message_type())) { - if (!configuration_->is_client_allowed(its_message->get_client(), - its_message->get_service(), its_message->get_instance())) { - VSOMEIP_WARNING << std::hex << "Security: Client 0x" << its_message->get_client() - << " isn't allow to send a request to service/instance " - << its_message->get_service() << "/" << its_message->get_instance() - << " : Skip message!"; - return; + its_message->set_is_valid_crc(its_is_valid_crc); + 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 (!configuration_->is_client_allowed(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 (configuration_->is_security_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 (!configuration_->is_client_allowed(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 (!configuration_->is_client_allowed(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 { // response - if (!configuration_->is_client_allowed(get_client(), its_message->get_service(), - its_message->get_instance())) { - VSOMEIP_WARNING << std::hex << "Security: Client 0x" << get_client() - << " isn't allow receive a response from to service/instance " + } else { + if (!configuration_->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() - << " respectively from client 0x" << its_client - << " : Skip message!"; + << "/" << 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 (!configuration_->is_client_allowed(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; + } } } #ifdef USE_DLT @@ -938,10 +1061,10 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, && (client_side_logging_filter_.empty() || (1 == client_side_logging_filter_.count(std::make_tuple(its_message->get_service(), ANY_INSTANCE))) || (1 == client_side_logging_filter_.count(std::make_tuple(its_message->get_service(), its_message->get_instance()))))) { - tc::trace_header its_header; + trace::header its_header; if (its_header.prepare(nullptr, false, its_instance)) tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, - &_data[VSOMEIP_COMMAND_PAYLOAD_POS], + &_data[VSOMEIP_SEND_COMMAND_PAYLOAD_POS], static_cast<std::uint16_t>(its_message_size)); } #endif @@ -950,20 +1073,29 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, VSOMEIP_ERROR << "Routing proxy: on_message: " << "SomeIP-Header deserialization failed!"; } - } break; + } case VSOMEIP_ROUTING_INFO: - if (!configuration_->is_security_enabled() ||_bound_client == routing_host_id) { + if (_size - VSOMEIP_COMMAND_HEADER_SIZE != its_length) { + VSOMEIP_WARNING << "Received a ROUTING_INFO command with invalid size -> skip!"; + break; + } + if (!configuration_->is_security_enabled() || message_from_routing) { on_routing_info(&_data[VSOMEIP_COMMAND_PAYLOAD_POS], its_length); } else { - VSOMEIP_WARNING << std::hex << "Security: Client 0x" << get_client() + 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_ << ")"; @@ -990,6 +1122,8 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, std::unique_lock<std::recursive_mutex> its_lock(incoming_subscriptions_mutex_); if (its_subscription_id != DEFAULT_SUBSCRIPTION) { its_lock.unlock(); + routing_manager_base::set_incoming_subscription_state(its_client, its_service, + its_instance, its_eventgroup, its_event, subscription_state_e::IS_SUBSCRIBING); // Remote subscriber: Notify routing manager initially + count subscribes auto self = shared_from_this(); host_->on_subscription(its_service, its_instance, its_eventgroup, @@ -1011,6 +1145,8 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, notify_remote_initially(its_service, its_instance, its_eventgroup, its_already_subscribed_events); } + send_pending_notify_ones(its_service, its_instance, its_eventgroup, its_client, true); + std::uint32_t its_count = get_remote_subscriber_count( its_service, its_instance, its_eventgroup, true); VSOMEIP_INFO << "SUBSCRIBE(" @@ -1022,19 +1158,51 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, << std::dec << (uint16_t)its_major << "]" << (bool)(its_subscription_id != DEFAULT_SUBSCRIPTION) << " " << std::dec << its_count; + + routing_manager_base::erase_incoming_subscription_state(its_client, its_service, + its_instance, its_eventgroup, its_event); }); } else if (is_client_known(its_client)) { its_lock.unlock(); - if (!configuration_->is_client_allowed(its_client, - its_service, its_instance)) { - VSOMEIP_WARNING << "Security: Client " << std::hex - << its_client << " subscribes to service/instance " - << its_service << "/" << its_instance - << " which violates the security policy ~> Skip subscribe!"; - return; + if (!message_from_routing) { + if (its_event == ANY_EVENT) { + if (!is_subscribe_to_any_event_allowed(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 (!configuration_->is_client_allowed(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 (!configuration_->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 + routing_manager_base::set_incoming_subscription_state(its_client, its_service, + its_instance, its_eventgroup, its_event, subscription_state_e::IS_SUBSCRIBING); (void) find_or_create_local(its_client); auto self = shared_from_this(); host_->on_subscription(its_service, its_instance, @@ -1053,6 +1221,8 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, subscription_type_e::SU_RELIABLE_AND_UNRELIABLE); send_pending_notify_ones(its_service, its_instance, its_eventgroup, its_client); } + routing_manager_base::erase_incoming_subscription_state(its_client, its_service, + its_instance, its_eventgroup, its_event); }); } else { // Local & not yet known subscriber ~> set pending until subscriber gets known! @@ -1182,7 +1352,11 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, break; case VSOMEIP_OFFERED_SERVICES_RESPONSE: - if (!configuration_->is_security_enabled() ||_bound_client == routing_host_id) { + if (_size - VSOMEIP_COMMAND_HEADER_SIZE != its_length) { + VSOMEIP_WARNING << "Received a VSOMEIP_OFFERED_SERVICES_RESPONSE command with invalid size -> skip!"; + break; + } + if (!configuration_->is_security_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() @@ -1190,7 +1364,148 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, << " : 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: { + 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 (!configuration_->is_security_enabled() || message_from_routing) { + pending_security_update_id_t its_update_id(0); + uint32_t its_uid(0); + uint32_t its_gid(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* buffer_ptr = _data + (VSOMEIP_COMMAND_PAYLOAD_POS + + sizeof(pending_security_update_id_t)); + uint32_t its_size = uint32_t(_size - (VSOMEIP_COMMAND_PAYLOAD_POS + + sizeof(pending_security_update_id_t))); + utility::parse_policy(buffer_ptr, its_size, its_uid, its_gid, its_policy); + + if (configuration_->is_policy_update_allowed(its_uid, its_policy)) { + configuration_->update_security_policy(its_uid, its_gid, its_policy); + send_update_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 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 (!configuration_->is_security_enabled() || message_from_routing) { + pending_security_update_id_t its_update_id(0); + uint32_t its_uid(0xffffffff); + uint32_t its_gid(0xffffffff); + + 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 (configuration_->is_policy_removal_allowed(its_uid)) { + configuration_->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 (!configuration_->is_security_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 (utility::parse_policy(buffer_ptr, its_policy_size, its_uid, its_gid, its_policy)) { + if (configuration_->is_policy_update_allowed(its_uid, its_policy)) { + configuration_->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 (!configuration_->is_security_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; + } default: break; } @@ -1237,6 +1552,17 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, VSOMEIP_INFO << std::hex << "Application/Client " << get_client() << " is registered."; +#ifndef _WIN32 + if (!check_credentials(get_client(), getuid(), getgid())) { + 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 + // inform host about its own registration state changes host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_REGISTERED)); @@ -1257,6 +1583,7 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, known_clients_.erase(its_client); } if (its_client == get_client()) { + configuration_->remove_client_to_uid_gid_mapping(its_client); VSOMEIP_INFO << std::hex << "Application/Client " << get_client() << " is deregistered."; @@ -1270,7 +1597,7 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, state_condition_.notify_one(); } } else if (its_client != VSOMEIP_ROUTING_CLIENT) { - remove_local(its_client); + remove_local(its_client, true); } } @@ -1325,6 +1652,8 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, 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); } @@ -1374,6 +1703,8 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, } } for (const subscription_info &si : subscription_actions) { + 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); (void) find_or_create_local(si.client_id_); auto self = shared_from_this(); host_->on_subscription( @@ -1393,6 +1724,8 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, send_pending_notify_ones(si.service_id_, si.instance_id_, si.eventgroup_id_, si.client_id_); } + routing_manager_base::erase_incoming_subscription_state(si.client_id_, si.service_id_, + si.instance_id_, si.eventgroup_id_, si.event_); { std::lock_guard<std::recursive_mutex> its_lock2(incoming_subscriptions_mutex_); pending_incoming_subscripitons_.erase(si.client_id_); @@ -1469,12 +1802,26 @@ void routing_manager_proxy::reconnect(const std::unordered_set<client_t> &_clien // Remove all local connections/endpoints for (const auto its_client : _clients) { if (its_client != VSOMEIP_ROUTING_CLIENT) { - remove_local(its_client); + remove_local(its_client, true); } } VSOMEIP_INFO << std::hex << "Application/Client " << get_client() <<": Reconnecting to routing manager."; + +#ifndef _WIN32 + if (!check_credentials(get_client(), getuid(), getgid())) { + 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(); @@ -1509,14 +1856,10 @@ void routing_manager_proxy::register_application() { } void routing_manager_proxy::deregister_application() { - uint32_t its_size = sizeof(client_); - - std::vector<byte_t> its_command(VSOMEIP_COMMAND_HEADER_SIZE + its_size); + 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_)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); if (is_connected_) { std::lock_guard<std::mutex> its_lock(sender_mutex_); @@ -1558,7 +1901,7 @@ void routing_manager_proxy::send_request_services(std::set<service_data_t>& _req 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)); + sizeof(std::uint32_t)); uint32_t entry_size = (sizeof(service_t) + sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t) + sizeof(bool)); @@ -1788,17 +2131,13 @@ void routing_manager_proxy::init_receiver() { ::_unlink(its_client.str().c_str()); int port = VSOMEIP_INTERNAL_BASE_PORT + client_; #else - if (!check_credentials(get_client(), getuid(), getgid())) { - VSOMEIP_ERROR << "routing_manager_proxy::init_receiver: " - << std::hex << "Client " << get_client() << " isn't allow" - << " to create a server endpoint due to credential check failed!"; - return; - } + configuration_->store_client_to_uid_gid_mapping(get_client(), getuid(), getgid()); + configuration_->store_uid_gid_to_client_mapping(getuid(), getgid(), get_client()); + if (-1 == ::unlink(its_client.str().c_str()) && errno != ENOENT) { VSOMEIP_ERROR << "routing_manager_proxy::init_receiver unlink failed (" << its_client.str() << "): "<< std::strerror(errno); } - const mode_t previous_mask(::umask(static_cast<mode_t>(configuration_->get_umask()))); #endif try { receiver_ = std::make_shared<local_server_endpoint_impl>(shared_from_this(), @@ -1809,7 +2148,8 @@ void routing_manager_proxy::init_receiver() { #endif io_, configuration_->get_max_message_size_local(), configuration_->get_buffer_shrink_threshold(), - configuration_->get_endpoint_queue_limit_local()); + configuration_->get_endpoint_queue_limit_local(), + configuration_->get_permissions_uds()); #ifdef _WIN32 VSOMEIP_INFO << "Listening at " << port; #else @@ -1819,9 +2159,6 @@ void routing_manager_proxy::init_receiver() { host_->on_error(error_code_e::SERVER_ENDPOINT_CREATION_FAILED); VSOMEIP_ERROR << "Client ID: " << std::hex << client_ << ": " << e.what(); } -#ifndef _WIN32 - ::umask(previous_mask); -#endif } void routing_manager_proxy::notify_remote_initially(service_t _service, instance_t _instance, @@ -2008,7 +2345,7 @@ 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); + remove_local(_client, true); } else { bool should_reconnect(true); { @@ -2077,4 +2414,99 @@ void routing_manager_proxy::send_unsubscribe_ack( } } +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.event_, ed.eventgroups_, + ed.is_field_, 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) { + uint32_t i = 0; + while ( (i + sizeof(uint32_t) + sizeof(uint32_t)) <= _size) { + std::shared_ptr<policy> its_policy(std::make_shared<policy>()); + ranges_t its_uid_ranges, its_gid_ranges; + 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_uid_ranges.insert(std::make_pair(its_uid, its_uid)); + its_gid_ranges.insert(std::make_pair(its_gid, its_gid)); + + its_policy->allow_who_ = true; + its_policy->ids_.insert(std::make_pair(its_uid_ranges, its_gid_ranges)); + configuration_->add_security_credentials(its_uid, its_gid, its_policy, get_client()); + } +} + } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_stub.cpp b/implementation/routing/src/routing_manager_stub.cpp index 528c729..5c19af9 100644 --- a/implementation/routing/src/routing_manager_stub.cpp +++ b/implementation/routing/src/routing_manager_stub.cpp @@ -8,12 +8,6 @@ #include <iomanip> #include <forward_list> -#ifndef _WIN32 -// for umask -#include <sys/types.h> -#include <sys/stat.h> -#endif - #include <boost/system/error_code.hpp> #include <vsomeip/constants.hpp> @@ -34,6 +28,7 @@ #include "../../logging/include/logger.hpp" #include "../../utility/include/byteorder.hpp" #include "../../utility/include/utility.hpp" +#include "../implementation/message/include/payload_impl.hpp" namespace vsomeip { @@ -162,6 +157,7 @@ const std::shared_ptr<configuration> routing_manager_stub::get_configuration() c void routing_manager_stub::on_connect(std::shared_ptr<endpoint> _endpoint) { _endpoint->set_connected(true); + _endpoint->set_established(true); } void routing_manager_stub::on_disconnect(std::shared_ptr<endpoint> _endpoint) { @@ -211,6 +207,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, std::string its_client_endpoint; service_t its_service; instance_t its_instance; + method_t its_method; eventgroup_t its_eventgroup; std::set<eventgroup_t> its_eventgroups; event_t its_event; @@ -235,10 +232,11 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, sizeof(its_client)); if (configuration_->is_security_enabled() && _bound_client != its_client) { - VSOMEIP_WARNING << "Security: Routing Manager received a message from 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 " + << 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; @@ -250,14 +248,26 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, if (its_size <= _size - VSOMEIP_COMMAND_HEADER_SIZE) { switch (its_command) { case VSOMEIP_REGISTER_APPLICATION: + 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; 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; case VSOMEIP_PONG: + if (_size != VSOMEIP_PONG_COMMAND_SIZE) { + VSOMEIP_WARNING << "Received a PONG command with wrong size ~> skip!"; + break; + } on_pong(its_client); VSOMEIP_TRACE << "PONG(" << std::hex << std::setw(4) << std::setfill('0') << its_client << ")"; @@ -277,8 +287,16 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, sizeof(its_major)); std::memcpy(&its_minor, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 5], sizeof(its_minor)); - host_->offer_service(its_client, its_service, its_instance, - its_major, its_minor); + + if (configuration_->is_offer_allowed(its_client, its_service, its_instance)) { + host_->offer_service(its_client, its_service, its_instance, + its_major, its_minor); + } else { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_stub::on_message: isn't allowed to offer " + << "the following service/instance " << its_service << "/" << its_instance + << " ~> Skip offer!"; + } break; case VSOMEIP_STOP_OFFER_SERVICE: @@ -317,15 +335,30 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, sizeof(its_event)); std::memcpy(&its_subscription_type, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 9], sizeof(its_subscription_type)); - if (configuration_->is_client_allowed(its_client, - its_service, its_instance)) { - host_->subscribe(its_client, its_service, its_instance, - its_eventgroup, its_major, its_event, its_subscription_type); + + if (its_event == ANY_EVENT) { + if (host_->is_subscribe_to_any_event_allowed(its_client, its_service, its_instance, its_eventgroup)) { + host_->subscribe(its_client, its_service, its_instance, + its_eventgroup, its_major, its_event, its_subscription_type); + } else { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_stub::on_message: " + << " subscribes to service/instance/event " + << its_service << "/" << its_instance << "/ANY_EVENT" + << " which violates the security policy ~> Skip subscribe!"; + } } else { - VSOMEIP_WARNING << "Security: Client " << std::hex - << its_client << " subscribes to service/instance " - << its_service << "/" << its_instance - << " which violates the security policy ~> Skip subscribe!"; + if (configuration_->is_client_allowed(its_client, + its_service, its_instance, its_event)) { + host_->subscribe(its_client, its_service, its_instance, + its_eventgroup, its_major, its_event, its_subscription_type); + } else { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_stub::on_message: " + << " subscribes to service/instance/event " + << its_service << "/" << its_instance << "/" << its_event + << " which violates the security policy ~> Skip subscribe!"; + } } break; @@ -422,6 +455,10 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, << 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], @@ -429,6 +466,9 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, 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], @@ -436,34 +476,40 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, std::memcpy(&its_is_valid_crc, &_data[VSOMEIP_SEND_COMMAND_VALID_CRC_POS], sizeof(its_is_valid_crc)); + // 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 (!configuration_->is_client_allowed(its_client_from_header, - its_service, its_instance)) { - VSOMEIP_WARNING << std::hex << "Security: Client 0x" << its_client_from_header - << " isn't allow to send a request to service/instance " - << its_service << "/" << its_instance - << " : Skip message!"; - return; - } - } else { - if (!configuration_->is_client_allowed(get_client(), its_service, - its_instance)) { - VSOMEIP_WARNING << std::hex << "Security: Client 0x" - << get_client() - << " isn't allow receive a response from to service/instance " - << its_service << "/" << its_instance - << " respectively from client 0x" << its_client - << " : Skip message!"; + 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); - host_->on_message(its_service, its_instance, its_data, its_message_size, its_reliable, its_is_valid_crc); + 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, its_is_valid_crc, 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], @@ -473,10 +519,23 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, // 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], @@ -488,6 +547,15 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, // 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; @@ -496,6 +564,10 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, { uint32_t entry_size = (sizeof(service_t) + sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t) + sizeof(bool)); + 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) { @@ -515,19 +587,23 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, sizeof(its_minor)); std::memcpy(&use_exclusive_proxy, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 9 + (i * entry_size)], sizeof(use_exclusive_proxy)); - if (configuration_->is_client_allowed(its_client, its_service, its_instance)) { + if (configuration_->is_client_allowed(its_client, its_service, its_instance, 0x00, true)) { host_->request_service(its_client, its_service, its_instance, its_major, its_minor, use_exclusive_proxy); service_data_t request = { its_service, its_instance, its_major, its_minor, use_exclusive_proxy }; requests.insert(request); } else { - VSOMEIP_WARNING << "Security: Client " << std::hex - << its_client << " requests service/instance " + 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!"; } } + if (configuration_->is_security_enabled()) { + handle_credentials(its_client, requests); + } handle_requests(its_client, requests); break; } @@ -640,10 +716,14 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, 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: + 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; @@ -694,6 +774,46 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, } 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)); + + host_->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)); + + host_->on_security_update_response(its_pending_security_update_id ,its_client); + break; + } } } } @@ -778,6 +898,10 @@ void routing_manager_stub::client_registration_func(void) { routing_info_entry_e::RIE_ADD_CLIENT : routing_info_entry_e::RIE_DEL_CLIENT, r.first); + // distribute updated security config to new clients + if (b == registration_type_e::REGISTER) { + send_cached_security_policies(r.first); + } send_client_routing_info(r.first); } if (b != registration_type_e::REGISTER) { @@ -802,7 +926,9 @@ void routing_manager_stub::client_registration_func(void) { } service_requests_.erase(r.first); } - host_->remove_local(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); if (b == registration_type_e::DEREGISTER_ON_ERROR) { utility::release_client_id(r.first); } @@ -819,8 +945,7 @@ void routing_manager_stub::init_routing_endpoint() { endpoint_path_ = its_endpoint_path.str(); client_t routing_host_id = configuration_->get_id(configuration_->get_routing_host()); if (configuration_->is_security_enabled() && get_client() != routing_host_id) { - VSOMEIP_ERROR << "routing_manager_stub::init_routing_endpoint: " - << std::hex << "Client " << get_client() << " isn't allow" + VSOMEIP_ERROR << __func__ << std::hex << " Client " << get_client() << " isn't allowed" << " to create the routing endpoint due to its not configured as the routing master!"; return; } @@ -840,7 +965,9 @@ void routing_manager_stub::init_routing_endpoint() { > (shared_from_this(), boost::asio::local::stream_protocol::endpoint(endpoint_path_), io_, configuration_->get_max_message_size_local(), native_socket_fd, - configuration_->get_buffer_shrink_threshold()); + configuration_->get_buffer_shrink_threshold(), + configuration_->get_endpoint_queue_limit_local(), + configuration_->get_permissions_uds()); } catch (const std::exception &e) { VSOMEIP_ERROR << ERROR_INFO[static_cast<int>(error_code_e::SERVER_ENDPOINT_CREATION_FAILED)] << " (" << static_cast<int>(error_code_e::SERVER_ENDPOINT_CREATION_FAILED) << ")"; @@ -860,8 +987,6 @@ void routing_manager_stub::init_routing_endpoint() { << endpoint_path_ << "): "<< std::strerror(errno); } VSOMEIP_INFO << "init_routing_endpoint Routing endpoint at " << endpoint_path_; - - const mode_t previous_mask(::umask(static_cast<mode_t>(configuration_->get_umask()))); #endif try { @@ -875,16 +1000,14 @@ void routing_manager_stub::init_routing_endpoint() { #endif io_, configuration_->get_max_message_size_local(), configuration_->get_buffer_shrink_threshold(), - configuration_->get_endpoint_queue_limit_local()); + configuration_->get_endpoint_queue_limit_local(), + configuration_->get_permissions_uds()); } catch (const std::exception &e) { VSOMEIP_ERROR << ERROR_INFO[static_cast<int>(error_code_e::SERVER_ENDPOINT_CREATION_FAILED)] << " (" << static_cast<int>(error_code_e::SERVER_ENDPOINT_CREATION_FAILED) << ")"; VSOMEIP_ERROR << "routing_manager_stub::init_routing_endpoint Client ID: " << std::hex << VSOMEIP_ROUTING_CLIENT << ": " << e.what(); } - #ifndef _WIN32 - ::umask(previous_mask); - #endif is_socket_activated_ = false; } } @@ -899,13 +1022,17 @@ void routing_manager_stub::on_offer_service(client_t _client, configuration_->is_offer_allowed(_client, _service, _instance)) { std::lock_guard<std::mutex> its_guard(routing_info_mutex_); routing_info_[_client].second[_service][_instance] = std::make_pair(_major, _minor); + 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); } else { - VSOMEIP_WARNING << std::hex << "Security: Client 0x" << _client - << " isn't allow to offer the following service/instance " + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << _client + << " : routing_manager_stub::on_offer_service: " + << "isn't allowed to offer the following service/instance " << _service << "/" << _instance - << " : Skip offer!"; + << " ~> Skip offer!"; } } @@ -959,6 +1086,87 @@ void routing_manager_stub::create_client_routing_info(const client_t _target) { 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; + } + + 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; + +#if 0 + std::stringstream msg; + msg << "rms::send_credentials_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), true); + } 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); @@ -1175,6 +1383,44 @@ void routing_manager_stub::insert_offered_services_info(client_t _target, offered_services_info_[_target] = its_command; } +void routing_manager_stub::distribute_credentials(client_t _hoster, service_t _service, instance_t _instance) { + std::set<std::pair<uint32_t, uint32_t>> its_credentials; + std::set<client_t> its_requesting_clients; + // search for clients which shall receive the credentials + for (auto its_requesting_client : service_requests_) { + auto its_service = its_requesting_client.second.find(_service); + if (its_service != its_requesting_client.second.end()) { + for (auto its_instance : its_service->second) { + if (its_instance.first == ANY_INSTANCE || + its_instance.first == _instance) { + its_requesting_clients.insert(its_requesting_client.first); + } else { + auto found_instance = its_service->second.find(_instance); + if (found_instance != its_service->second.end()) { + its_requesting_clients.insert(its_requesting_client.first); + } + } + } + } + } + + // search for UID / GID linked with the client ID that offers the requested services + std::pair<uint32_t, uint32_t> its_uid_gid; + if (configuration_->get_client_to_uid_gid_mapping(_hoster, its_uid_gid)) { + for (auto its_requesting_client : its_requesting_clients) { + std::pair<uint32_t, uint32_t> its_requester_uid_gid; + if (configuration_->get_client_to_uid_gid_mapping(its_requesting_client, its_requester_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))); + create_client_credentials_info(its_requesting_client); + insert_client_credentials_info(its_requesting_client, its_credentials); + send_client_credentials_info(its_requesting_client); + } + } + } + } +} + 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) { @@ -1414,7 +1660,7 @@ void routing_manager_stub::on_pong(client_t _client) { void routing_manager_stub::start_watchdog() { - std::function<void(boost::system::error_code const &)> its_callback = + auto its_callback = [this](boost::system::error_code const &_error) { if (!_error) check_watchdog(); @@ -1440,8 +1686,7 @@ void routing_manager_stub::check_watchdog() { broadcast_ping(); - std::function<void(boost::system::error_code const &)> its_callback = - [this](boost::system::error_code const &_error) { + auto its_callback = [this](boost::system::error_code const &_error) { (void)_error; std::list< client_t > lost; { @@ -1483,8 +1728,8 @@ void routing_manager_stub::create_local_receiver() { int port = VSOMEIP_INTERNAL_BASE_PORT; #else if (!check_credentials(get_client(), getuid(), getgid())) { - VSOMEIP_ERROR << "routing_manager_stub::create_local_receiver: " - << std::hex << "Client " << get_client() << " isn't allow" + 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!"; return; } @@ -1492,8 +1737,6 @@ void routing_manager_stub::create_local_receiver() { VSOMEIP_ERROR << "routing_manager_stub::create_local_receiver unlink (local receiver) failed (" << local_receiver_path_ << "): "<< std::strerror(errno); } - - const mode_t previous_mask(::umask(static_cast<mode_t>(configuration_->get_umask()))); #endif try { local_receiver_ = @@ -1506,16 +1749,14 @@ void routing_manager_stub::create_local_receiver() { #endif io_, configuration_->get_max_message_size_local(), configuration_->get_buffer_shrink_threshold(), - configuration_->get_endpoint_queue_limit_local()); + configuration_->get_endpoint_queue_limit_local(), + configuration_->get_permissions_uds()); } catch (const std::exception &e) { VSOMEIP_ERROR << ERROR_INFO[static_cast<int>(error_code_e::SERVER_ENDPOINT_CREATION_FAILED)] << " (" << static_cast<int>(error_code_e::SERVER_ENDPOINT_CREATION_FAILED) << ")"; VSOMEIP_ERROR << "routing_manager_stub::_local_receiver Client ID: " << std::hex << VSOMEIP_ROUTING_CLIENT << ": " << e.what(); } -#ifndef _WIN32 - ::umask(previous_mask); -#endif local_receiver_->start(); } @@ -1680,6 +1921,10 @@ void routing_manager_stub::update_registration(client_t _client, << (_type == registration_type_e::REGISTER ? "registering." : "deregistering."); + if (_type != registration_type_e::REGISTER) { + configuration_->remove_client_to_uid_gid_mapping(_client); + } + if (_type == registration_type_e::DEREGISTER) { // If we receive a DEREGISTER client command // the endpoint error handler is not longer needed @@ -1715,6 +1960,46 @@ 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) { + 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 (configuration_->get_client_to_uid_gid_mapping(_client, its_requester_uid_gid)) { + // determine credentials of offering clients using current routing info + std::set<client_t> its_offering_clients; + + // search in local clients for the offering client + for (auto request : _requests) { + std::set<client_t> its_clients; + its_clients = host_->find_local_clients(request.service_, request.instance_); + for (auto its_client : its_clients) { + its_offering_clients.insert(its_client); + } + } + + // 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 (configuration_->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))); + } + } + } + + // 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); + } + } +} + void routing_manager_stub::handle_requests(const client_t _client, std::set<service_data_t>& _requests) { if (!_requests.size()) { return; @@ -1861,4 +2146,176 @@ void routing_manager_stub::print_endpoint_status() const { } } +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; + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, + sizeof(client_t)); + 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)); + } 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; + } +} + +bool routing_manager_stub::is_policy_cached(uint32_t _uid) { + { + std::lock_guard<std::mutex> its_lock(updated_security_policies_mutex_); + if (updated_security_policies_.find(_uid) + != updated_security_policies_.end()) { + VSOMEIP_INFO << __func__ << " Policy for UID: " << std::dec + << _uid << " was already updated before!"; + return true; + } else { + return false; + } + } +} + +void routing_manager_stub::policy_cache_add(uint32_t _uid, std::shared_ptr<payload> _payload) { + // cache security policy payload for later distribution to new registering clients + { + std::lock_guard<std::mutex> its_lock(updated_security_policies_mutex_); + updated_security_policies_[_uid] = _payload; + } +} + +void routing_manager_stub::policy_cache_remove(uint32_t _uid) { + { + std::lock_guard<std::mutex> its_lock(updated_security_policies_mutex_); + updated_security_policies_.erase(_uid); + } +} + +bool routing_manager_stub::send_update_security_policy_request(client_t _client, pending_security_update_id_t _update_id, + uint32_t _uid, std::shared_ptr<payload> _payload) { + 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); + + // client ID + for (uint32_t i = 0; i < sizeof(client_t); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&_client)[i]); + } + // security update id length + payload length including gid and uid + std::uint32_t its_size = uint32_t(sizeof(pending_security_update_id_t) + _payload->get_length()); + for (uint32_t i = 0; i < sizeof(its_size); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&its_size)[i]); + } + // ID of update request + for (uint32_t i = 0; i < sizeof(pending_security_update_id_t); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&_update_id)[i]); + } + // payload + for (uint32_t i = 0; i < _payload->get_length(); ++i) { + its_command.push_back(_payload->get_data()[i]); + } + + return its_endpoint->send(its_command.data(), uint32_t(its_command.size())); + } else { + return false; + } +} + +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()); + + if (!its_policy_count) { + return true; + } + + VSOMEIP_INFO << __func__ << " Distributing [" + << std::dec << its_policy_count + << "] security policy updates to registering client: " + << std::hex << _client; + + // command + its_command.push_back(VSOMEIP_DISTRIBUTE_SECURITY_POLICIES); + + // 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]); + } + + //overall size (placeholder + for (uint32_t i = 0; i < sizeof(uint32_t); ++i) { + its_command.push_back(0x00); + } + + // 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]); + } + + for (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]); + } + // 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)); + + 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; + } +} + +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; + } +} + } // namespace vsomeip diff --git a/implementation/routing/src/serviceinfo.cpp b/implementation/routing/src/serviceinfo.cpp index 3afc937..42db53b 100644 --- a/implementation/routing/src/serviceinfo.cpp +++ b/implementation/routing/src/serviceinfo.cpp @@ -22,6 +22,18 @@ serviceinfo::serviceinfo(major_version_t _major, minor_version_t _minor, ttl_ = std::chrono::duration_cast<std::chrono::milliseconds>(ttl); } +serviceinfo::serviceinfo(const serviceinfo& _other) : + group_(_other.group_), + major_(_other.major_), + minor_(_other.minor_), + ttl_(_other.ttl_), + reliable_(_other.reliable_), + unreliable_(_other.unreliable_), + requesters_(_other.requesters_), + is_local_(_other.is_local_), + is_in_mainphase_(_other.is_in_mainphase_) + {} + serviceinfo::~serviceinfo() { } diff --git a/implementation/runtime/include/application_impl.hpp b/implementation/runtime/include/application_impl.hpp index efd7d7d..fe23c90 100644 --- a/implementation/runtime/include/application_impl.hpp +++ b/implementation/runtime/include/application_impl.hpp @@ -61,7 +61,7 @@ public: instance_t _instance, event_t _event, const std::set<eventgroup_t> &_eventgroups, bool _is_field, - std::chrono::milliseconds _cycle, bool _change_resets_cycle_, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, const epsilon_change_func_t &_epsilon_change_func); VSOMEIP_EXPORT void stop_offer_event(service_t _service, instance_t _instance, event_t _event); @@ -184,6 +184,31 @@ public: VSOMEIP_EXPORT void register_async_subscription_handler(service_t _service, instance_t _instance, eventgroup_t _eventgroup, async_subscription_handler_t _handler); + VSOMEIP_EXPORT void set_offer_acceptance_required(ip_address_t _address, const std::string _path, bool _enable); + VSOMEIP_EXPORT offer_acceptance_map_type_t get_offer_acceptance_required(); + + VSOMEIP_EXPORT void register_offer_acceptance_handler(offer_acceptance_handler_t _handler); + + VSOMEIP_EXPORT void register_reboot_notification_handler(reboot_notification_handler_t _handler); + + VSOMEIP_EXPORT void register_routing_ready_handler(routing_ready_handler_t _handler); + VSOMEIP_EXPORT void register_routing_state_handler(routing_state_handler_t _handler); + + VSOMEIP_EXPORT bool update_service_configuration(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool _offer); + + VSOMEIP_EXPORT void update_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + std::shared_ptr<policy> _policy, + std::shared_ptr<payload> _payload, + security_update_handler_t _handler); + VSOMEIP_EXPORT void remove_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + security_update_handler_t _handler); private: // // Types diff --git a/implementation/runtime/src/application_impl.cpp b/implementation/runtime/src/application_impl.cpp index 219c8f0..a3040c3 100644 --- a/implementation/runtime/src/application_impl.cpp +++ b/implementation/runtime/src/application_impl.cpp @@ -27,8 +27,7 @@ #include "../../routing/include/routing_manager_impl.hpp" #include "../../routing/include/routing_manager_proxy.hpp" #include "../../utility/include/utility.hpp" -#include "../../tracing/include/trace_connector.hpp" -#include "../../tracing/include/enumeration_types.hpp" +#include "../../tracing/include/connector_impl.hpp" #include "../../plugin/include/plugin_manager.hpp" #include "../../endpoints/include/endpoint.hpp" @@ -63,6 +62,37 @@ application_impl::application_impl(const std::string &_name) application_impl::~application_impl() { runtime_->remove_application(name_); + try { + if (stop_thread_.joinable()) { + stop_thread_.detach(); + } + } catch (const std::exception& e) { + std::cerr << __func__ << " catched exception (shutdown): " << e.what() << std::endl; + } + + try { + std::lock_guard<std::mutex> its_lock_start_stop(start_stop_mutex_); + for (auto t : io_threads_) { + if (t->joinable()) { + t->detach(); + } + } + io_threads_.clear(); + } catch (const std::exception& e) { + std::cerr << __func__ << " catched exception (io threads): " << e.what() << std::endl; + } + + try { + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + for (auto its_dispatcher : dispatchers_) { + if (its_dispatcher.second->joinable()) { + its_dispatcher.second->detach(); + } + } + dispatchers_.clear(); + } catch (const std::exception& e) { + std::cerr << __func__ << " catched exception (dispatchers): " << e.what() << std::endl; + } } void application_impl::set_configuration( @@ -102,7 +132,7 @@ bool application_impl::init() { configuration_->load(name_); VSOMEIP_INFO << "Default configuration module loaded."; } else { - std::cerr << "Service Discovery module could not be loaded!" << std::endl; + std::cerr << "Configuration module could not be loaded!" << std::endl; std::exit(EXIT_FAILURE); } } @@ -170,14 +200,22 @@ bool application_impl::init() { if (!utility::auto_configuration_init(its_configuration)) { VSOMEIP_WARNING << "Could _not_ initialize auto-configuration:" " Cannot guarantee unique application identifiers!"; + if (client_ == ILLEGAL_CLIENT) { + VSOMEIP_ERROR << "Couldn't acquire client identifier."; + return false; + } } else { // Client Identifier client_t its_old_client = client_; client_ = utility::request_client_id(its_configuration, name_, client_); if (client_ == ILLEGAL_CLIENT) { - VSOMEIP_ERROR << "Couldn't acquire client identifier"; + VSOMEIP_ERROR << "Couldn't acquire client identifier from auto-configuration."; return false; } + std::string credentials = ""; +#ifndef _WIN32 + credentials = " and UID/GID=" + std::to_string(getuid()) + "/" + std::to_string(getgid()); +#endif VSOMEIP_INFO << "SOME/IP client identifier configured. " << "Using " << std::hex << std::setfill('0') << std::setw(4) @@ -185,7 +223,7 @@ bool application_impl::init() { << " (was: " << std::hex << std::setfill('0') << std::setw(4) << its_old_client - << ")"; + << ")" << credentials; // Routing if (its_routing_host == "") { @@ -213,47 +251,16 @@ bool application_impl::init() { #ifdef USE_DLT // Tracing - std::shared_ptr<tc::trace_connector> its_trace_connector = tc::trace_connector::get(); - std::shared_ptr<cfg::trace> its_trace_cfg = its_configuration->get_trace(); - - auto &its_channels_cfg = its_trace_cfg->channels_; - for (auto it = its_channels_cfg.begin(); it != its_channels_cfg.end(); ++it) { - its_trace_connector->add_channel(it->get()->id_, it->get()->name_); - } - - auto &its_filter_rules_cfg = its_trace_cfg->filter_rules_; - for (auto it = its_filter_rules_cfg.begin(); it != its_filter_rules_cfg.end(); ++it) { - std::shared_ptr<cfg::trace_filter_rule> its_filter_rule_cfg = *it; - tc::trace_connector::filter_rule_t its_filter_rule; - tc::filter_type_e its_filter_type; - - if(its_filter_rule_cfg->type_ == "negative") { - its_filter_type = tc::filter_type_e::NEGATIVE; - } else { - its_filter_type = tc::filter_type_e::POSITIVE; - } - - tc::trace_connector::filter_rule_map_t its_filter_rule_map; - its_filter_rule_map[tc::filter_criteria_e::SERVICES] = its_filter_rule_cfg->services_; - its_filter_rule_map[tc::filter_criteria_e::METHODS] = its_filter_rule_cfg->methods_; - its_filter_rule_map[tc::filter_criteria_e::CLIENTS] = its_filter_rule_cfg->clients_; - - its_filter_rule = std::make_pair(its_filter_type, its_filter_rule_map); - - its_trace_connector->add_filter_rule(it->get()->channel_, its_filter_rule); - } - - bool enable_tracing = its_trace_cfg->is_enabled_; - if (enable_tracing) - its_trace_connector->init(); - its_trace_connector->set_enabled(enable_tracing); - - bool enable_sd_tracing = its_trace_cfg->is_sd_enabled_; - its_trace_connector->set_sd_enabled(enable_sd_tracing); + std::shared_ptr<trace::connector_impl> its_connector + = trace::connector_impl::get(); + std::shared_ptr<cfg::trace> its_trace_configuration + = its_configuration->get_trace(); + its_connector->configure(its_trace_configuration); #endif VSOMEIP_INFO << "Application(" << (name_ != "" ? name_ : "unnamed") - << ", " << std::hex << client_ << ") is initialized (" + << ", " << std::hex << std::setw(4) << std::setfill('0') << client_ + << ") is initialized (" << std::dec << max_dispatchers_ << ", " << std::dec << max_dispatch_time_ << ")."; @@ -266,7 +273,7 @@ bool application_impl::init() { signals_.add(SIGTERM); // Register signal handler - std::function<void(boost::system::error_code const &, int)> its_signal_handler = + auto its_signal_handler = [this] (boost::system::error_code const &_error, int _signal) { if (!_error) { switch (_signal) { @@ -284,19 +291,24 @@ bool application_impl::init() { } #endif - auto its_plugins = configuration_->get_plugins(name_); - auto its_app_plugin_info = its_plugins.find(plugin_type_e::APPLICATION_PLUGIN); - if (its_app_plugin_info != its_plugins.end()) { - for (auto its_library : its_app_plugin_info->second) { - auto its_application_plugin = plugin_manager::get()->get_plugin( - plugin_type_e::APPLICATION_PLUGIN, its_library); - if (its_application_plugin) { - VSOMEIP_INFO << "Client 0x" << std::hex << get_client() - << " Loading plug-in library: " << its_library << " succeeded!"; - std::dynamic_pointer_cast<application_plugin>(its_application_plugin)-> - on_application_state_change(name_, application_plugin_state_e::STATE_INITIALIZED); + if (configuration_) { + auto its_plugins = configuration_->get_plugins(name_); + auto its_app_plugin_info = its_plugins.find(plugin_type_e::APPLICATION_PLUGIN); + if (its_app_plugin_info != its_plugins.end()) { + for (auto its_library : its_app_plugin_info->second) { + auto its_application_plugin = plugin_manager::get()->get_plugin( + plugin_type_e::APPLICATION_PLUGIN, its_library); + if (its_application_plugin) { + VSOMEIP_INFO << "Client 0x" << std::hex << get_client() + << " Loading plug-in library: " << its_library << " succeeded!"; + std::dynamic_pointer_cast<application_plugin>(its_application_plugin)-> + on_application_state_change(name_, application_plugin_state_e::STATE_INITIALIZED); + } } } + } else { + std::cerr << "Configuration module could not be loaded!" << std::endl; + std::exit(EXIT_FAILURE); } return is_initialized_; @@ -313,6 +325,7 @@ void application_impl::start() { } #endif const size_t io_thread_count = configuration_->get_io_thread_count(name_); + const int io_thread_nice_level = configuration_->get_io_thread_nice_level(name_); { std::lock_guard<std::mutex> its_lock(start_stop_mutex_); if (io_.stopped()) { @@ -336,8 +349,13 @@ void application_impl::start() { } stopped_ = false; stopped_called_ = false; - VSOMEIP_INFO << "Starting vsomeip application \"" << name_ << "\" using " - << std::dec << io_thread_count << " threads"; + VSOMEIP_INFO << "Starting vsomeip application \"" << name_ << "\" (" + << std::hex << std::setw(4) << std::setfill('0') << client_ + << ") using " << std::dec << io_thread_count << " threads" +#ifndef _WIN32 + << " I/O nice " << io_thread_nice_level +#endif + ; start_caller_id_ = std::this_thread::get_id(); { @@ -351,14 +369,14 @@ void application_impl::start() { if (stop_thread_.joinable()) { stop_thread_.join(); } - stop_thread_= std::thread(&application_impl::shutdown, this); + stop_thread_= std::thread(&application_impl::shutdown, shared_from_this()); if (routing_) routing_->start(); for (size_t i = 0; i < io_thread_count - 1; i++) { std::shared_ptr<std::thread> its_thread - = std::make_shared<std::thread>([this, i] { + = std::make_shared<std::thread>([this, i, io_thread_nice_level] { VSOMEIP_INFO << "io thread id from application: " << std::hex << std::setw(4) << std::setfill('0') << client_ << " (" << name_ << ") is: " << std::hex @@ -375,13 +393,15 @@ void application_impl::start() { << std::setfill('0') << i+1; pthread_setname_np(pthread_self(),s.str().c_str()); } + if ((VSOMEIP_IO_THREAD_NICE_LEVEL != io_thread_nice_level) && (io_thread_nice_level != nice(io_thread_nice_level))) { + VSOMEIP_WARNING << "nice(" << io_thread_nice_level << ") failed " << errno << " for " << std::this_thread::get_id(); + } #endif try { io_.run(); #ifndef _WIN32 } catch (const boost::log::v2_mt_posix::system_error &e) { - std::cerr << "catched boost::log system_error in I/O thread" << std::endl << - boost::current_exception_diagnostic_information(); + std::cerr << "catched boost::log system_error in I/O thread" << std::endl; #endif } catch (const std::exception &e) { VSOMEIP_ERROR << "application_impl::start() " @@ -416,24 +436,29 @@ void application_impl::start() { << " TID: " << std::dec << static_cast<int>(syscall(SYS_gettid)) #endif ; +#ifndef _WIN32 + if ((VSOMEIP_IO_THREAD_NICE_LEVEL != io_thread_nice_level) && (io_thread_nice_level != nice(io_thread_nice_level))) { + VSOMEIP_WARNING << "nice(" << io_thread_nice_level << ") failed " << errno << " for " << std::this_thread::get_id(); + } +#endif try { io_.run(); + + if (stop_thread_.joinable()) { + stop_thread_.join(); + } + + utility::release_client_id(client_); + utility::auto_configuration_exit(client_, configuration_); + #ifndef _WIN32 } catch (const boost::log::v2_mt_posix::system_error &e) { - std::cerr << "catched boost::log system_error in I/O thread" << std::endl << - boost::current_exception_diagnostic_information(); + std::cerr << "catched boost::log system_error in I/O thread" << std::endl; #endif } catch (const std::exception &e) { VSOMEIP_ERROR << "application_impl::start() catched exception: " << e.what(); } - if (stop_thread_.joinable()) { - stop_thread_.join(); - } - - utility::release_client_id(client_); - utility::auto_configuration_exit(client_, configuration_); - { std::lock_guard<std::mutex> its_lock_start_stop(block_stop_mutex_); block_stopping_ = true; @@ -460,7 +485,12 @@ void application_impl::start() { void application_impl::stop() { #ifndef _WIN32 // Gives serious problems under Windows. - VSOMEIP_INFO << "Stopping vsomeip application \"" << name_ << "\"."; + try { + VSOMEIP_INFO << "Stopping vsomeip application \"" << name_ << "\" (" + << std::hex << std::setw(4) << std::setfill('0') << client_ << ")."; + } catch (const boost::log::v2_mt_posix::system_error &e) { + std::cerr << "catched boost::log system_error application_impl::stop" << std::endl; + } #endif bool block = true; { @@ -593,9 +623,7 @@ bool application_impl::is_available_unlocked( bool is_available(false); - const std::function<void(const std::map<instance_t, - std::map<major_version_t, minor_version_t>>::const_iterator&)> - check_major_minor = [&](const std::map<instance_t, + auto check_major_minor = [&](const std::map<instance_t, std::map<major_version_t, minor_version_t >>::const_iterator &_found_instance) { auto found_major = _found_instance->second.find(_major); @@ -839,7 +867,7 @@ void application_impl::notify_one(service_t _service, instance_t _instance, client_t _client, bool _force) const { if (routing_) { routing_->notify_one(_service, _instance, _event, _payload, _client, - _force, true); + _force, true, false); } } @@ -848,7 +876,7 @@ void application_impl::notify_one(service_t _service, instance_t _instance, client_t _client, bool _force, bool _flush) const { if (routing_) { routing_->notify_one(_service, _instance, _event, _payload, _client, - _force, _flush); + _force, _flush, false); } } @@ -1379,7 +1407,7 @@ void application_impl::on_availability(service_t _service, instance_t _instance, } } - const std::function<void(const availability_major_minor_t&)> find_matching_handler = + auto find_matching_handler = [&](const availability_major_minor_t& _av_ma_mi_it) { auto found_major = _av_ma_mi_it.find(_major); if (found_major != _av_ma_mi_it.end()) { @@ -1650,8 +1678,8 @@ void application_impl::dispatch() { << " TID: " << std::dec << static_cast<int>(syscall(SYS_gettid)) #endif ; + std::unique_lock<std::mutex> its_lock(handlers_mutex_); while (is_active_dispatcher(its_id)) { - std::unique_lock<std::mutex> its_lock(handlers_mutex_); if (is_dispatching_ && handlers_.empty()) { dispatcher_condition_.wait(its_lock); // Maybe woken up from main dispatcher @@ -1680,7 +1708,6 @@ void application_impl::dispatch() { } } } - std::lock_guard<std::mutex> its_lock(handlers_mutex_); if (is_dispatching_) { std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); elapsed_dispatchers_.insert(its_id); @@ -1768,29 +1795,34 @@ void application_impl::invoke_handler(std::shared_ptr<sync_handler> &_handler) { its_dispatcher_timer.async_wait([this, its_id, its_sync_handler](const boost::system::error_code &_error) { if (!_error) { print_blocking_call(its_sync_handler); - bool active_dispatcher_available(false); - if (is_dispatching_) { - std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); - active_dispatcher_available = has_active_dispatcher(); - } - if (active_dispatcher_available) { + if (has_active_dispatcher()) { std::lock_guard<std::mutex> its_lock(handlers_mutex_); dispatcher_condition_.notify_all(); - } else if (is_dispatching_) { + } else { // If possible, create a new dispatcher thread to unblock. // If this is _not_ possible, dispatching is blocked until // at least one of the active handler calls returns. - std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); - if (dispatchers_.size() < max_dispatchers_ && is_dispatching_) { - auto its_dispatcher = std::make_shared<std::thread>( - std::bind(&application_impl::dispatch, shared_from_this())); - dispatchers_[its_dispatcher->get_id()] = its_dispatcher; - } else { - VSOMEIP_ERROR << "Maximum number of dispatchers exceeded."; + while (is_dispatching_) { + if (dispatcher_mutex_.try_lock()) { + if (dispatchers_.size() < max_dispatchers_) { + if (is_dispatching_) { + auto its_dispatcher = std::make_shared<std::thread>( + std::bind(&application_impl::dispatch, shared_from_this())); + dispatchers_[its_dispatcher->get_id()] = its_dispatcher; + } else { + VSOMEIP_INFO << "Won't start new dispatcher " + "thread as Client=" << std::hex + << get_client() << " is shutting down"; + } + } else { + VSOMEIP_ERROR << "Maximum number of dispatchers exceeded."; + } + dispatcher_mutex_.unlock(); + break; + } else { + std::this_thread::yield(); + } } - } else { - VSOMEIP_INFO << "Won't start new dispatcher thread as Client=" - << std::hex << get_client() << " is shutting down"; } } }); @@ -1840,28 +1872,40 @@ void application_impl::invoke_handler(std::shared_ptr<sync_handler> &_handler) { } bool application_impl::has_active_dispatcher() { - for (const auto &d : dispatchers_) { - if (running_dispatchers_.find(d.first) == running_dispatchers_.end() && - elapsed_dispatchers_.find(d.first) == elapsed_dispatchers_.end()) { - return true; + while (is_dispatching_) { + if (dispatcher_mutex_.try_lock()) { + for (const auto &d : dispatchers_) { + if (running_dispatchers_.find(d.first) == running_dispatchers_.end() && + elapsed_dispatchers_.find(d.first) == elapsed_dispatchers_.end()) { + dispatcher_mutex_.unlock(); + return true; + } + } + dispatcher_mutex_.unlock(); + return false; } + std::this_thread::yield(); } return false; } bool application_impl::is_active_dispatcher(const std::thread::id &_id) { - if (!is_dispatching_) { - return is_dispatching_; - } - std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); - for (const auto &d : dispatchers_) { - if (d.first != _id && - running_dispatchers_.find(d.first) == running_dispatchers_.end() && - elapsed_dispatchers_.find(d.first) == elapsed_dispatchers_.end()) { - return false; + while (is_dispatching_) { + if (dispatcher_mutex_.try_lock()) { + for (const auto &d : dispatchers_) { + if (d.first != _id && + running_dispatchers_.find(d.first) == running_dispatchers_.end() && + elapsed_dispatchers_.find(d.first) == elapsed_dispatchers_.end()) { + dispatcher_mutex_.unlock(); + return false; + } + } + dispatcher_mutex_.unlock(); + return true; } + std::this_thread::yield(); } - return true; + return false; } void application_impl::remove_elapsed_dispatchers() { @@ -1978,14 +2022,15 @@ void application_impl::shutdown() { { std::lock_guard<std::mutex> its_lock_start_stop(start_stop_mutex_); for (auto t : io_threads_) { - t->join(); + if (t->joinable()) { + t->join(); + } } io_threads_.clear(); } #ifndef _WIN32 } catch (const boost::log::v2_mt_posix::system_error &e) { - std::cerr << "catched boost::log system_error in stop thread" << std::endl << - boost::current_exception_diagnostic_information(); + std::cerr << "catched boost::log system_error in stop thread" << std::endl; #endif } catch (const std::exception &e) { VSOMEIP_ERROR << "application_impl::shutdown() catched exception: " << e.what(); @@ -2361,4 +2406,129 @@ void application_impl::register_async_subscription_handler(service_t _service, register_message_handler(_service, _instance, ANY_METHOD - 1, handler); } +void application_impl::register_offer_acceptance_handler( + offer_acceptance_handler_t _handler) { + if (is_routing() && routing_) { + const auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + rm_impl->register_offer_acceptance_handler(_handler); + } +} + +void application_impl::register_reboot_notification_handler( + reboot_notification_handler_t _handler) { + if (is_routing() && routing_) { + const auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + rm_impl->register_reboot_notification_handler(_handler); + } +} + +void application_impl::set_offer_acceptance_required( + ip_address_t _address, const std::string _path, bool _enable) { + if (is_routing()) { + const boost::asio::ip::address its_address = _address.is_v4_ ? + static_cast<boost::asio::ip::address>(boost::asio::ip::address_v4(_address.address_.v4_)) : + static_cast<boost::asio::ip::address>(boost::asio::ip::address_v6(_address.address_.v6_)); + configuration_->set_offer_acceptance_required(its_address, _path, _enable); + if (_enable && routing_) { + const auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + rm_impl->offer_acceptance_enabled(its_address); + } + } +} + +vsomeip::application::offer_acceptance_map_type_t +application_impl::get_offer_acceptance_required() { + offer_acceptance_map_type_t its_ret; + if (is_routing()) { + for (const auto& e : configuration_->get_offer_acceptance_required()) { + ip_address_t its_address; + its_address.is_v4_ = e.first.is_v4(); + if (its_address.is_v4_) { + its_address.address_.v4_ = e.first.to_v4().to_bytes(); + } else { + its_address.address_.v6_ = e.first.to_v6().to_bytes(); + } + its_ret[its_address] = e.second; + } + } + return its_ret; +} + +void application_impl::register_routing_ready_handler( + routing_ready_handler_t _handler) { + if (is_routing() && routing_) { + const auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + rm_impl->register_routing_ready_handler(_handler); + } +} + +void application_impl::register_routing_state_handler( + routing_state_handler_t _handler) { + if (is_routing() && routing_) { + const auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + rm_impl->register_routing_state_handler(_handler); + } +} + +bool application_impl::update_service_configuration(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool _offer) { + bool ret = false; + if (!is_routing_manager_host_) { + VSOMEIP_ERROR << __func__ << " is only intended to be called by " + "application acting as routing manager host"; + } else if (!routing_) { + VSOMEIP_ERROR << __func__ << " routing is zero"; + } else { + auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + if (rm_impl) { + if (_offer) { + ret = rm_impl->offer_service_remotely(_service, _instance, + _port, _reliable, _magic_cookies_enabled); + } else { + ret = rm_impl->stop_offer_service_remotely(_service, _instance, + _port, _reliable, _magic_cookies_enabled); + } + } + } + return ret; +} + +void application_impl::update_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + ::std::shared_ptr<policy> _policy, + std::shared_ptr<payload> _payload, + security_update_handler_t _handler) { + if (!is_routing()) { + VSOMEIP_ERROR << __func__ << " is only intended to be called by " + "application acting as routing manager host"; + } else if (!routing_) { + VSOMEIP_ERROR << __func__ << " routing is zero"; + } else { + auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + if (rm_impl) { + rm_impl->update_security_policy_configuration(_uid, _gid, _policy, _payload, _handler); + } + } +} + +void application_impl::remove_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + security_update_handler_t _handler) { + if (!is_routing()) { + VSOMEIP_ERROR << __func__ << " is only intended to be called by " + "application acting as routing manager host"; + } else if (!routing_) { + VSOMEIP_ERROR << __func__ << " routing is zero"; + } else { + auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + if (rm_impl) { + rm_impl->remove_security_policy_configuration(_uid, _gid, _handler); + } + } +} + } // namespace vsomeip diff --git a/implementation/service_discovery/include/entry_impl.hpp b/implementation/service_discovery/include/entry_impl.hpp index db12a1e..b41a94c 100755 --- a/implementation/service_discovery/include/entry_impl.hpp +++ b/implementation/service_discovery/include/entry_impl.hpp @@ -40,7 +40,7 @@ public: void set_instance(instance_t _instance);
major_version_t get_major_version() const;
- void set_major_version(major_version_t _version);
+ void set_major_version(major_version_t _major_version);
ttl_t get_ttl() const;
void set_ttl(ttl_t _ttl);
@@ -72,7 +72,7 @@ protected: std::uint8_t index2_;
entry_impl();
- entry_impl(const entry_impl &entry_);
+ entry_impl(const entry_impl &_entry);
};
} // namespace sd
diff --git a/implementation/service_discovery/include/ip_option_impl.hpp b/implementation/service_discovery/include/ip_option_impl.hpp index 1345835..a2a7660 100644 --- a/implementation/service_discovery/include/ip_option_impl.hpp +++ b/implementation/service_discovery/include/ip_option_impl.hpp @@ -17,7 +17,7 @@ class ip_option_impl: public option_impl { public: ip_option_impl(); virtual ~ip_option_impl(); - virtual bool operator ==(const ip_option_impl &_option) const; + virtual bool operator ==(const ip_option_impl &_other) const; uint16_t get_port() const; void set_port(uint16_t _port); diff --git a/implementation/service_discovery/include/message_impl.hpp b/implementation/service_discovery/include/message_impl.hpp index baca328..83d3a64 100755 --- a/implementation/service_discovery/include/message_impl.hpp +++ b/implementation/service_discovery/include/message_impl.hpp @@ -98,7 +98,7 @@ public: void forced_initial_events_add(forced_initial_events_t _entry);
const std::vector<forced_initial_events_t> forced_initial_events_get();
- void set_initial_events_required(bool _initial_events);
+ void set_initial_events_required(bool _initial_events_required);
bool initial_events_required() const;
private:
diff --git a/implementation/service_discovery/include/runtime.hpp b/implementation/service_discovery/include/runtime.hpp index f99fec8..670a7bb 100644 --- a/implementation/service_discovery/include/runtime.hpp +++ b/implementation/service_discovery/include/runtime.hpp @@ -10,6 +10,8 @@ namespace vsomeip {
+class configuration;
+
namespace sd {
class message_impl;
@@ -22,7 +24,8 @@ public: }
virtual std::shared_ptr<service_discovery> create_service_discovery(
- service_discovery_host *_host) const = 0;
+ service_discovery_host *_host,
+ std::shared_ptr<vsomeip::configuration> _configuration) const = 0;
virtual std::shared_ptr<message_impl> create_message() const = 0;
};
diff --git a/implementation/service_discovery/include/runtime_impl.hpp b/implementation/service_discovery/include/runtime_impl.hpp index dcdb7d7..0a9baaf 100644 --- a/implementation/service_discovery/include/runtime_impl.hpp +++ b/implementation/service_discovery/include/runtime_impl.hpp @@ -20,7 +20,8 @@ public: virtual ~runtime_impl(); std::shared_ptr<service_discovery> create_service_discovery( - service_discovery_host *_host) const; + service_discovery_host *_host, + std::shared_ptr<configuration> _configuration) const; std::shared_ptr<message_impl> create_message() const; }; diff --git a/implementation/service_discovery/include/service_discovery.hpp b/implementation/service_discovery/include/service_discovery.hpp index 92d80d3..e1c3dc4 100644 --- a/implementation/service_discovery/include/service_discovery.hpp +++ b/implementation/service_discovery/include/service_discovery.hpp @@ -11,6 +11,7 @@ #include <vsomeip/primitive_types.hpp> #include <vsomeip/enumeration_types.hpp> +#include <vsomeip/handler.hpp> #include "../../routing/include/serviceinfo.hpp" #include "../../endpoints/include/endpoint.hpp" #include "../include/service_discovery_host.hpp" @@ -26,7 +27,6 @@ public: virtual ~service_discovery() { } - virtual std::shared_ptr<configuration> get_configuration() const = 0; virtual boost::asio::io_service & get_io() = 0; virtual void init() = 0; @@ -72,6 +72,11 @@ public: service_t _service, instance_t _instance, eventgroup_t _eventgroup, client_t _client, bool _accepted, const std::shared_ptr<sd_message_identifier_t> &_sd_message_id) = 0; + + virtual void register_offer_acceptance_handler( + vsomeip::offer_acceptance_handler_t _handler) = 0; + virtual void register_reboot_notification_handler( + reboot_notification_handler_t _handler) = 0; }; } // namespace sd diff --git a/implementation/service_discovery/include/service_discovery_host.hpp b/implementation/service_discovery/include/service_discovery_host.hpp index f9e8f29..9c346fd 100644 --- a/implementation/service_discovery/include/service_discovery_host.hpp +++ b/implementation/service_discovery/include/service_discovery_host.hpp @@ -31,7 +31,6 @@ public: } virtual boost::asio::io_service & get_io() = 0; - virtual const std::shared_ptr<configuration> get_configuration() const = 0; virtual std::shared_ptr<endpoint> create_service_discovery_endpoint( const std::string &_address, uint16_t _port, bool _reliable) = 0; @@ -90,7 +89,7 @@ public: virtual bool has_identified(client_t _client, service_t _service, instance_t _instance, bool _reliable) = 0; - virtual std::chrono::steady_clock::time_point expire_subscriptions() = 0; + virtual std::chrono::steady_clock::time_point expire_subscriptions(bool _force) = 0; virtual std::shared_ptr<serviceinfo> get_offered_service( service_t _service, instance_t _instance) const = 0; diff --git a/implementation/service_discovery/include/service_discovery_impl.hpp b/implementation/service_discovery/include/service_discovery_impl.hpp index 995cfbc..77dbae9 100644 --- a/implementation/service_discovery/include/service_discovery_impl.hpp +++ b/implementation/service_discovery/include/service_discovery_impl.hpp @@ -56,10 +56,10 @@ struct subscriber_t { class service_discovery_impl: public service_discovery, public std::enable_shared_from_this<service_discovery_impl> { public: - service_discovery_impl(service_discovery_host *_host); + service_discovery_impl(service_discovery_host *_host, + std::shared_ptr<configuration> _configuration); virtual ~service_discovery_impl(); - std::shared_ptr<configuration> get_configuration() const; boost::asio::io_service & get_io(); void init(); @@ -102,6 +102,10 @@ public: service_t _service, instance_t _instance, eventgroup_t _eventgroup, client_t _client, bool _acknowledged, const std::shared_ptr<sd_message_identifier_t> &_sd_message_id); + + void register_offer_acceptance_handler(offer_acceptance_handler_t _handler); + void register_reboot_notification_handler( + reboot_notification_handler_t _handler); private: std::pair<session_t, bool> get_session(const boost::asio::ip::address &_address); void increment_session(const boost::asio::ip::address &_address); @@ -149,7 +153,9 @@ private: void process_serviceentry(std::shared_ptr<serviceentry_impl> &_entry, const std::vector<std::shared_ptr<option_impl> > &_options, - bool _unicast_flag, std::vector<std::pair<std::uint16_t, std::shared_ptr<message_impl>>>* _resubscribes); + bool _unicast_flag, + std::vector<std::pair<std::uint16_t, std::shared_ptr<message_impl>>>* _resubscribes, + bool _accept_offers); void process_offerservice_serviceentry( service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, ttl_t _ttl, @@ -210,7 +216,7 @@ private: void stop_subscription_expiration_timer_unlocked(); void expire_subscriptions(const boost::system::error_code &_error); - bool check_ipv4_address(boost::asio::ip::address its_address); + bool check_ipv4_address(const boost::asio::ip::address& its_address) const; bool check_static_header_fields( const std::shared_ptr<const message> &_message) const; @@ -346,6 +352,7 @@ private: private: boost::asio::io_service &io_; service_discovery_host *host_; + std::shared_ptr<configuration> configuration_; boost::asio::ip::address unicast_; uint16_t port_; @@ -443,6 +450,12 @@ private: std::mutex remote_offer_types_mutex_; std::map<std::pair<service_t, instance_t>, remote_offer_type_e> remote_offer_types_; std::map<boost::asio::ip::address, std::set<std::pair<service_t, instance_t>>> remote_offers_by_ip_; + + reboot_notification_handler_t reboot_notification_handler_; + offer_acceptance_handler_t offer_acceptance_handler_; + + std::mutex offer_mutex_; + std::mutex check_ttl_mutex_; }; } // namespace sd diff --git a/implementation/service_discovery/src/configuration_option_impl.cpp b/implementation/service_discovery/src/configuration_option_impl.cpp index e9cf058..e09c7c9 100755 --- a/implementation/service_discovery/src/configuration_option_impl.cpp +++ b/implementation/service_discovery/src/configuration_option_impl.cpp @@ -100,7 +100,7 @@ bool configuration_option_impl::deserialize(vsomeip::deserializer *_from) { is_successful = is_successful && _from->deserialize(l_itemLength);
if (l_itemLength > 0) {
is_successful = is_successful
- && _from->deserialize((uint8_t*) &l_item[0], l_itemLength);
+ && _from->deserialize(l_item, static_cast<std::size_t>(l_itemLength));
if (is_successful) {
size_t l_eqPos = l_item.find('='); //SWS_SD_00292
diff --git a/implementation/service_discovery/src/eventgroupentry_impl.cpp b/implementation/service_discovery/src/eventgroupentry_impl.cpp index f5394be..17fd63b 100755 --- a/implementation/service_discovery/src/eventgroupentry_impl.cpp +++ b/implementation/service_discovery/src/eventgroupentry_impl.cpp @@ -150,37 +150,42 @@ bool eventgroupentry_impl::is_matching_subscribe( // read out ip options of current and _other
std::vector<std::shared_ptr<ip_option_impl>> its_options_current;
std::vector<std::shared_ptr<ip_option_impl>> its_options_other;
+ const std::size_t its_options_size = _options.size();
for (const auto option_run : {0,1}) {
for (const auto option_index : options_[option_run]) {
- switch (_options[option_index]->get_type()) {
- case option_type_e::IP4_ENDPOINT:
- its_options_current.push_back(
- std::static_pointer_cast<ipv4_option_impl>(
- _options[option_index]));
- break;
- case option_type_e::IP6_ENDPOINT:
- its_options_current.push_back(
- std::static_pointer_cast<ipv6_option_impl>(
- _options[option_index]));
- break;
- default:
- break;
+ if (its_options_size > option_index) {
+ switch (_options[option_index]->get_type()) {
+ case option_type_e::IP4_ENDPOINT:
+ its_options_current.push_back(
+ std::static_pointer_cast<ipv4_option_impl>(
+ _options[option_index]));
+ break;
+ case option_type_e::IP6_ENDPOINT:
+ its_options_current.push_back(
+ std::static_pointer_cast<ipv6_option_impl>(
+ _options[option_index]));
+ break;
+ default:
+ break;
+ }
}
}
for (const auto option_index : _other.options_[option_run]) {
- switch (_options[option_index]->get_type()) {
- case option_type_e::IP4_ENDPOINT:
- its_options_other.push_back(
- std::static_pointer_cast<ipv4_option_impl>(
- _options[option_index]));
- break;
- case option_type_e::IP6_ENDPOINT:
- its_options_other.push_back(
- std::static_pointer_cast<ipv6_option_impl>(
- _options[option_index]));
- break;
- default:
- break;
+ if (its_options_size > option_index) {
+ switch (_options[option_index]->get_type()) {
+ case option_type_e::IP4_ENDPOINT:
+ its_options_other.push_back(
+ std::static_pointer_cast<ipv4_option_impl>(
+ _options[option_index]));
+ break;
+ case option_type_e::IP6_ENDPOINT:
+ its_options_other.push_back(
+ std::static_pointer_cast<ipv6_option_impl>(
+ _options[option_index]));
+ break;
+ default:
+ break;
+ }
}
}
}
diff --git a/implementation/service_discovery/src/message_impl.cpp b/implementation/service_discovery/src/message_impl.cpp index 9d5c1ac..e3b54ec 100755 --- a/implementation/service_discovery/src/message_impl.cpp +++ b/implementation/service_discovery/src/message_impl.cpp @@ -196,17 +196,17 @@ bool message_impl::serialize(vsomeip::serializer *_to) const { uint32_t entries_length = uint32_t(entries_.size() * VSOMEIP_SOMEIP_SD_ENTRY_SIZE);
is_successful = is_successful && _to->serialize(entries_length);
- for (auto it = entries_.begin(); it != entries_.end(); ++it)
- is_successful = is_successful && (*it)->serialize(_to);
+ for (const auto& its_entry : entries_)
+ is_successful = is_successful && its_entry && its_entry->serialize(_to);
uint32_t options_length = 0;
- for (auto its_option : options_)
- options_length += its_option->get_length()
- + VSOMEIP_SOMEIP_SD_OPTION_HEADER_SIZE;
+ for (const auto& its_option : options_)
+ options_length += its_option ? its_option->get_length()
+ + VSOMEIP_SOMEIP_SD_OPTION_HEADER_SIZE : 0;
is_successful = is_successful && _to->serialize(options_length);
- for (auto its_option : options_)
- is_successful = is_successful && its_option->serialize(_to);
+ for (const auto& its_option : options_)
+ is_successful = is_successful && its_option && its_option->serialize(_to);
return is_successful;
}
@@ -231,6 +231,14 @@ bool message_impl::deserialize(vsomeip::deserializer *_from) { // backup the current remaining length
uint32_t save_remaining = uint32_t(_from->get_remaining());
+ if (!is_successful) {
+ // couldn't deserialize entries length
+ return is_successful;
+ } else if (entries_length > save_remaining) {
+ // not enough data available to deserialize entries array
+ is_successful = false;
+ return is_successful;
+ }
// set remaining bytes to length of entries array
_from->set_remaining(entries_length);
diff --git a/implementation/service_discovery/src/runtime_impl.cpp b/implementation/service_discovery/src/runtime_impl.cpp index 90743b8..d72d034 100644 --- a/implementation/service_discovery/src/runtime_impl.cpp +++ b/implementation/service_discovery/src/runtime_impl.cpp @@ -25,8 +25,9 @@ runtime_impl::~runtime_impl() { } std::shared_ptr<service_discovery> runtime_impl::create_service_discovery( - service_discovery_host *_host) const { - return std::make_shared < service_discovery_impl > (_host); + service_discovery_host *_host, + std::shared_ptr<configuration> _configuration) const { + return std::make_shared < service_discovery_impl > (_host, _configuration); } std::shared_ptr<message_impl> runtime_impl::create_message() const { diff --git a/implementation/service_discovery/src/service_discovery_impl.cpp b/implementation/service_discovery/src/service_discovery_impl.cpp index 1f93559..de5f190 100644 --- a/implementation/service_discovery/src/service_discovery_impl.cpp +++ b/implementation/service_discovery/src/service_discovery_impl.cpp @@ -34,21 +34,22 @@ #include "../../routing/include/eventgroupinfo.hpp" #include "../../routing/include/serviceinfo.hpp" #include "../../plugin/include/plugin_manager.hpp" +#include "../../utility/include/byteorder.hpp" namespace vsomeip { namespace sd { -service_discovery_impl::service_discovery_impl(service_discovery_host *_host) +service_discovery_impl::service_discovery_impl(service_discovery_host *_host, + std::shared_ptr<configuration> _configuration) : io_(_host->get_io()), host_(_host), + configuration_(_configuration), port_(VSOMEIP_SD_DEFAULT_PORT), reliable_(false), - serializer_( - std::make_shared<serializer>( - host_->get_configuration()->get_buffer_shrink_threshold())), - deserializer_( - std::make_shared<deserializer>( - host_->get_configuration()->get_buffer_shrink_threshold())), + serializer_(std::make_shared<serializer>( + configuration_->get_buffer_shrink_threshold())), + deserializer_(std::make_shared<deserializer>( + configuration_->get_buffer_shrink_threshold())), ttl_timer_(_host->get_io()), ttl_timer_runtime_(VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY / 2), ttl_(VSOMEIP_SD_DEFAULT_TTL), @@ -75,10 +76,6 @@ service_discovery_impl::service_discovery_impl(service_discovery_host *_host) service_discovery_impl::~service_discovery_impl() { } -std::shared_ptr<configuration> service_discovery_impl::get_configuration() const { - return host_->get_configuration(); -} - boost::asio::io_service & service_discovery_impl::get_io() { return io_; } @@ -86,62 +83,55 @@ boost::asio::io_service & service_discovery_impl::get_io() { void service_discovery_impl::init() { runtime_ = std::dynamic_pointer_cast<sd::runtime>(plugin_manager::get()->get_plugin(plugin_type_e::SD_RUNTIME_PLUGIN, VSOMEIP_SD_LIBRARY)); - std::shared_ptr < configuration > its_configuration = - host_->get_configuration(); - if (its_configuration) { - unicast_ = its_configuration->get_unicast_address(); - sd_multicast_ = its_configuration->get_sd_multicast(); - boost::system::error_code ec; - sd_multicast_address_ = boost::asio::ip::address::from_string(sd_multicast_, ec); - - port_ = its_configuration->get_sd_port(); - reliable_ = (its_configuration->get_sd_protocol() - == "tcp"); - max_message_size_ = (reliable_ ? VSOMEIP_MAX_TCP_SD_PAYLOAD : - VSOMEIP_MAX_UDP_SD_PAYLOAD); - - ttl_ = its_configuration->get_sd_ttl(); - - // generate random initial delay based on initial delay min and max - std::int32_t initial_delay_min = - its_configuration->get_sd_initial_delay_min(); - if (initial_delay_min < 0) { - initial_delay_min = VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MIN; - } - std::int32_t initial_delay_max = - its_configuration->get_sd_initial_delay_max(); - if (initial_delay_max < 0) { - initial_delay_max = VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MAX; - } - if (initial_delay_min > initial_delay_max) { - const std::uint32_t tmp(initial_delay_min); - initial_delay_min = initial_delay_max; - initial_delay_max = tmp; - } - - std::random_device r; - std::mt19937 e(r()); - std::uniform_int_distribution<std::uint32_t> distribution( - initial_delay_min, initial_delay_max); - initial_delay_ = std::chrono::milliseconds(distribution(e)); - - - repetitions_base_delay_ = std::chrono::milliseconds( - its_configuration->get_sd_repetitions_base_delay()); - repetitions_max_ = its_configuration->get_sd_repetitions_max(); - cyclic_offer_delay_ = std::chrono::milliseconds( - its_configuration->get_sd_cyclic_offer_delay()); - offer_debounce_time_ = std::chrono::milliseconds( - its_configuration->get_sd_offer_debounce_time()); - ttl_timer_runtime_ = cyclic_offer_delay_ / 2; - - ttl_factor_offers_ = its_configuration->get_ttl_factor_offers(); - ttl_factor_subscriptions_ = its_configuration->get_ttl_factor_subscribes(); - last_msg_received_timer_timeout_ = cyclic_offer_delay_ - + (cyclic_offer_delay_ / 10); - } else { - VSOMEIP_ERROR << "SD: no configuration found!"; + unicast_ = configuration_->get_unicast_address(); + sd_multicast_ = configuration_->get_sd_multicast(); + boost::system::error_code ec; + sd_multicast_address_ = boost::asio::ip::address::from_string(sd_multicast_, ec); + + port_ = configuration_->get_sd_port(); + reliable_ = (configuration_->get_sd_protocol() == "tcp"); + max_message_size_ = (reliable_ ? VSOMEIP_MAX_TCP_SD_PAYLOAD : + VSOMEIP_MAX_UDP_SD_PAYLOAD); + + ttl_ = configuration_->get_sd_ttl(); + + // generate random initial delay based on initial delay min and max + std::int32_t initial_delay_min = + configuration_->get_sd_initial_delay_min(); + if (initial_delay_min < 0) { + initial_delay_min = VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MIN; + } + std::int32_t initial_delay_max = + configuration_->get_sd_initial_delay_max(); + if (initial_delay_max < 0) { + initial_delay_max = VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MAX; } + if (initial_delay_min > initial_delay_max) { + const std::uint32_t tmp(initial_delay_min); + initial_delay_min = initial_delay_max; + initial_delay_max = tmp; + } + + std::random_device r; + std::mt19937 e(r()); + std::uniform_int_distribution<std::uint32_t> distribution( + initial_delay_min, initial_delay_max); + initial_delay_ = std::chrono::milliseconds(distribution(e)); + + + repetitions_base_delay_ = std::chrono::milliseconds( + configuration_->get_sd_repetitions_base_delay()); + repetitions_max_ = configuration_->get_sd_repetitions_max(); + cyclic_offer_delay_ = std::chrono::milliseconds( + configuration_->get_sd_cyclic_offer_delay()); + offer_debounce_time_ = std::chrono::milliseconds( + configuration_->get_sd_offer_debounce_time()); + ttl_timer_runtime_ = cyclic_offer_delay_ / 2; + + ttl_factor_offers_ = configuration_->get_ttl_factor_offers(); + ttl_factor_subscriptions_ = configuration_->get_ttl_factor_subscribes(); + last_msg_received_timer_timeout_ = cyclic_offer_delay_ + + (cyclic_offer_delay_ / 10); } void service_discovery_impl::start() { @@ -300,7 +290,7 @@ void service_discovery_impl::subscribe(service_t _service, instance_t _instance, if (its_offer_type == remote_offer_type_e::UNRELIABLE && !its_subscription->get_endpoint(true) && its_subscription->get_endpoint(false)) { - if (its_subscription->get_endpoint(false)->is_connected()) { + if (its_subscription->get_endpoint(false)->is_established()) { insert_subscription(its_message, _service, _instance, _eventgroup, @@ -311,7 +301,7 @@ void service_discovery_impl::subscribe(service_t _service, instance_t _instance, } else if (its_offer_type == remote_offer_type_e::RELIABLE && its_subscription->get_endpoint(true) && !its_subscription->get_endpoint(false)) { - if (its_subscription->get_endpoint(true)->is_connected()) { + if (its_subscription->get_endpoint(true)->is_established()) { insert_subscription(its_message, _service, _instance, _eventgroup, @@ -322,17 +312,17 @@ void service_discovery_impl::subscribe(service_t _service, instance_t _instance, } else if (its_offer_type == remote_offer_type_e::RELIABLE_UNRELIABLE && its_subscription->get_endpoint(true) && its_subscription->get_endpoint(false)) { - if (its_subscription->get_endpoint(true)->is_connected() && - its_subscription->get_endpoint(false)->is_connected()) { + if (its_subscription->get_endpoint(true)->is_established() && + its_subscription->get_endpoint(false)->is_established()) { insert_subscription(its_message, _service, _instance, _eventgroup, its_subscription, its_offer_type); } else { - if (!its_subscription->get_endpoint(true)->is_connected()) { + if (!its_subscription->get_endpoint(true)->is_established()) { its_subscription->set_tcp_connection_established(false); } - if (!its_subscription->get_endpoint(false)->is_connected()) { + if (!its_subscription->get_endpoint(false)->is_established()) { its_subscription->set_udp_connection_established(false); } } @@ -446,13 +436,7 @@ void service_discovery_impl::unsubscribe_all(service_t _service, instance_t _ins if (found_service != subscribed_.end()) { auto found_instance = found_service->second.find(_instance); if (found_instance != found_service->second.end()) { - for (auto &its_eventgroup : found_instance->second) { - for (auto its_client : its_eventgroup.second) { - its_client.second->set_acknowledged(true); - its_client.second->set_endpoint(nullptr, true); - its_client.second->set_endpoint(nullptr, false); - } - } + found_instance->second.clear(); } } } @@ -813,11 +797,15 @@ void service_discovery_impl::insert_offer_entries( for (const auto its_service : _services) { for (const auto its_instance : its_service.second) { if ((!is_suspended_) - && ((!is_diagnosis_) || (is_diagnosis_ && !host_->get_configuration()->is_someip(its_service.first, its_instance.first)))) { + && ((!is_diagnosis_) + || (is_diagnosis_ + && !configuration_->is_someip(its_service.first, + its_instance.first)))) { // Only insert services with configured endpoint(s) if ((_ignore_phase || its_instance.second->is_in_mainphase()) && (its_instance.second->get_endpoint(false) - || its_instance.second->get_endpoint(true))) { + || its_instance.second->get_endpoint(true)) + && its_instance.second->get_ttl() > 0) { if (i >= _start) { if (!insert_offer_service(_message, its_service.first, its_instance.first, its_instance.second, its_size)) { @@ -935,8 +923,7 @@ bool service_discovery_impl::insert_nack_subscription_on_resubscribe(std::shared // Two entries: Stop subscribe & subscribe within one SD-Message // One option: Both entries reference it - const std::function<std::shared_ptr<eventgroupentry_impl>(ttl_t)> insert_entry - = [&](ttl_t _ttl) { + auto insert_entry = [&](ttl_t _ttl) { std::shared_ptr<eventgroupentry_impl> its_entry = _message->create_eventgroup_entry(); // SUBSCRIBE_EVENTGROUP and STOP_SUBSCRIBE_EVENTGROUP are identical @@ -955,7 +942,7 @@ bool service_discovery_impl::insert_nack_subscription_on_resubscribe(std::shared if (_offer_type == remote_offer_type_e::UNRELIABLE && !its_reliable_endpoint && its_unreliable_endpoint) { - if (its_unreliable_endpoint->is_connected()) { + if (its_unreliable_endpoint->is_established()) { const std::uint16_t its_port = its_unreliable_endpoint->get_local_port(); if (its_port) { std::shared_ptr<eventgroupentry_impl> its_stop_entry = insert_entry(0); @@ -975,7 +962,7 @@ bool service_discovery_impl::insert_nack_subscription_on_resubscribe(std::shared } } else if (_offer_type == remote_offer_type_e::RELIABLE && its_reliable_endpoint && !its_unreliable_endpoint) { - if (its_reliable_endpoint->is_connected()) { + if (its_reliable_endpoint->is_established()) { const std::uint16_t its_port = its_reliable_endpoint->get_local_port(); if (its_port) { std::shared_ptr<eventgroupentry_impl> its_stop_entry = insert_entry(0); @@ -995,8 +982,8 @@ bool service_discovery_impl::insert_nack_subscription_on_resubscribe(std::shared } } else if (_offer_type == remote_offer_type_e::RELIABLE_UNRELIABLE && its_reliable_endpoint && its_unreliable_endpoint) { - if (its_reliable_endpoint->is_connected() && - its_unreliable_endpoint->is_connected()) { + if (its_reliable_endpoint->is_established() && + its_unreliable_endpoint->is_established()) { const std::uint16_t its_reliable_port = its_reliable_endpoint->get_local_port(); const std::uint16_t its_unreliable_port = its_unreliable_endpoint->get_local_port(); if (its_reliable_port && its_unreliable_port) { @@ -1021,10 +1008,10 @@ bool service_discovery_impl::insert_nack_subscription_on_resubscribe(std::shared << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "]"; } } else { - if (!its_reliable_endpoint->is_connected()) { + if (!its_reliable_endpoint->is_established()) { _subscription->set_tcp_connection_established(false); } - if (!its_unreliable_endpoint->is_connected()) { + if (!its_unreliable_endpoint->is_established()) { _subscription->set_udp_connection_established(false); } } @@ -1127,6 +1114,7 @@ bool service_discovery_impl::send(bool _is_announcing) { its_message = its_runtime->create_message(); its_messages.push_back(its_message); + std::lock_guard<std::mutex> its_lock(offer_mutex_); services_t its_offers = host_->get_offered_services(); fill_message_with_offer_entries(its_runtime, its_message, its_messages, its_offers, false); @@ -1149,6 +1137,7 @@ void service_discovery_impl::on_message(const byte_t *_data, length_t _length, msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; VSOMEIP_INFO << msg.str(); #endif + std::lock_guard<std::mutex> its_lock(check_ttl_mutex_); std::lock_guard<std::mutex> its_session_lock(sessions_received_mutex_); if(is_suspended_) { @@ -1186,8 +1175,18 @@ void service_discovery_impl::on_message(const byte_t *_data, length_t _length, remove_remote_offer_type_by_ip(_sender); host_->expire_subscriptions(_sender); host_->expire_services(_sender); + if (reboot_notification_handler_) { + ip_address_t ip; + if (_sender.is_v4()) { + ip.address_.v4_ = _sender.to_v4().to_bytes(); + ip.is_v4_ = true; + } else { + ip.address_.v6_ = _sender.to_v6().to_bytes(); + ip.is_v4_ = false; + } + reboot_notification_handler_(ip); + } } - std::vector < std::shared_ptr<option_impl> > its_options = its_message->get_options(); @@ -1199,7 +1198,7 @@ void service_discovery_impl::on_message(const byte_t *_data, length_t _length, std::shared_ptr < message_impl > its_message_response = its_runtime->create_message(); - const std::uint8_t its_required_acks = + std::uint8_t its_required_acks = its_message->get_number_required_acks(); its_message_response->set_number_required_acks(its_required_acks); std::shared_ptr<sd_message_identifier_t> its_message_id = @@ -1215,27 +1214,66 @@ void service_discovery_impl::on_message(const byte_t *_data, length_t _length, const message_impl::entries_t::const_iterator its_end = its_entries.end(); bool is_stop_subscribe_subscribe(false); + bool offer_acceptance_queried(false); + bool accept_offers(false); + bool expired_services(false); + for (auto iter = its_entries.begin(); iter != its_end; iter++) { + if (!offer_acceptance_queried) { + if (offer_acceptance_handler_) { + ip_address_t ip; + if (configuration_->offer_acceptance_required(_sender)) { + if (_sender.is_v4()) { + ip.address_.v4_ = _sender.to_v4().to_bytes(); + ip.is_v4_ = true; + } else { + ip.address_.v6_ = _sender.to_v6().to_bytes(); + ip.is_v4_ = false; + } + accept_offers = offer_acceptance_handler_(ip); + if (!accept_offers && !expired_services) { + + VSOMEIP_INFO << "service_discovery_impl::on_message: Do not accept offer / subscribe from: " + << std::hex << std::setw(4) << std::setfill('0') << _sender.to_string(); + + remove_remote_offer_type_by_ip(_sender); + host_->expire_subscriptions(_sender); + host_->expire_services(_sender); + expired_services = true; + } + } else { + accept_offers = true; + } + offer_acceptance_queried = true; + } else { + offer_acceptance_queried = true; + accept_offers = true; + } + } if ((*iter)->is_service_entry()) { std::shared_ptr < serviceentry_impl > its_service_entry = std::dynamic_pointer_cast < serviceentry_impl > (*iter); bool its_unicast_flag = its_message->get_unicast_flag(); process_serviceentry(its_service_entry, its_options, - its_unicast_flag, &its_resubscribes); + its_unicast_flag, &its_resubscribes, accept_offers); } else { - std::shared_ptr < eventgroupentry_impl > its_eventgroup_entry = - std::dynamic_pointer_cast < eventgroupentry_impl - > (*iter); - bool force_initial_events(false); - if (is_stop_subscribe_subscribe) { - force_initial_events = true; + if (accept_offers) { + std::shared_ptr < eventgroupentry_impl > its_eventgroup_entry = + std::dynamic_pointer_cast < eventgroupentry_impl + > (*iter); + bool force_initial_events(false); + if (is_stop_subscribe_subscribe) { + force_initial_events = true; + } + is_stop_subscribe_subscribe = check_stop_subscribe_subscribe( + iter, its_end, its_message->get_options()); + process_eventgroupentry(its_eventgroup_entry, its_options, + its_message_response, _destination, + its_message_id, is_stop_subscribe_subscribe, force_initial_events); + } else { + its_required_acks = 0; } - is_stop_subscribe_subscribe = check_stop_subscribe_subscribe( - iter, its_end, its_message->get_options()); - process_eventgroupentry(its_eventgroup_entry, its_options, - its_message_response, _destination, - its_message_id, is_stop_subscribe_subscribe, force_initial_events); } } @@ -1283,7 +1321,8 @@ void service_discovery_impl::process_serviceentry( std::shared_ptr<serviceentry_impl> &_entry, const std::vector<std::shared_ptr<option_impl> > &_options, bool _unicast_flag, - std::vector<std::pair<std::uint16_t, std::shared_ptr<message_impl>>>* _resubscribes) { + std::vector<std::pair<std::uint16_t, std::shared_ptr<message_impl>>>* _resubscribes, + bool _accept_offers) { // Read service info from entry entry_type_e its_type = _entry->get_type(); @@ -1365,17 +1404,19 @@ void service_discovery_impl::process_serviceentry( its_major, its_minor, _unicast_flag); break; case entry_type_e::OFFER_SERVICE: - process_offerservice_serviceentry(its_service, its_instance, - its_major, its_minor, its_ttl, - its_reliable_address, its_reliable_port, - its_unreliable_address, its_unreliable_port, _resubscribes); + if (_accept_offers) { + process_offerservice_serviceentry(its_service, its_instance, + its_major, its_minor, its_ttl, + its_reliable_address, its_reliable_port, + its_unreliable_address, its_unreliable_port, _resubscribes); + } break; case entry_type_e::UNKNOWN: default: VSOMEIP_ERROR << "Unsupported serviceentry type"; } - } else { + } else if (_accept_offers) { std::shared_ptr<request> its_request = find_request(its_service, its_instance); if (its_request) { std::lock_guard<std::mutex> its_lock(requested_mutex_); @@ -1491,7 +1532,7 @@ void service_discovery_impl::process_offerservice_serviceentry( if (its_subscription->is_acknowledged()) { if (its_offer_type == remote_offer_type_e::UNRELIABLE) { - if (its_unreliable && its_unreliable->is_connected()) { + if (its_unreliable && its_unreliable->is_established()) { // 28 = 16 (subscription) + 12 (option) check_space(28); const std::size_t options_size_before = @@ -1514,7 +1555,7 @@ void service_discovery_impl::process_offerservice_serviceentry( } } } else if (its_offer_type == remote_offer_type_e::RELIABLE) { - if (its_reliable && its_reliable->is_connected()) { + if (its_reliable && its_reliable->is_established()) { // 28 = 16 (subscription) + 12 (option) check_space(28); const std::size_t options_size_before = @@ -1544,8 +1585,8 @@ void service_discovery_impl::process_offerservice_serviceentry( } } else if (its_offer_type == remote_offer_type_e::RELIABLE_UNRELIABLE) { if (its_reliable && its_unreliable && - its_reliable->is_connected() && - its_unreliable->is_connected()) { + its_reliable->is_established() && + its_unreliable->is_established()) { // 40 = 16 (subscription) + 2x12 (option) check_space(40); const std::size_t options_size_before = @@ -1566,7 +1607,7 @@ void service_discovery_impl::process_offerservice_serviceentry( static_cast<std::uint16_t>( _resubscribes->back().first - 40); } - } else if (its_reliable && !its_reliable->is_connected()) { + } else if (its_reliable && !its_reliable->is_established()) { its_client.second->set_tcp_connection_established(false); // restart TCP endpoint if not connected its_reliable->restart(); @@ -1597,7 +1638,7 @@ void service_discovery_impl::process_offerservice_serviceentry( } // restart TCP endpoint if not connected - if (its_reliable && !its_reliable->is_connected()) { + if (its_reliable && !its_reliable->is_established()) { its_reliable->restart(); } } @@ -1735,14 +1776,14 @@ void service_discovery_impl::on_endpoint_connected( its_subscription->get_endpoint(true)); const std::shared_ptr<const endpoint> its_unreliable_endpoint( its_subscription->get_endpoint(false)); - if(its_reliable_endpoint && its_reliable_endpoint->is_connected()) { + if(its_reliable_endpoint && its_reliable_endpoint->is_established()) { if(its_reliable_endpoint.get() == _endpoint.get()) { // mark tcp as established its_subscription->set_tcp_connection_established(true); } } - if(its_unreliable_endpoint && its_unreliable_endpoint->is_connected()) { - if(its_reliable_endpoint.get() == _endpoint.get()) { + if(its_unreliable_endpoint && its_unreliable_endpoint->is_established()) { + if(its_unreliable_endpoint.get() == _endpoint.get()) { // mark udp as established its_subscription->set_udp_connection_established(true); } @@ -2633,7 +2674,10 @@ void service_discovery_impl::serialize_and_send( _message->set_session(its_session.first); _message->set_reboot_flag(its_session.second); if(!serializer_->serialize(_message.get())) { - VSOMEIP_ERROR << "service_discovery_impl::serialize_and_send: serialization error."; + boost::system::error_code ec; + VSOMEIP_ERROR << "service_discovery_impl::serialize_and_send: serialization error." + << " Remote: " << _address.to_string(ec) << " session: 0x" + << std::hex << its_session.first; return; } if (host_->send_to(endpoint_definition::get(_address, port_, reliable_, _message->get_service(), _message->get_instance()), @@ -2660,7 +2704,10 @@ void service_discovery_impl::stop_ttl_timer() { void service_discovery_impl::check_ttl(const boost::system::error_code &_error) { if (!_error) { - host_->update_routing_info(ttl_timer_runtime_); + { + std::lock_guard<std::mutex> its_lock(check_ttl_mutex_); + host_->update_routing_info(ttl_timer_runtime_); + } start_ttl_timer(); } } @@ -2752,7 +2799,7 @@ void service_discovery_impl::send_subscriptions(service_t _service, instance_t _ = its_runtime->create_message(); if (its_reliable && its_unreliable) { - if (its_reliable->is_connected() && its_unreliable->is_connected()) { + if (its_reliable->is_established() && its_unreliable->is_established()) { insert_subscription(its_message, _service, _instance, found_eventgroup.first, found_client->second, its_offer_type); @@ -2764,7 +2811,7 @@ void service_discovery_impl::send_subscriptions(service_t _service, instance_t _ } } else { if(_reliable) { - if(endpoint->is_connected()) { + if(endpoint->is_established()) { insert_subscription(its_message, _service, _instance, found_eventgroup.first, found_client->second, its_offer_type); @@ -2775,7 +2822,7 @@ void service_discovery_impl::send_subscriptions(service_t _service, instance_t _ found_client->second->set_tcp_connection_established(false); } } else { - if (endpoint->is_connected()) { + if (endpoint->is_established()) { insert_subscription(its_message, _service, _instance, found_eventgroup.first, found_client->second, its_offer_type); @@ -2827,47 +2874,39 @@ void service_discovery_impl::stop_subscription_expiration_timer_unlocked() { void service_discovery_impl::expire_subscriptions(const boost::system::error_code &_error) { if (!_error) { - next_subscription_expiration_ = host_->expire_subscriptions(); + next_subscription_expiration_ = host_->expire_subscriptions(false); start_subscription_expiration_timer(); } } bool service_discovery_impl::check_ipv4_address( - boost::asio::ip::address its_address) { + const boost::asio::ip::address& its_address) const { //Check unallowed ipv4 address bool is_valid = true; - std::shared_ptr<configuration> its_configuration = - host_->get_configuration(); - - if(its_configuration) { - boost::asio::ip::address_v4::bytes_type its_unicast_address = - its_configuration.get()->get_unicast_address().to_v4().to_bytes(); - boost::asio::ip::address_v4::bytes_type endpoint_address = - its_address.to_v4().to_bytes(); - - //same address as unicast address of DUT not allowed - if(its_unicast_address - == endpoint_address) { - VSOMEIP_ERROR << "Subscribers endpoint IP address is same as DUT's address! : " - << its_address.to_string(); - is_valid = false; - } - - // first 3 triples must match - its_unicast_address[3] = 0x00; - endpoint_address[3] = 0x00; - if(its_unicast_address - != endpoint_address) { -#if 1 - VSOMEIP_ERROR<< "First 3 triples of subscribers endpoint IP address are not valid!"; -#endif + static const boost::asio::ip::address_v4::bytes_type its_unicast_address = + unicast_.to_v4().to_bytes(); + const boost::asio::ip::address_v4::bytes_type endpoint_address = + its_address.to_v4().to_bytes(); + static const boost::asio::ip::address_v4::bytes_type its_netmask = + configuration_->get_netmask().to_v4().to_bytes(); + + //same address as unicast address of DUT not allowed + if (its_unicast_address == endpoint_address) { + VSOMEIP_ERROR << "Subscriber's IP address is same as host's address! : " + << its_address; + is_valid = false; + } else { + const std::uint32_t self = VSOMEIP_BYTES_TO_LONG(its_unicast_address[0], + its_unicast_address[1], its_unicast_address[2], its_unicast_address[3]); + const std::uint32_t remote = VSOMEIP_BYTES_TO_LONG(endpoint_address[0], + endpoint_address[1], endpoint_address[2], endpoint_address[3]); + const std::uint32_t netmask = VSOMEIP_BYTES_TO_LONG(its_netmask[0], + its_netmask[1], its_netmask[2], its_netmask[3]); + if ((self & netmask) != (remote & netmask)) { + VSOMEIP_ERROR<< "Subscriber's IP isn't in the same subnet as host's IP: " + << its_address; is_valid = false; - - } else { -#if 0 - VSOMEIP_INFO << "First 3 triples of subscribers endpoint IP address are valid!"; -#endif } } return is_valid; @@ -3012,7 +3051,7 @@ void service_discovery_impl::on_offer_debounce_timer_expired( for (services_t::iterator its_service = collected_offers_.begin(); its_service != collected_offers_.end(); its_service++) { for (auto its_instance : its_service->second) { - if (!host_->get_configuration()->is_someip( + if (!configuration_->is_someip( its_service->first, its_instance.first)) { non_someip_services.push_back(its_service); } @@ -3286,6 +3325,8 @@ bool service_discovery_impl::serialize_and_send_messages( void service_discovery_impl::stop_offer_service( service_t _service, instance_t _instance, std::shared_ptr<serviceinfo> _info) { + std::lock_guard<std::mutex> its_lock(offer_mutex_); + _info->set_ttl(0); bool stop_offer_required(false); // delete from initial phase offers { @@ -3420,19 +3461,11 @@ bool service_discovery_impl::last_offer_shorter_half_offer_delay_ago() { bool service_discovery_impl::check_source_address( const boost::asio::ip::address &its_source_address) const { bool is_valid = true; - std::shared_ptr<configuration> its_configuration = - host_->get_configuration(); - - if(its_configuration) { - boost::asio::ip::address its_unicast_address = - its_configuration.get()->get_unicast_address(); - // check if source address is same as nodes unicast address - if(its_unicast_address - == its_source_address) { - VSOMEIP_ERROR << "Source address of message is same as DUT's unicast address! : " - << its_source_address.to_string(); - is_valid = false; - } + // check if source address is same as nodes unicast address + if(unicast_ == its_source_address) { + VSOMEIP_ERROR << "Source address of message is same as DUT's unicast address! : " + << its_source_address.to_string(); + is_valid = false; } return is_valid; } @@ -3502,8 +3535,10 @@ void service_discovery_impl::update_subscription_expiration_timer( const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); stop_subscription_expiration_timer_unlocked(); + + std::unique_lock<std::mutex> its_message_lock(_message->get_message_lock()); for (const auto &entry : _message->get_entries()) { - if (entry->get_type() == entry_type_e::SUBSCRIBE_EVENTGROUP_ACK + if (entry && entry->get_type() == entry_type_e::SUBSCRIBE_EVENTGROUP_ACK && entry->get_ttl()) { const std::chrono::steady_clock::time_point its_expiration = now + std::chrono::seconds( @@ -3792,5 +3827,15 @@ service_discovery_impl::get_eventgroups_requiring_initial_events( return its_acks; } +void service_discovery_impl::register_offer_acceptance_handler( + vsomeip::offer_acceptance_handler_t _handler) { + offer_acceptance_handler_ = _handler; +} + +void service_discovery_impl::register_reboot_notification_handler( + reboot_notification_handler_t _handler) { + reboot_notification_handler_ = _handler; +} + } // namespace sd } // namespace vsomeip diff --git a/implementation/tracing/include/channel_impl.hpp b/implementation/tracing/include/channel_impl.hpp new file mode 100644 index 0000000..9034657 --- /dev/null +++ b/implementation/tracing/include/channel_impl.hpp @@ -0,0 +1,62 @@ +// Copyright (C) 2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_TRACING_CHANNEL_IMPL_HPP_ +#define VSOMEIP_TRACING_CHANNEL_IMPL_HPP_ + +#include <atomic> +#include <functional> +#include <map> +#include <mutex> +#include <string> + +#include <vsomeip/trace.hpp> + +namespace vsomeip { +namespace trace { + +typedef std::function<bool (service_t, instance_t, method_t)> filter_func_t; + +class channel_impl : public channel { +public: + channel_impl(const std::string &_id, const std::string &_name); + + std::string get_id() const; + std::string get_name() const; + + filter_id_t add_filter( + const match_t &_match, + bool _is_positive); + + filter_id_t add_filter( + const std::vector<match_t> &_matches, + bool _is_positive); + + filter_id_t add_filter( + const match_t &_from, const match_t &_to, + bool _is_positive); + + void remove_filter( + filter_id_t _id); + + bool matches(service_t _service, instance_t _instance, method_t _method); + +private: + filter_id_t add_filter_intern(filter_func_t _func, bool _is_positive); + + std::string id_; + std::string name_; + + std::atomic<filter_id_t> current_filter_id_; + + std::map<filter_id_t, filter_func_t> positive_; + std::map<filter_id_t, filter_func_t> negative_; + std::mutex mutex_; // protects positive_ & negative_ +}; + +} // namespace trace +} // namespace vsomeip + +#endif // VSOMEIP_TRACING_CHANNEL_IMPL_HPP_ diff --git a/implementation/tracing/include/connector_impl.hpp b/implementation/tracing/include/connector_impl.hpp new file mode 100644 index 0000000..3234fed --- /dev/null +++ b/implementation/tracing/include/connector_impl.hpp @@ -0,0 +1,81 @@ +// 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/. + +#ifndef VSOMEIP_TC_TRACE_CONNECTOR_HPP +#define VSOMEIP_TC_TRACE_CONNECTOR_HPP + +#ifdef USE_DLT +#include <dlt/dlt.h> +#endif + +#include <mutex> +#include <vector> +#include <map> + +#include <boost/shared_ptr.hpp> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/export.hpp> +#include <vsomeip/trace.hpp> + +#include "enumeration_types.hpp" +#include "header.hpp" +#include "../../endpoints/include/buffer.hpp" + +namespace vsomeip { + +namespace cfg { + struct trace; +} + +namespace trace { + +class channel_impl; + +class connector_impl : public connector { +public: + VSOMEIP_EXPORT static std::shared_ptr<connector_impl> get(); + + VSOMEIP_EXPORT connector_impl(); + VSOMEIP_EXPORT virtual ~connector_impl(); + + VSOMEIP_EXPORT void configure(const std::shared_ptr<cfg::trace> &_configuration); + VSOMEIP_EXPORT void reset(); + + VSOMEIP_EXPORT void set_enabled(const bool _enabled); + VSOMEIP_EXPORT bool is_enabled() const; + + VSOMEIP_EXPORT void set_sd_enabled(const bool _sd_enabled); + VSOMEIP_EXPORT bool is_sd_enabled() const; + + VSOMEIP_EXPORT bool is_sd_message(const byte_t *_data, uint16_t _data_size) const; + + VSOMEIP_EXPORT std::shared_ptr<channel> add_channel(const std::string &_id, + const std::string &_description); + VSOMEIP_EXPORT bool remove_channel(const std::string &_id); + VSOMEIP_EXPORT std::shared_ptr<channel> get_channel(const std::string &_id) const; + + VSOMEIP_EXPORT void trace(const byte_t *_header, uint16_t _header_size, + const byte_t *_data, uint16_t _data_size); + +private: + bool is_enabled_; + bool is_sd_enabled_; + bool is_initialized_; + + std::map<std::string, std::shared_ptr<channel_impl>> channels_; + mutable std::mutex channels_mutex_; + +#ifdef USE_DLT + std::map<std::string, std::shared_ptr<DltContext>> contexts_; + mutable std::mutex contexts_mutex_; +#endif + +}; + +} // namespace trace +} // namespace vsomeip + +#endif // VSOMEIP_TC_TRACE_CONNECTOR_HPP diff --git a/implementation/tracing/include/defines.hpp b/implementation/tracing/include/defines.hpp index aadb44f..2325259 100644 --- a/implementation/tracing/include/defines.hpp +++ b/implementation/tracing/include/defines.hpp @@ -7,7 +7,9 @@ #define TRACING_INCLUDE_DEFINES_HPP_ #define VSOMEIP_TC_DEFAULT_CHANNEL_NAME "Trace Connector Network Logging" -#define VSOMEIP_TC_DEFAULT_CHANNEL_ID "TC" #define VSOMEIP_TC_DEFAULT_FILTER_TYPE "positive" +#define VSOMEIP_TC_INSTANCE_POS_MIN 8 +#define VSOMEIP_TC_INSTANCE_POS_MAX 9 + #endif /* TRACING_INCLUDE_DEFINES_HPP_ */ diff --git a/implementation/tracing/include/enumeration_types.hpp b/implementation/tracing/include/enumeration_types.hpp index 82ed3c4..352ddd3 100644 --- a/implementation/tracing/include/enumeration_types.hpp +++ b/implementation/tracing/include/enumeration_types.hpp @@ -3,24 +3,18 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -#ifndef VSOMEIP_TC_ENUMERATION_TYPES_HPP -#define VSOMEIP_TC_ENUMERATION_TYPES_HPP +#ifndef VSOMEIP_TRACE_ENUMERATION_TYPES_HPP +#define VSOMEIP_TRACE_ENUMERATION_TYPES_HPP namespace vsomeip { -namespace tc { - -enum class filter_criteria_e : uint8_t { - SERVICES = 0x00, - METHODS = 0x01, - CLIENTS = 0x02, -}; +namespace trace { enum class filter_type_e : uint8_t { NEGATIVE = 0x00, POSITIVE = 0x01 }; -} // namespace tc +} // namespace trace } // namespace vsomeip #endif // VSOMEIP_TC_ENUMERATION_TYPES_HPP diff --git a/implementation/tracing/include/trace_header.hpp b/implementation/tracing/include/header.hpp index 11ccbdd..55ec73e 100644 --- a/implementation/tracing/include/trace_header.hpp +++ b/implementation/tracing/include/header.hpp @@ -3,8 +3,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -#ifndef VSOMEIP_TC_TRACE_HEADER_HPP -#define VSOMEIP_TC_TRACE_HEADER_HPP +#ifndef VSOMEIP_TRACE_HEADER_HPP +#define VSOMEIP_TRACE_HEADER_HPP #include <memory> @@ -18,7 +18,7 @@ namespace vsomeip { class endpoint; -namespace tc { +namespace trace { enum class protocol_e : uint8_t { local = 0x0, @@ -27,7 +27,7 @@ enum class protocol_e : uint8_t { unknown = 0xFF }; -struct trace_header { +struct header { bool prepare(const std::shared_ptr<endpoint> &_endpoint, bool _is_sending, instance_t _instance); bool prepare(const endpoint* _endpoint, bool _is_sending, @@ -39,7 +39,7 @@ struct trace_header { byte_t data_[VSOMEIP_TRACE_HEADER_SIZE]; }; -} // namespace tc +} // namespace trace } // namespace vsomeip -#endif // VSOMEIP_TC_TRACE_HEADER_HPP +#endif // VSOMEIP_TRACE_HEADER_HPP diff --git a/implementation/tracing/include/trace_connector.hpp b/implementation/tracing/include/trace_connector.hpp deleted file mode 100644 index ef36e29..0000000 --- a/implementation/tracing/include/trace_connector.hpp +++ /dev/null @@ -1,107 +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/. - -#ifndef VSOMEIP_TC_TRACE_CONNECTOR_HPP -#define VSOMEIP_TC_TRACE_CONNECTOR_HPP - -#include <vsomeip/primitive_types.hpp> -#include <vsomeip/export.hpp> -#include <boost/shared_ptr.hpp> -#include <mutex> -#include <vector> -#include <map> - -#ifdef USE_DLT -#include <dlt/dlt.h> -#endif - -#include "enumeration_types.hpp" -#include "trace_header.hpp" -#include "../../endpoints/include/buffer.hpp" - -namespace vsomeip -{ -namespace tc -{ - -class trace_connector { -public: - typedef uint16_t filter_expression_t; - typedef std::vector<filter_expression_t> filter_expressions_t; - typedef std::map<filter_criteria_e, filter_expressions_t> filter_rule_map_t; - typedef std::pair<filter_type_e, filter_rule_map_t> filter_rule_t; - - typedef std::map<trace_channel_t, std::string> channels_t; - typedef std::map<trace_channel_t, filter_rule_t> filter_rules_t; - -#ifdef USE_DLT - typedef std::map<trace_channel_t, DltContext*> dlt_contexts_t; -#endif - - VSOMEIP_EXPORT static std::shared_ptr<trace_connector> get(); - - VSOMEIP_EXPORT trace_connector(); - VSOMEIP_EXPORT virtual ~trace_connector(); - - VSOMEIP_EXPORT void init(); - VSOMEIP_EXPORT void reset(); - - VSOMEIP_EXPORT void set_enabled(const bool _enabled); - VSOMEIP_EXPORT bool is_enabled() const; - - VSOMEIP_EXPORT void set_sd_enabled(const bool _enabled); - VSOMEIP_EXPORT bool is_sd_enabled() const; - - VSOMEIP_EXPORT bool is_sd_message(const byte_t *_data, uint16_t _data_size) const; - - VSOMEIP_EXPORT bool add_channel(const trace_channel_t &_id,const std::string &_name); - VSOMEIP_EXPORT bool remove_channel(const trace_channel_t &_id); - - VSOMEIP_EXPORT bool add_filter_rule(const trace_channel_t &_channel_id, - const filter_rule_t _filter_rule); - VSOMEIP_EXPORT bool add_filter_expression(const trace_channel_t &_channel_id, - const filter_criteria_e _criteria, - const filter_expression_t _expression); - VSOMEIP_EXPORT bool change_filter_expressions(const trace_channel_t &_channel_id, - const filter_criteria_e _criteria, - const filter_expressions_t _expressions); - VSOMEIP_EXPORT bool remove_filter_rule(const trace_channel_t &_channel_id); - - VSOMEIP_EXPORT void trace(const byte_t *_header, uint16_t _header_size, - const byte_t *_data, uint16_t _data_size); - - VSOMEIP_EXPORT channels_t get_channels(); - VSOMEIP_EXPORT filter_rules_t get_filter_rules(); - VSOMEIP_EXPORT filter_rule_t get_filter_rule(const trace_channel_t &_channel_id); - -private: - - bool apply_filter_rules(const byte_t *_data, const uint16_t _data_size, - std::vector<trace_channel_t> &_send_msg_over_channels); - - bool filter_expressions_match(const filter_criteria_e _criteria, - const filter_expressions_t _expressions, - const byte_t *_data, const uint16_t _data_size); - - bool is_enabled_; - bool is_sd_enabled_; - bool is_initialized_; - - channels_t channels_; - filter_rules_t filter_rules_; - -#ifdef USE_DLT - dlt_contexts_t dlt_contexts_; -#endif - - std::mutex channels_mutex_; - std::mutex filter_rules_mutex_; - std::mutex dlt_contexts_mutex; -}; - -} // namespace tc -} // namespace vsomeip - -#endif // VSOMEIP_TC_TRACE_CONNECTOR_HPP diff --git a/implementation/tracing/src/channel_impl.cpp b/implementation/tracing/src/channel_impl.cpp new file mode 100644 index 0000000..58f67e6 --- /dev/null +++ b/implementation/tracing/src/channel_impl.cpp @@ -0,0 +1,273 @@ +// Copyright (C) 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 "../include/channel_impl.hpp" +#include "../../logging/include/logger.hpp" + +namespace vsomeip { +namespace trace { + +const filter_id_t FILTER_ID_ERROR(0); + +channel_impl::channel_impl(const std::string &_id, const std::string &_name) + : id_(_id), name_(_name), current_filter_id_(1) { +} + +std::string channel_impl::get_id() const { + return id_; +} + +std::string channel_impl::get_name() const { + return name_; +} + +filter_id_t channel_impl::add_filter( + const match_t &_match, bool _is_positive) { + + // Create a filter function + std::function<bool (service_t, instance_t, method_t)> its_filter_func; + if (std::get<0>(_match) != ANY_SERVICE) { + if (std::get<1>(_match) != ANY_INSTANCE) { + if (std::get<2>(_match) != ANY_METHOD) { + its_filter_func + = [_match](service_t _s, instance_t _i, method_t _m) { + return (std::get<0>(_match) == _s + && std::get<1>(_match) == _i + && std::get<2>(_match) == _m); + }; + } else { + its_filter_func + = [_match](service_t _s, instance_t _i, method_t) { + return (std::get<0>(_match) == _s + && std::get<1>(_match) == _i); + }; + } + } else { + if (std::get<2>(_match) != ANY_METHOD) { + its_filter_func + = [_match](service_t _s, instance_t, method_t _m) { + return (std::get<0>(_match) == _s + && std::get<1>(_match) == _m); + }; + } else { + its_filter_func + = [_match](service_t _s, instance_t, method_t) { + return (std::get<0>(_match) == _s); + }; + } + } + } else { + if (std::get<1>(_match) != ANY_INSTANCE) { + if (std::get<2>(_match) != ANY_METHOD) { + its_filter_func + = [_match](service_t, instance_t _i, method_t _m) { + return (std::get<1>(_match) == _i + && std::get<2>(_match) == _m); + }; + } else { + its_filter_func + = [_match](service_t, instance_t _i, method_t) { + return (std::get<1>(_match) == _i); + }; + } + } else { + if (std::get<2>(_match) != ANY_METHOD) { + its_filter_func + = [_match](service_t, instance_t, method_t _m) { + return (std::get<2>(_match) == _m); + }; + } else { + its_filter_func + = [](service_t, instance_t, method_t) { + return true; + }; + } + } + } + + return add_filter_intern(its_filter_func, _is_positive); +} + +filter_id_t channel_impl::add_filter( + const std::vector<match_t> &_matches, bool _is_positive) { + bool has_service(false); + bool has_instance(false); + bool has_method(false); + + for (auto m : _matches) { + if (std::get<0>(m) != ANY_SERVICE) has_service = true; + if (std::get<1>(m) != ANY_INSTANCE) has_instance = true; + if (std::get<2>(m) != ANY_METHOD) has_method = true; + } + + // Create a filter function + std::function<bool (service_t, instance_t, method_t)> its_filter_func; + if (has_service) { + if (has_instance) { + if (has_method) { + its_filter_func + = [_matches](service_t _s, instance_t _i, method_t _m) { + for (const auto &m : _matches) { + if ((std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE) + && (std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE) + && (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD)) { + return true; + } + } + return false; + }; + } else { + its_filter_func + = [_matches](service_t _s, instance_t _i, method_t) { + for (const auto &m : _matches) { + if ((std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE) + && (std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE)) { + return true; + } + } + return false; + }; + } + } else { + if (has_method) { + its_filter_func + = [_matches](service_t _s, instance_t, method_t _m) { + for (const auto &m : _matches) { + if ((std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE) + && (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD)) { + return true; + } + } + return false; + }; + } else { + its_filter_func + = [_matches](service_t _s, instance_t, method_t) { + for (auto &m : _matches) { + if (std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE) { + return true; + } + } + return false; + }; + } + } + } else { + if (has_instance) { + if (has_method) { + its_filter_func + = [_matches](service_t, instance_t _i, method_t _m) { + for (auto &m : _matches) { + if ((std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE) + && (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD)) { + return true; + } + } + return false; + }; + } else { + its_filter_func + = [_matches](service_t, instance_t _i, method_t) { + for (auto &m : _matches) { + if (std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE) { + return true; + } + } + return false; + }; + } + } else { + if (has_method) { + its_filter_func + = [_matches](service_t, instance_t, method_t _m) { + for (auto &m : _matches) { + if (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD) { + return true; + } + } + return false; + }; + } else { + its_filter_func + = [](service_t, instance_t, method_t) { + return true; + }; + } + } + } + + return add_filter_intern(its_filter_func, _is_positive); +} + +filter_id_t channel_impl::add_filter( + const match_t &_from, const match_t &_to, bool _is_positive) { + + // Check usage of ANY_* which is forbidden here + if (std::get<0>(_from) == ANY_SERVICE || + std::get<1>(_from) == ANY_INSTANCE || + std::get<2>(_from) == ANY_METHOD || + std::get<0>(_to) == ANY_SERVICE || + std::get<1>(_to) == ANY_INSTANCE || + std::get<2>(_to) == ANY_METHOD) { + VSOMEIP_ERROR << "Trace filter configuration error: " + "You must not use wildcards in range filters."; + return FILTER_ID_ERROR; + } + + std::function<bool (service_t, instance_t, method_t)> its_filter_func + = [_from, _to](service_t _s, instance_t _i, method_t _m) { + return (std::get<0>(_from) <= _s && _s <= std::get<0>(_to) + && std::get<1>(_from) <= _i && _i <= std::get<1>(_to) + && std::get<2>(_from) <= _m && _m <= std::get<2>(_to)); + }; + + return add_filter_intern(its_filter_func, _is_positive); +} + +void channel_impl::remove_filter(filter_id_t _id) { + std::lock_guard<std::mutex> its_lock(mutex_); + positive_.erase(_id); + negative_.erase(_id); +} + +filter_id_t channel_impl::add_filter_intern(filter_func_t _func, bool _is_positive) { + filter_id_t its_id = current_filter_id_.fetch_add(1); + + std::lock_guard<std::mutex> its_lock(mutex_); + if (_is_positive) + positive_[its_id] = _func; + else + negative_[its_id] = _func; + + return its_id; +} + +bool channel_impl::matches( + service_t _service, instance_t _instance, method_t _method) { + std::lock_guard<std::mutex> its_lock(mutex_); + + // If a negative filter matches --> drop! + for (auto &its_filter : negative_) { + if (its_filter.second(_service, _instance, _method)) { + return false; + } + } + + // If no positive filter is defined --> forward! + if (positive_.size() == 0) + return true; + + // If a positive filter matches --> forward! + for (auto &its_filter : positive_) { + if (its_filter.second(_service, _instance, _method)) { + return true; + } + } + + // drop! + return false; +} + +} // namespace trace +} // namespace vsomeip diff --git a/implementation/tracing/src/connector_impl.cpp b/implementation/tracing/src/connector_impl.cpp new file mode 100644 index 0000000..f8655db --- /dev/null +++ b/implementation/tracing/src/connector_impl.cpp @@ -0,0 +1,226 @@ +// 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 <vsomeip/constants.hpp> + +#include "../include/channel_impl.hpp" +#include "../include/connector_impl.hpp" +#include "../include/defines.hpp" +#include "../../configuration/include/internal.hpp" +#include "../../configuration/include/trace.hpp" +#include "../../logging/include/logger.hpp" +#include "../../utility/include/byteorder.hpp" + +namespace vsomeip { +namespace trace { + +const char *VSOMEIP_TC_DEFAULT_CHANNEL_ID = "TC"; + +std::shared_ptr<connector_impl> connector_impl::get() { + static std::shared_ptr<connector_impl> instance = std::make_shared<connector_impl>(); + return instance; +} + +connector_impl::connector_impl() : + is_enabled_(false), + is_sd_enabled_(false), + is_initialized_(false) { + + channels_[VSOMEIP_TC_DEFAULT_CHANNEL_ID] + = std::make_shared<channel_impl>(VSOMEIP_TC_DEFAULT_CHANNEL_ID, + VSOMEIP_TC_DEFAULT_CHANNEL_NAME); +#ifdef USE_DLT + std::shared_ptr<DltContext> its_default_context + = std::make_shared<DltContext>(); + + contexts_[VSOMEIP_TC_DEFAULT_CHANNEL_ID] = its_default_context; + DLT_REGISTER_CONTEXT_LL_TS(*(its_default_context.get()), + VSOMEIP_TC_DEFAULT_CHANNEL_ID, VSOMEIP_TC_DEFAULT_CHANNEL_NAME, + DLT_LOG_INFO, DLT_TRACE_STATUS_ON); +#endif +} + +connector_impl::~connector_impl() { + reset(); +} + +void connector_impl::configure(const std::shared_ptr<cfg::trace> &_configuration) { + if (_configuration) { + is_enabled_ = _configuration->is_enabled_; + is_sd_enabled_ = _configuration->is_sd_enabled_; + } + + if (is_enabled_) { // No need to create filters if tracing is disabled! + for (auto &its_channel : _configuration->channels_) { + if (!add_channel(its_channel->id_, its_channel->name_)) { + VSOMEIP_ERROR << "Channel " << its_channel->id_ + << " has multiple definitions."; + } + } + + for (auto &its_filter : _configuration->filters_) { + for (auto &its_channel : its_filter->channels_) { + std::shared_ptr<channel> its_channel_ptr = get_channel(its_channel); + if (its_channel_ptr) { + if (its_filter->is_range_) { + its_channel_ptr->add_filter(its_filter->matches_[0], + its_filter->matches_[1], its_filter->is_positive_); + } else { + its_channel_ptr->add_filter(its_filter->matches_, + its_filter->is_positive_); + } + } + } + } + } + + VSOMEIP_INFO << "vsomeip tracing " + << (is_enabled_ ? "enabled " : "not enabled. ") + << ". vsomeip service discovery tracing " + << (is_sd_enabled_ ? "enabled " : "not enabled. "); +} + +void connector_impl::reset() { +#ifdef USE_DLT + std::lock_guard<std::mutex> its_contexts_lock(contexts_mutex_); + contexts_.clear(); +#endif + // reset to default + std::lock_guard<std::mutex> its_lock_channels(channels_mutex_); + channels_.clear(); +} + +void connector_impl::set_enabled(const bool _enabled) { + is_enabled_ = _enabled; +} + +bool connector_impl::is_enabled() const { + return is_enabled_; +} + +void connector_impl::set_sd_enabled(const bool _sd_enabled) { + is_sd_enabled_ = _sd_enabled; +} + +bool connector_impl::is_sd_enabled() const { + return is_sd_enabled_; +} + +bool connector_impl::is_sd_message(const byte_t *_data, uint16_t _data_size) const { + if (VSOMEIP_METHOD_POS_MAX < _data_size) { + return (_data[VSOMEIP_SERVICE_POS_MIN] == 0xFF && _data[VSOMEIP_SERVICE_POS_MAX] == 0xFF && + _data[VSOMEIP_METHOD_POS_MIN] == 0x81 && _data[VSOMEIP_METHOD_POS_MAX] == 0x00); + } + return false; +} + +std::shared_ptr<channel> connector_impl::add_channel( + const trace_channel_t &_id, const std::string &_name) { + std::lock_guard<std::mutex> its_channels_lock(channels_mutex_); + + // check whether we already know the requested channel + if (channels_.find(_id) != channels_.end()) + return nullptr; + + // create new channel + std::shared_ptr<channel_impl> its_channel + = std::make_shared<channel_impl>(_id, _name); + + // add channel + channels_[_id] = its_channel; + + // register context +#ifdef USE_DLT + std::lock_guard<std::mutex> its_contexts_lock(contexts_mutex_); + std::shared_ptr<DltContext> its_context = std::make_shared<DltContext>(); + contexts_[_id] = its_context; + DLT_REGISTER_CONTEXT_LL_TS(*(its_context.get()), _id.c_str(), _name.c_str(), + DLT_LOG_INFO, DLT_TRACE_STATUS_ON); +#endif + + return its_channel; +} + +bool connector_impl::remove_channel(const trace_channel_t &_id) { + if (_id == VSOMEIP_TC_DEFAULT_CHANNEL_ID) { + // the default channel can not be removed + return false; + } + + std::lock_guard<std::mutex> its_channels_lock(channels_mutex_); + bool has_removed = (channels_.erase(_id) == 1); + if (has_removed) { + // unregister context +#ifdef USE_DLT + std::lock_guard<std::mutex> its_contexts_lock(contexts_mutex_); + auto its_context = contexts_.find(_id); + if (its_context != contexts_.end()) { + DLT_UNREGISTER_CONTEXT(*(its_context->second.get())); + } +#endif + } + + return true; +} + +std::shared_ptr<channel> connector_impl::get_channel(const std::string &_id) const { + std::lock_guard<std::mutex> its_channels_lock(channels_mutex_); + auto its_channel = channels_.find(_id); + return (its_channel != channels_.end() ? its_channel->second : nullptr); +} + +void connector_impl::trace(const byte_t *_header, uint16_t _header_size, + const byte_t *_data, uint16_t _data_size) { +#ifdef USE_DLT + if (!is_enabled_) + return; + + if (_data_size == 0) + return; // no data + + if (is_sd_message(_data, _data_size) && !is_sd_enabled_) + return; // tracing of service discovery messages is disabled! + + service_t its_service = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_SERVICE_POS_MIN], + _data[VSOMEIP_SERVICE_POS_MAX]); + + // Instance is not part of the SOME/IP header, read it from the trace + // header + instance_t its_instance = VSOMEIP_BYTES_TO_WORD( + _header[VSOMEIP_TC_INSTANCE_POS_MIN], + _header[VSOMEIP_TC_INSTANCE_POS_MAX]); + + method_t its_method = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_METHOD_POS_MIN], + _data[VSOMEIP_METHOD_POS_MAX]); + + // Forward to channel if the filter set of the channel allows + std::lock_guard<std::mutex> its_channels_lock(channels_mutex_); + std::lock_guard<std::mutex> its_contexts_lock(contexts_mutex_); + for (auto its_channel : channels_) { + if (its_channel.second->matches(its_service, its_instance, its_method)) { + auto its_context = contexts_.find(its_channel.second->get_id()); + if (its_context != contexts_.end()) { + DLT_TRACE_NETWORK_SEGMENTED(*(its_context->second.get()), + DLT_NW_TRACE_IPC, + _header_size, static_cast<void *>(const_cast<byte_t *>(_header)), + _data_size, static_cast<void *>(const_cast<byte_t *>(_data))); + } else { + // This should never happen! + VSOMEIP_ERROR << "tracing: found channel without DLT context!"; + } + } + } +#else + (void)_header; + (void)_header_size; + (void)_data; + (void)_data_size; +#endif +} + +} // namespace trace +} // namespace vsomeip diff --git a/implementation/tracing/src/trace_header.cpp b/implementation/tracing/src/header.cpp index 3ae1b10..2f4f3f8 100644 --- a/implementation/tracing/src/trace_header.cpp +++ b/implementation/tracing/src/header.cpp @@ -5,20 +5,20 @@ #include <cstring> -#include "../include/trace_header.hpp" +#include "../include/header.hpp" #include "../../endpoints/include/endpoint.hpp" #include "../../endpoints/include/client_endpoint.hpp" #include "../../utility/include/byteorder.hpp" namespace vsomeip { -namespace tc { +namespace trace { -bool trace_header::prepare(const std::shared_ptr<endpoint> &_endpoint, +bool header::prepare(const std::shared_ptr<endpoint> &_endpoint, bool _is_sending, instance_t _instance) { return prepare(_endpoint.get(), _is_sending, _instance); } -bool trace_header::prepare(const endpoint *_endpoint, bool _is_sending, +bool header::prepare(const endpoint *_endpoint, bool _is_sending, instance_t _instance) { boost::asio::ip::address its_address; unsigned short its_port(0); @@ -51,9 +51,9 @@ bool trace_header::prepare(const endpoint *_endpoint, bool _is_sending, return true; } -void trace_header::prepare(const boost::asio::ip::address_v4 &_address, - std::uint16_t _port, protocol_e _protocol, - bool _is_sending, instance_t _instance) { +void header::prepare(const boost::asio::ip::address_v4 &_address, + std::uint16_t _port, protocol_e _protocol, + bool _is_sending, instance_t _instance) { unsigned long its_address_as_long = _address.to_ulong(); data_[0] = VSOMEIP_LONG_BYTE3(its_address_as_long); data_[1] = VSOMEIP_LONG_BYTE2(its_address_as_long); @@ -67,5 +67,5 @@ void trace_header::prepare(const boost::asio::ip::address_v4 &_address, data_[9] = VSOMEIP_WORD_BYTE0(_instance); } -} // namespace tc +} // namespace trace } // namespace vsomeip diff --git a/implementation/tracing/src/trace_connector.cpp b/implementation/tracing/src/trace_connector.cpp deleted file mode 100644 index 93f7d6e..0000000 --- a/implementation/tracing/src/trace_connector.cpp +++ /dev/null @@ -1,381 +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 "../include/trace_connector.hpp" - -#include <vsomeip/constants.hpp> - -#include "../include/defines.hpp" -#include "../../configuration/include/internal.hpp" - -namespace vsomeip { -namespace tc { - -std::shared_ptr<trace_connector> trace_connector::get() { - static std::shared_ptr<trace_connector> instance = std::make_shared<trace_connector>(); - return instance; -} - -trace_connector::trace_connector() : - is_enabled_(false), - is_sd_enabled_(false), - is_initialized_(false), - channels_(), - filter_rules_() - { - channels_.insert(std::make_pair(VSOMEIP_TC_DEFAULT_CHANNEL_ID, VSOMEIP_TC_DEFAULT_CHANNEL_NAME)); -} - -trace_connector::~trace_connector() { - reset(); -} - -void trace_connector::init() { -#ifdef USE_DLT - if(!is_initialized_) { - // register channels/contexts - std::lock_guard<std::mutex> lock(dlt_contexts_mutex); - for(auto it = channels_.begin(); it != channels_.end(); ++it) { - DltContext *dlt_context = new DltContext(); - dlt_contexts_.insert(std::make_pair(it->first, dlt_context)); - DLT_REGISTER_CONTEXT_LL_TS(*dlt_context, it->first.c_str(), it->second.c_str(), DLT_LOG_INFO, DLT_TRACE_STATUS_ON); - } - } -#endif - is_initialized_ = true; -} - -void trace_connector::reset() { - std::lock_guard<std::mutex> its_lock_channels(channels_mutex_); - std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_); - std::lock_guard<std::mutex> its_lock_dlt_contexts(dlt_contexts_mutex); - -#ifdef USE_DLT - // unregister channels/contexts - for(auto it = dlt_contexts_.begin(); it != dlt_contexts_.end(); ++it) { - DLT_UNREGISTER_CONTEXT(*it->second); - delete it->second; - } - dlt_contexts_.clear(); -#endif - - // reset to default - - channels_.clear(); - channels_.insert(std::make_pair(VSOMEIP_TC_DEFAULT_CHANNEL_ID, VSOMEIP_TC_DEFAULT_CHANNEL_NAME)); - - filter_rules_.clear(); - - is_initialized_ = false; -} - -void trace_connector::set_enabled(const bool _enabled) { - is_enabled_ = _enabled; -} - -bool trace_connector::is_enabled() const { - return is_enabled_; -} - -void trace_connector::set_sd_enabled(const bool _sd_enabled) { - is_sd_enabled_ = _sd_enabled; -} - -bool trace_connector::is_sd_enabled() const { - return is_sd_enabled_; -} - -bool trace_connector::is_sd_message(const byte_t *_data, uint16_t _data_size) const { - if (VSOMEIP_METHOD_POS_MAX < _data_size) { - return (_data[VSOMEIP_SERVICE_POS_MIN] == 0xFF && _data[VSOMEIP_SERVICE_POS_MAX] == 0xFF && - _data[VSOMEIP_METHOD_POS_MIN] == 0x81 && _data[VSOMEIP_METHOD_POS_MAX] == 0x00); - } - return false; -} - -bool trace_connector::add_channel(const trace_channel_t &_id, const std::string &_name) { - std::lock_guard<std::mutex> its_lock_channels(channels_mutex_); - std::lock_guard<std::mutex> its_lock_dlt_contexts(dlt_contexts_mutex); - - bool channel_inserted = false; - bool dlt_context_registered = false; - - // add channel - channel_inserted = channels_.insert(std::make_pair(_id, _name)).second; - - // register context -#ifdef USE_DLT - if(channel_inserted) { - DltContext *dlt_context = new DltContext(); - dlt_context_registered = dlt_contexts_.insert(std::make_pair(_id, dlt_context)).second; - DLT_REGISTER_CONTEXT_LL_TS(*dlt_context, _id.c_str(), _name.c_str(), DLT_LOG_INFO, DLT_TRACE_STATUS_ON); - } -#endif - - return (channel_inserted && dlt_context_registered); -} - -bool trace_connector::remove_channel(const trace_channel_t &_id) { - - if(_id == VSOMEIP_TC_DEFAULT_CHANNEL_ID) { - // the default channel can not be removed - return false; - } - - std::lock_guard<std::mutex> its_lock_channels(channels_mutex_); - std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_); - std::lock_guard<std::mutex> its_lock_dlt_contexts(dlt_contexts_mutex); - - bool channel_removed = false; - bool dlt_context_unregistered = false; - - // remove channel - channel_removed = (channels_.erase(_id) == 1); - if(channel_removed) { - - // unregister context -#ifdef USE_DLT - auto it = dlt_contexts_.find(_id); - if(it != dlt_contexts_.end()) { - DltContext *dlt_context = it->second; - DLT_UNREGISTER_CONTEXT(*dlt_context); - dlt_context_unregistered = true; - } -#endif - - // remove filter - filter_rules_.erase(_id); - } - return (channel_removed && dlt_context_unregistered); -} - -bool trace_connector::add_filter_rule(const trace_channel_t &_channel_id, - const filter_rule_t _filter_rule) { - std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_); - std::lock_guard<std::mutex> its_lock_channels(channels_mutex_); - - // find channel - auto it = channels_.find(_channel_id); - if(it != channels_.end()) { - // add filter rule - return filter_rules_.insert(std::make_pair(_channel_id, _filter_rule)).second; - } - return false; -} - -bool trace_connector::add_filter_expression(const trace_channel_t &_channel_id, - const filter_criteria_e _criteria, - const filter_expression_t _expression) { - std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_); - - // find filter rule - auto it_filter_rules = filter_rules_.find(_channel_id); - if(it_filter_rules != filter_rules_.end()) { - filter_rule_t its_filter_rule = it_filter_rules->second; - - // find filter criteria - auto it_filter_rule_map = its_filter_rule.second.find(_criteria); - if(it_filter_rule_map != its_filter_rule.second.end()) { - // add expression - it_filter_rule_map->second.push_back(_expression); - return true; - } - } - return false; -} - -bool trace_connector::change_filter_expressions(const trace_channel_t &_channel_id, - const filter_criteria_e _criteria, - const filter_expressions_t _expressions) { - std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_); - - // find filter rule - auto it_filter_rules = filter_rules_.find(_channel_id); - if(it_filter_rules != filter_rules_.end()) { - filter_rule_t its_filter_rule = it_filter_rules->second; - - // find filter criteria - auto it_filter_rule_map = its_filter_rule.second.find(_criteria); - if(it_filter_rule_map != its_filter_rule.second.end()) { - // change expressions - it_filter_rule_map->second = _expressions; - return true; - } - } - return false; -} - -bool trace_connector::remove_filter_rule(const trace_channel_t &_channel_id) { - std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_); - - auto it = filter_rules_.find(_channel_id); - if(it != filter_rules_.end()) { - return (filter_rules_.erase(_channel_id) == 1); - } - return false; -} - -void trace_connector::trace(const byte_t *_header, uint16_t _header_size, - const byte_t *_data, uint16_t _data_size) { -#ifdef USE_DLT - if(!is_enabled_) - return; - - std::lock_guard<std::mutex> its_lock_filter_rules(filter_rules_mutex_); - std::lock_guard<std::mutex> its_lock_channels(channels_mutex_); - std::lock_guard<std::mutex> its_lock_dlt_contexts(dlt_contexts_mutex); - - if (_data_size == 0) - return; // no data - - if (is_sd_message(_data, _data_size) && !is_sd_enabled_) - return; // tracing of service discovery messages is disabled! - - // check if filter rules match - std::vector<trace_channel_t> its_channels; - if (apply_filter_rules(_data, _data_size, its_channels)) { - // send message over 'its_channels' - for(auto channel_id : its_channels) { - //find dlt context - auto it = dlt_contexts_.find(channel_id); - if (it != dlt_contexts_.end()) { - DltContext *dlt_context = it->second; - DLT_TRACE_NETWORK_SEGMENTED(*dlt_context, - DLT_NW_TRACE_IPC, - _header_size, static_cast<void *>(const_cast<byte_t *>(_header)), - _data_size, static_cast<void *>(const_cast<byte_t *>(_data))); - } - } - } -#else - (void)_header; - (void)_header_size; - (void)_data; - (void)_data_size; -#endif -} - -trace_connector::channels_t trace_connector::get_channels() { - std::lock_guard<std::mutex>its_lock_channels(channels_mutex_); - return channels_; -} - -trace_connector::filter_rules_t trace_connector::get_filter_rules() { - std::lock_guard<std::mutex> its_lock_filters(filter_rules_mutex_); - return filter_rules_; -} - -trace_connector::filter_rule_t trace_connector::get_filter_rule(const trace_channel_t &_channel_id) { - std::lock_guard<std::mutex> its_lock_filters(filter_rules_mutex_); - - // find filter - auto it = filter_rules_.find(_channel_id); - if (it != filter_rules_.end()) { - return filter_rules_[_channel_id]; - } else { - return filter_rule_t(); - } -} - -bool trace_connector::apply_filter_rules(const byte_t *_data, uint16_t _data_size, - std::vector<trace_channel_t> &_send_msg_over_channels) { - _send_msg_over_channels.clear(); - if (filter_rules_.size() == 0) { - // no filter rules -> send message over all channels to DLT - for(auto it=channels_.begin(); it !=channels_.end(); ++it) - _send_msg_over_channels.push_back(it->first); - return true; - } - - // loop through filter rules - for(auto it_filter_rules = filter_rules_.begin(); it_filter_rules != filter_rules_.end(); ++it_filter_rules) { - trace_channel_t its_channel = it_filter_rules->first; - filter_rule_t its_filter_rule = it_filter_rules->second; - - // apply filter rule - bool trace_message = true; - filter_type_e its_filter_type = its_filter_rule.first; - for(auto it_filter_rule_map = its_filter_rule.second.begin(); - it_filter_rule_map != its_filter_rule.second.end() && trace_message; - ++it_filter_rule_map) { - - filter_criteria_e its_criteria = it_filter_rule_map->first; - auto &its_filter_expressions = it_filter_rule_map->second; - - if(its_filter_expressions.size() != 0) { - // check if filter expressions of filter criteria match - const bool filter_rule_matches = filter_expressions_match(its_criteria, its_filter_expressions, _data, _data_size); - trace_message = !(filter_rule_matches && its_filter_type == filter_type_e::NEGATIVE); - } - } - - if(trace_message) { - //filter rule matches -> send message over 'its_channel' to DLT - _send_msg_over_channels.push_back(its_channel); - } - } - return (_send_msg_over_channels.size() != 0); -} - -bool trace_connector::filter_expressions_match( - const filter_criteria_e _criteria, const filter_expressions_t _expressions, - const byte_t *_data, uint16_t _data_size) { - - // ignore empty filter expressions - if (_expressions.size() == 0) { - return true; - } - - // extract criteria from message - bool is_successful(false); - byte_t first = 0; - byte_t second = 0; - switch (_criteria) { - case filter_criteria_e::SERVICES: - if (VSOMEIP_SERVICE_POS_MAX < _data_size) { - first = _data[VSOMEIP_SERVICE_POS_MIN]; - second = _data[VSOMEIP_SERVICE_POS_MAX]; - is_successful = true; - } - break; - case filter_criteria_e::METHODS: - if (VSOMEIP_SERVICE_POS_MAX < _data_size) { - first = _data[VSOMEIP_METHOD_POS_MIN]; - second = _data[VSOMEIP_METHOD_POS_MAX]; - is_successful = true; - } - break; - case filter_criteria_e::CLIENTS: - if (VSOMEIP_CLIENT_POS_MAX < _data_size) { - first = _data[VSOMEIP_CLIENT_POS_MIN]; - second = _data[VSOMEIP_CLIENT_POS_MAX]; - is_successful = true; - } - break; - default: - break; - } - - // if extraction is successful, filter - if (is_successful) { - bool filter_expressions_matches = false; - for (auto it_expressions = _expressions.begin(); - it_expressions != _expressions.end() && !filter_expressions_matches; - ++it_expressions) { - filter_expression_t its_filter_expression = *it_expressions; - uint16_t its_message_value = 0; - - its_message_value = (uint16_t)((its_message_value << 8) + first); - its_message_value = (uint16_t)((its_message_value << 8) + second); - - filter_expressions_matches = (its_filter_expression == its_message_value); - } - return filter_expressions_matches; - } - return false; -} - -} // namespace tc -} // namespace vsomeip diff --git a/implementation/utility/include/utility.hpp b/implementation/utility/include/utility.hpp index 34979a6..c5d8afe 100644 --- a/implementation/utility/include/utility.hpp +++ b/implementation/utility/include/utility.hpp @@ -11,13 +11,23 @@ #include <set> #include <atomic> +#ifdef _WIN32 + #include <stdlib.h> + #define bswap_16(x) _byteswap_ushort(x) + #define bswap_32(x) _byteswap_ulong(x) +#else + #include <byteswap.h> +#endif + #include <vsomeip/enumeration_types.hpp> #include <vsomeip/message.hpp> #include "criticalsection.hpp" +#include "../../../implementation/configuration/include/policy.hpp" namespace vsomeip { class configuration; +struct policy; class utility { public: @@ -124,13 +134,46 @@ public: || _type == message_type_e::MT_UNKNOWN); } + static inline bool is_valid_return_code(return_code_e _code) { + return (_code == return_code_e::E_OK + || _code == return_code_e::E_NOT_OK + || _code == return_code_e::E_UNKNOWN_SERVICE + || _code == return_code_e::E_UNKNOWN_METHOD + || _code == return_code_e::E_NOT_READY + || _code == return_code_e::E_NOT_REACHABLE + || _code == return_code_e::E_TIMEOUT + || _code == return_code_e::E_WRONG_PROTOCOL_VERSION + || _code == return_code_e::E_WRONG_INTERFACE_VERSION + || _code == return_code_e::E_MALFORMED_MESSAGE + || _code == return_code_e::E_WRONG_MESSAGE_TYPE); + } + + VSOMEIP_EXPORT static bool parse_policy(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_uid, uint32_t &_gid, ::std::shared_ptr<policy> &_policy); + VSOMEIP_EXPORT static bool parse_uid_gid(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_uid, uint32_t &_gid); + private: - static bool is_bigger_last_assigned_client_id(client_t _client, std::uint16_t _diagnosis_mask); - static void set_max_assigned_client_id_without_diagnosis(client_t _client); static void check_client_id_consistency(); + static std::uint16_t get_max_number_of_clients(std::uint16_t _diagnosis_max); + static inline bool parse_range(const byte_t* &_buffer, uint32_t &_buffer_size, uint16_t &_first, uint16_t &_last); + static inline bool parse_id(const byte_t* &_buffer, uint32_t &_buffer_size, uint16_t &_id); + static inline bool get_struct_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length); + static inline bool get_union_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length); + static inline bool get_array_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length); + static inline bool is_range(const byte_t* &_buffer, uint32_t &_buffer_size); + static inline bool parse_id_item(const byte_t* &_buffer, uint32_t& parsed_ids_bytes, ranges_t& its_ranges, uint32_t &_buffer_size); static std::atomic<std::uint16_t> its_configuration_refs__; static std::uint16_t* used_client_ids__; + + static const uint8_t uid_width_; + static const uint8_t gid_width_; + static const uint8_t id_width_; + static const uint8_t range_width_; + static const uint8_t skip_union_length_ ; + static const uint8_t skip_union_type_ ; + static const uint8_t skip_union_length_type_ ; + static const uint8_t skip_struct_length_; + static const uint8_t skip_array_length_; }; } // namespace vsomeip diff --git a/implementation/utility/src/utility.cpp b/implementation/utility/src/utility.cpp index 6b633ea..9919ea8 100644 --- a/implementation/utility/src/utility.cpp +++ b/implementation/utility/src/utility.cpp @@ -5,6 +5,7 @@ #ifdef _WIN32 #include <iostream> + #include <intrin.h> #else #include <dlfcn.h> #include <signal.h> @@ -101,9 +102,11 @@ static HANDLE its_descriptor(INVALID_HANDLE_VALUE); bool utility::auto_configuration_init(const std::shared_ptr<configuration> &_config) { std::unique_lock<CriticalSection> its_lock(its_local_configuration_mutex__); + const std::uint16_t its_max_clients = + get_max_number_of_clients(_config->get_diagnosis_mask()); const size_t its_shm_size = sizeof(configuration_data_t) + - static_cast<std::uint16_t>(~_config->get_diagnosis_mask()) * sizeof(client_t); + (its_max_clients + 1) * sizeof(client_t); #ifdef _WIN32 if (its_configuration_refs__ > 0) { assert(configuration_data_mutex != INVALID_HANDLE_VALUE); @@ -187,9 +190,9 @@ bool utility::auto_configuration_init(const std::shared_ptr<configuration> &_con the_configuration_data__->client_base_ = static_cast<unsigned short>((_config->get_diagnosis_address() << 8) & _config->get_diagnosis_mask()); - the_configuration_data__->max_clients_ = static_cast<std::uint16_t>(~_config->get_diagnosis_mask()); + the_configuration_data__->max_clients_ = its_max_clients; the_configuration_data__->max_used_client_ids_index_ = 1; - the_configuration_data__->max_assigned_client_id_without_diagnosis_ = 0x00; + the_configuration_data__->max_assigned_client_id_ = 0x00; the_configuration_data__->routing_manager_host_ = 0x0000; // the clientid array starts right after the routing_manager_host_ struct member used_client_ids__ = reinterpret_cast<unsigned short*>( @@ -232,11 +235,13 @@ bool utility::auto_configuration_init(const std::shared_ptr<configuration> &_con // shm is already mapped into the process its_configuration_refs__++; } else { - const mode_t previous_mask(::umask(static_cast<mode_t>(_config->get_umask()))); - int its_descriptor = shm_open(utility::get_shm_name(_config).c_str(), O_RDWR | O_CREAT | O_EXCL, + int its_descriptor = shm_open(utility::get_shm_name(_config).c_str(), O_RDWR | O_CREAT | O_EXCL, static_cast<mode_t>(_config->get_permissions_shm())); - ::umask(previous_mask); - if (its_descriptor > -1) { + if (its_descriptor > -1) { + if (-1 == chmod(std::string("/dev/shm").append(utility::get_shm_name(_config)).c_str(), + static_cast<mode_t>(_config->get_permissions_uds()))) { + VSOMEIP_ERROR << __func__ << ": chmod: " << strerror(errno); + } if (-1 == ftruncate(its_descriptor, its_shm_size)) { VSOMEIP_ERROR << "utility::auto_configuration_init: " "ftruncate failed: " << std::strerror(errno); @@ -278,9 +283,9 @@ bool utility::auto_configuration_init(const std::shared_ptr<configuration> &_con the_configuration_data__->client_base_ = static_cast<unsigned short>((_config->get_diagnosis_address() << 8) & _config->get_diagnosis_mask()); - the_configuration_data__->max_clients_ = static_cast<std::uint16_t>(~_config->get_diagnosis_mask()); + the_configuration_data__->max_clients_ = its_max_clients; the_configuration_data__->max_used_client_ids_index_ = 1; - the_configuration_data__->max_assigned_client_id_without_diagnosis_ = 0x00; + the_configuration_data__->max_assigned_client_id_ = 0x00; the_configuration_data__->routing_manager_host_ = 0x0000; // the clientid array starts right after the routing_manager_host_ struct member used_client_ids__ = reinterpret_cast<unsigned short*>( @@ -307,10 +312,18 @@ bool utility::auto_configuration_init(const std::shared_ptr<configuration> &_con } } } else if (errno == EEXIST) { - const mode_t previous_mask(::umask(static_cast<mode_t>(_config->get_umask()))); its_descriptor = shm_open(utility::get_shm_name(_config).c_str(), O_RDWR, static_cast<mode_t>(_config->get_permissions_shm())); - ::umask(previous_mask); + + int retry_count = 8; + std::chrono::milliseconds retry_delay = std::chrono::milliseconds(10); + while (its_descriptor == -1 && retry_count-- > 0) { + std::this_thread::sleep_for(retry_delay); + its_descriptor = shm_open(utility::get_shm_name(_config).c_str(), O_RDWR, + static_cast<mode_t>(_config->get_permissions_shm())); + retry_delay *= 2; + } + if (-1 == its_descriptor) { VSOMEIP_ERROR << "utility::auto_configuration_init: " "shm_open failed: " << std::strerror(errno); @@ -376,8 +389,6 @@ bool utility::auto_configuration_init(const std::shared_ptr<configuration> &_con void utility::auto_configuration_exit(client_t _client, const std::shared_ptr<configuration> &_config) { std::unique_lock<CriticalSection> its_lock(its_local_configuration_mutex__); - const size_t its_shm_size = sizeof(configuration_data_t) + - static_cast<std::uint16_t>(~_config->get_diagnosis_mask()) * sizeof(client_t); if (the_configuration_data__) { #ifdef _WIN32 // not manipulating data in shared memory, no need to take global mutex @@ -412,6 +423,10 @@ void utility::auto_configuration_exit(client_t _client, } if (its_configuration_refs__ == 0) { + const std::uint16_t its_max_clients = + get_max_number_of_clients(_config->get_diagnosis_mask()); + const size_t its_shm_size = sizeof(configuration_data_t) + + (its_max_clients + 1) * sizeof(client_t); if (-1 == ::munmap(the_configuration_data__, its_shm_size)) { VSOMEIP_ERROR << "utility::auto_configuration_exit: " "munmap failed: " << std::strerror(errno); @@ -586,16 +601,20 @@ client_t utility::request_client_id(const std::shared_ptr<configuration> &_confi if (use_autoconfig) { if (_client == ILLEGAL_CLIENT || is_used_client_id(_client, _config)) { - _client = the_configuration_data__->client_base_; + if (the_configuration_data__->max_assigned_client_id_ != 0x00) { + _client = the_configuration_data__->max_assigned_client_id_; + } else { + _client = the_configuration_data__->client_base_; + } } int increase_count = 0; - while (is_used_client_id(_client, _config) - || !is_bigger_last_assigned_client_id(_client, _config->get_diagnosis_mask()) - || _config->is_configured_client_id(_client)) { - if ((_client & the_configuration_data__->max_clients_) - + 1 > the_configuration_data__->max_clients_) { + + while (_client <= the_configuration_data__->max_assigned_client_id_ + || _config->is_configured_client_id(_client) + || is_used_client_id(_client, _config)) { + if (_client + 1 > used_client_ids__[0] + the_configuration_data__->max_clients_) { _client = the_configuration_data__->client_base_; - the_configuration_data__->max_assigned_client_id_without_diagnosis_ = 0; + the_configuration_data__->max_assigned_client_id_ = the_configuration_data__->client_base_; } else { _client++; increase_count++; @@ -614,7 +633,7 @@ client_t utility::request_client_id(const std::shared_ptr<configuration> &_confi } } } - set_max_assigned_client_id_without_diagnosis(_client); + the_configuration_data__->max_assigned_client_id_ = _client; } if (set_client_as_manager_host) { @@ -731,19 +750,343 @@ void utility::set_routing_manager_host(client_t _client) { #endif } -bool utility::is_bigger_last_assigned_client_id(client_t _client, std::uint16_t _diagnosis_mask) { - return _client - > ((the_configuration_data__->client_base_ & _diagnosis_mask) - + the_configuration_data__->max_assigned_client_id_without_diagnosis_); + +inline bool utility::get_struct_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length) { + uint32_t its_length = 0; + bool length_field_deployed(false); + // [TR_SOMEIP_00080] d If the length of the length field is not specified, a length of 0 + // has to be assumed and no length field is in the message. + if (length_field_deployed) { + if (_buffer_size >= sizeof(uint32_t)) { + std::memcpy(&its_length, _buffer, sizeof(uint32_t)); + _length = bswap_32(its_length); + _buffer_size -= skip_struct_length_; + _buffer += skip_struct_length_; + return true; + } + } else { + _length = 0; + return true; + } + + return false; +} + +inline bool utility::get_union_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length) { + uint32_t its_length = 0; + + // [TR_SOMEIP_00125] d If the Interface Specification does not specify the length of the + // length field for a union, 32 bit length of the length field shall be used. + if (_buffer_size >= sizeof(uint32_t)) { + std::memcpy(&its_length, _buffer, sizeof(uint32_t)); + _length = bswap_32(its_length); + _buffer_size -= skip_union_length_; + _buffer += skip_union_length_; + return true; + } + return false; } -void utility::set_max_assigned_client_id_without_diagnosis(client_t _client) { - const std::uint16_t its_client_id_without_diagnosis = - static_cast<std::uint16_t>(_client - & the_configuration_data__->max_clients_); - the_configuration_data__->max_assigned_client_id_without_diagnosis_ = - static_cast<std::uint16_t>(its_client_id_without_diagnosis - % the_configuration_data__->max_clients_); +inline bool utility::get_array_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length) { + uint32_t its_length = 0; + + // [TR_SOMEIP_00106] d The layout of arrays with dynamic length basically is based on + // the layout of fixed length arrays. To determine the size of the array the serialization + // adds a length field (default length 32 bit) in front of the data, which counts the bytes + // of the array. The length does not include the size of the length field. Thus, when + // transporting an array with zero elements the length is set to zero. + if (_buffer_size >= sizeof(uint32_t)) { + std::memcpy(&its_length, _buffer, sizeof(uint32_t)); + _length = bswap_32(its_length); + _buffer_size -= skip_array_length_; + _buffer += skip_array_length_; + return true; + } + return false; +} + +inline bool utility::is_range(const byte_t* &_buffer, uint32_t &_buffer_size) { + uint32_t its_type = 0; + + // [TR_SOMEIP_00128] If the Interface Specification does not specify the length of the + // type field of a union, 32 bit length of the type field shall be used. + if (_buffer_size >= sizeof(uint32_t)) { + std::memcpy(&its_type, _buffer, sizeof(uint32_t)); + its_type = bswap_32(its_type); + _buffer_size -= skip_union_type_; + _buffer += skip_union_type_; + if (its_type == 0x02) { + return true; + } else { + return false; + } + } + return false; +} + +inline bool utility::parse_id_item(const byte_t* &_buffer, uint32_t& parsed_ids_bytes, ranges_t& its_ranges, uint32_t &_buffer_size) { + // get "union IdItem" length + uint32_t iditem_length = 0; + if (get_union_length(_buffer, _buffer_size, iditem_length)) { + // determine type of union + uint16_t its_first = 0; + uint16_t its_last = 0; + if (is_range(_buffer, _buffer_size)) { + // get range of instance IDs "struct IdRange" length + uint32_t range_length = 0; + if (get_struct_length(_buffer, _buffer_size, range_length)) { + // read first and last instance range + if (parse_range(_buffer, _buffer_size, its_first, its_last)) { + its_ranges.insert(std::make_pair(its_first, its_last)); + } else { + return false; + } + } + } else { + // a single instance ID + if (parse_id(_buffer, _buffer_size, its_first)) { + if (its_first != ANY_METHOD) { + if (its_first != 0x00) { + its_last = its_first; + its_ranges.insert(std::make_pair(its_first, its_last)); + } + } else { + its_first = 0x01; + its_last = 0xFFFE; + its_ranges.insert(std::make_pair(its_first, its_last)); + } + } + } + parsed_ids_bytes += (skip_union_length_type_ + iditem_length); + } + return true; +} + +inline bool utility::parse_range(const byte_t* &_buffer, uint32_t &_buffer_size, uint16_t &_first, uint16_t &_last){ + uint16_t its_first = 0; + uint16_t its_last = 0; + + if (_buffer_size >= sizeof(uint16_t) * 2) { + if (parse_id(_buffer, _buffer_size, its_first)) { + _first = its_first; + } + if (parse_id(_buffer, _buffer_size, its_last)) { + _last = its_last; + } + if (_first != _last + && (_first == ANY_METHOD || _last == ANY_METHOD)) { + return false; + } + if (_first != 0x0 && _last != 0x00 + && _first <= _last) { + if (_first == ANY_METHOD && + _last == ANY_METHOD) { + _first = 0x01; + _last = 0xFFFE; + } + return true; + } else { + if (_first == 0x00 && _last > _first + && _last != ANY_METHOD) { + _first = 0x01; + return true; + } + return false; + } + } + return false; +} + +inline bool utility::parse_id(const byte_t* &_buffer, uint32_t &_buffer_size, uint16_t &_id) { + uint16_t its_id = 0; + if (_buffer_size >= sizeof(uint16_t)) { + std::memcpy(&its_id, _buffer, sizeof(uint16_t)); + _id = bswap_16(its_id); + _buffer_size -= id_width_; + _buffer += id_width_; + return true; + } + return false; +} + +bool utility::parse_uid_gid(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_uid, uint32_t &_gid) { + uint32_t its_uid = 0xffffffff; + uint32_t its_gid = 0xffffffff; + + if (_buffer_size >= sizeof(uint32_t) * 2) { + std::memcpy(&its_uid, _buffer, sizeof(uint32_t)); + _uid = bswap_32(its_uid); + + std::memcpy(&its_gid, _buffer + sizeof(uint32_t), sizeof(uint32_t)); + _gid = bswap_32(its_gid); + + _buffer_size -= (uid_width_ + gid_width_); + _buffer += (uid_width_ + gid_width_); + return true; + } + return false; +} + +bool utility::parse_policy(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_uid, uint32_t &_gid, ::std::shared_ptr<policy> &_policy) { + uint32_t its_uid = 0xffffffff; + uint32_t its_gid = 0xffffffff; + bool has_error(false); + + // get user ID String + if (parse_uid_gid(_buffer, _buffer_size, its_uid, its_gid)) { + _uid = its_uid; + _gid = its_gid; + + // policy elements + std::pair<uint32_t, uint32_t> its_uid_range, its_gid_range; + std::set<std::pair<uint32_t, uint32_t>> its_uids, its_gids; + + // fill uid and gid range + std::get<0>(its_uid_range) = its_uid; + std::get<1>(its_uid_range) = its_uid; + std::get<0>(its_gid_range) = its_gid; + std::get<1>(its_gid_range) = its_gid; + its_uids.insert(its_uid_range); + its_gids.insert(its_gid_range); + + _policy->ids_.insert(std::make_pair(its_uids, its_gids)); + _policy->allow_who_ = true; + _policy->allow_what_ = true; + + // get struct AclUpdate + uint32_t acl_length = 0; + if (get_struct_length(_buffer, _buffer_size, acl_length)) { + // get requests array length + uint32_t requests_array_length = 0; + if (get_array_length(_buffer, _buffer_size, requests_array_length)) { + // loop through requests array consisting of n x "struct Request" + uint32_t parsed_req_bytes = 0; + while (parsed_req_bytes + skip_struct_length_ <= requests_array_length) { + // get request struct length + uint32_t req_length = 0; + if (get_struct_length(_buffer, _buffer_size, req_length)) { + if (req_length != 0) + parsed_req_bytes += skip_struct_length_; + + uint16_t its_service_id = 0; + ids_t its_instance_method_ranges; + // get serviceID + if (!parse_id(_buffer, _buffer_size, its_service_id)) { + has_error = true; + } else { + if (its_service_id == 0x00 + || its_service_id == 0xFFFF) { + VSOMEIP_WARNING << std::hex << "vSomeIP Security: Policy with service ID: 0x" + << its_service_id << " is not allowed!"; + return false; + } + // add length of serviceID + parsed_req_bytes += id_width_; + } + + // get instances array length + uint32_t instances_array_length = 0; + if (get_array_length(_buffer, _buffer_size, instances_array_length)) { + // loop trough instances array consisting of n x "struct Instance" + uint32_t parsed_inst_bytes = 0; + while (parsed_inst_bytes + skip_struct_length_ <= instances_array_length) { + // get instance struct length + uint32_t inst_length = 0; + if (get_struct_length(_buffer, _buffer_size, inst_length)) { + if (inst_length != 0) + parsed_inst_bytes += skip_struct_length_; + + ranges_t its_instance_ranges; + ranges_t its_method_ranges; + // get "IdItem[] ids" array length + uint32_t ids_array_length = 0; + if (get_array_length(_buffer, _buffer_size, ids_array_length)) { + uint32_t parsed_ids_bytes = 0; + while (parsed_ids_bytes + skip_struct_length_ <= ids_array_length) { + if (!parse_id_item(_buffer, parsed_ids_bytes, its_instance_ranges, _buffer_size)) { + return false; + } + } + parsed_inst_bytes += (skip_array_length_ + ids_array_length); + } + // get "IdItem[] methods" array length + uint32_t methods_array_length = 0; + if (get_array_length(_buffer, _buffer_size, methods_array_length)) { + uint32_t parsed_method_bytes = 0; + while (parsed_method_bytes + skip_struct_length_ <= methods_array_length) { + if (!parse_id_item(_buffer, parsed_method_bytes, its_method_ranges, _buffer_size)) { + return false; + } + } + if (!its_instance_ranges.empty() && !its_method_ranges.empty()) { + its_instance_method_ranges.insert(std::make_pair(its_instance_ranges, its_method_ranges)); + } + parsed_inst_bytes += (skip_array_length_ + methods_array_length); + } + } + } + parsed_req_bytes += (skip_array_length_ + instances_array_length); + } + if (!its_instance_method_ranges.empty()) { + _policy->services_.insert( + std::make_pair(its_service_id, its_instance_method_ranges)); + } + } + } + } + // get offers array length + uint32_t offers_array_length = 0; + if (get_array_length(_buffer, _buffer_size, offers_array_length)){ + // loop through offers array + uint32_t parsed_offers_bytes = 0; + while (parsed_offers_bytes + skip_struct_length_ <= offers_array_length) { + // get service ID + uint16_t its_service_id = 0; + ranges_t its_instance_ranges; + // get serviceID + if (!parse_id(_buffer, _buffer_size, its_service_id)) { + has_error = true; + } else { + if (its_service_id == 0x00 + || its_service_id == 0xFFFF) { + VSOMEIP_WARNING << std::hex << "vSomeIP Security: Policy with service ID: 0x" + << its_service_id << " is not allowed!"; + return false; + } + // add length of serviceID + parsed_offers_bytes += id_width_; + } + + // get "IdItem[] ids" array length + uint32_t ids_array_length = 0; + if (get_array_length(_buffer, _buffer_size, ids_array_length)) { + uint32_t parsed_ids_bytes = 0; + while (parsed_ids_bytes + skip_struct_length_ <= ids_array_length) { + if (!parse_id_item(_buffer, parsed_ids_bytes, its_instance_ranges, _buffer_size)) { + return false; + } + } + parsed_offers_bytes += (skip_array_length_ + ids_array_length); + } + if (!its_instance_ranges.empty()) { + _policy->offers_.insert( + std::make_pair(its_service_id, its_instance_ranges)); + } + } + } + } else { + VSOMEIP_WARNING << std::hex << "vSomeIP Security: Policy with empty request / offer section is not allowed!"; + has_error = true; + } + } else { + VSOMEIP_WARNING << std::hex << "vSomeIP Security: Policy without UID / GID is not allowed!"; + has_error = true; + } + + if (!has_error) + return true; + else + return false; } void utility::check_client_id_consistency() { @@ -767,4 +1110,30 @@ void utility::check_client_id_consistency() { } } +std::uint16_t utility::get_max_number_of_clients(std::uint16_t _diagnosis_max) { + std::uint16_t its_max_clients(0); + const int bits_for_clients = +#ifdef _WIN32 + __popcnt( +#else + __builtin_popcount( +#endif + static_cast<std::uint16_t>(~_diagnosis_max)); + for (int var = 0; var < bits_for_clients; ++var) { + its_max_clients = static_cast<std::uint16_t>(its_max_clients | (1 << var)); + } + return its_max_clients; +} + +const uint8_t utility::uid_width_ = sizeof(uint32_t); +const uint8_t utility::gid_width_ = sizeof(uint32_t); +const uint8_t utility::id_width_ = sizeof(uint16_t); +const uint8_t utility::range_width_ = sizeof(uint32_t); + +const uint8_t utility::skip_union_length_ = sizeof(uint32_t); +const uint8_t utility::skip_union_type_ = sizeof(uint32_t); +const uint8_t utility::skip_union_length_type_ = sizeof(uint32_t) + sizeof(uint32_t); +const uint8_t utility::skip_struct_length_ = sizeof(uint32_t); +const uint8_t utility::skip_array_length_ = sizeof(uint32_t); + } // namespace vsomeip |