diff options
author | Jürgen Gehring <Juergen.Gehring@bmw.de> | 2016-09-20 03:59:53 -0700 |
---|---|---|
committer | Jürgen Gehring <Juergen.Gehring@bmw.de> | 2016-09-20 03:59:53 -0700 |
commit | 273814c76be4a8f906dc053492529b8d53b9e807 (patch) | |
tree | e7160dc68fe3f478a0c5c86aaccaeb620d528b63 /implementation | |
parent | 4c5d160362d8693aed8abd642212e68c9778bbda (diff) | |
download | vSomeIP-273814c76be4a8f906dc053492529b8d53b9e807.tar.gz |
vSomeIP 2.2.42.2.4
Diffstat (limited to 'implementation')
145 files changed, 12801 insertions, 3056 deletions
diff --git a/implementation/configuration/include/client.hpp b/implementation/configuration/include/client.hpp new file mode 100644 index 0000000..fcb4395 --- /dev/null +++ b/implementation/configuration/include/client.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_CFG_CLIENT_HPP +#define VSOMEIP_CFG_CLIENT_HPP + +#include <map> +#include <memory> +#include <set> + +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip { +namespace cfg { + +struct client { + service_t service_; + instance_t instance_; + + std::map<bool, std::set<uint16_t> > ports_; +}; + +} // namespace cfg +} // namespace vsomeip + +#endif // VSOMEIP_CFG_CLIENT_HPP diff --git a/implementation/configuration/include/configuration.hpp b/implementation/configuration/include/configuration.hpp index 2f106ee..8dab1b4 100644 --- a/implementation/configuration/include/configuration.hpp +++ b/implementation/configuration/include/configuration.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -19,6 +19,7 @@ #include <vsomeip/primitive_types.hpp> #include "internal.hpp" +#include "trace.hpp" namespace vsomeip { @@ -32,6 +33,7 @@ public: virtual ~configuration() {} virtual const boost::asio::ip::address & get_unicast_address() const = 0; + virtual unsigned short get_diagnosis_address() const = 0; virtual bool is_v4() const = 0; virtual bool is_v6() const = 0; @@ -45,29 +47,36 @@ public: virtual std::string get_unicast_address(service_t _service, instance_t _instance) const = 0; - virtual std::string get_multicast_address(service_t _service, - instance_t _instance) const = 0; - virtual uint16_t get_multicast_port(service_t _service, - instance_t _instance) const = 0; - virtual uint16_t get_multicast_group(service_t _service, - instance_t _instance) const = 0; virtual uint16_t get_reliable_port(service_t _service, instance_t _instance) const = 0; - virtual bool is_someip(service_t _service, instance_t _instance) const = 0; virtual bool has_enabled_magic_cookies(std::string _address, uint16_t _port) const = 0; virtual uint16_t get_unreliable_port(service_t _service, instance_t _instance) const = 0; + virtual bool is_someip(service_t _service, instance_t _instance) const = 0; + + virtual bool get_client_port( + service_t _service, instance_t _instance, bool _reliable, + std::map<bool, std::set<uint16_t> > &_used, uint16_t &_port) const = 0; + virtual std::set<std::pair<service_t, instance_t> > get_remote_services() const = 0; + virtual bool get_multicast(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, std::string &_address, uint16_t &_port) const = 0; + virtual client_t get_id(const std::string &_name) const = 0; - virtual std::size_t get_num_dispatchers(const std::string &_name) const = 0; + virtual bool is_configured_client_id(client_t _id) const = 0; + + virtual std::size_t get_max_dispatchers(const std::string &_name) const = 0; + virtual std::size_t get_max_dispatch_time(const std::string &_name) const = 0; virtual std::uint32_t get_max_message_size_local() const = 0; virtual std::uint32_t get_message_size_reliable(const std::string& _address, std::uint16_t _port) const = 0; + virtual bool supports_selective_broadcasts(boost::asio::ip::address _address) const = 0; + // Service Discovery configuration virtual bool is_sd_enabled() const = 0; @@ -82,6 +91,18 @@ public: virtual ttl_t get_sd_ttl() const = 0; virtual int32_t get_sd_cyclic_offer_delay() const = 0; virtual int32_t get_sd_request_response_delay() const = 0; + + // Trace configuration + virtual std::shared_ptr<cfg::trace> get_trace() const = 0; + + // Watchdog + virtual bool is_watchdog_enabled() const = 0; + virtual uint32_t get_watchdog_timeout() const = 0; + virtual uint32_t get_allowed_missing_pongs() const = 0; + + // File permissions + virtual std::uint32_t get_umask() const = 0; + virtual std::uint32_t get_permissions_shm() const = 0; }; } // namespace vsomeip diff --git a/implementation/configuration/include/configuration_impl.hpp b/implementation/configuration/include/configuration_impl.hpp index a6ca21c..87a1d15 100644 --- a/implementation/configuration/include/configuration_impl.hpp +++ b/implementation/configuration/include/configuration_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -10,16 +10,31 @@ #include <memory> #include <mutex> #include <vector> +#include <unordered_set> #include <boost/property_tree/ptree.hpp> +#include "trace.hpp" #include "configuration.hpp" +#include "watchdog.hpp" namespace vsomeip { namespace cfg { +struct client; struct service; struct servicegroup; +struct eventgroup; +struct watchdog; + +struct element { + std::string name_; + boost::property_tree::ptree tree_; + + bool operator<(const element &_other) const { + return (name_ < _other.name_); + } +}; class configuration_impl: public configuration { public: @@ -31,10 +46,11 @@ public: VSOMEIP_EXPORT configuration_impl(const configuration_impl &_cfg); VSOMEIP_EXPORT virtual ~configuration_impl(); - VSOMEIP_EXPORT void load(const boost::property_tree::ptree &_tree); - VSOMEIP_EXPORT void load_log(const std::vector<boost::property_tree::ptree> &_trees); + VSOMEIP_EXPORT void load(const element &_element); + VSOMEIP_EXPORT void load_log(const std::vector<element> &_elements); VSOMEIP_EXPORT const boost::asio::ip::address & get_unicast_address() const; + VSOMEIP_EXPORT unsigned short get_diagnosis_address() const; VSOMEIP_EXPORT bool is_v4() const; VSOMEIP_EXPORT bool is_v6() const; @@ -45,12 +61,6 @@ public: VSOMEIP_EXPORT boost::log::trivial::severity_level get_loglevel() const; VSOMEIP_EXPORT std::string get_unicast_address(service_t _service, instance_t _instance) const; - VSOMEIP_EXPORT std::string get_multicast_address(service_t _service, - instance_t _instance) const; - VSOMEIP_EXPORT uint16_t get_multicast_port(service_t _service, - instance_t _instance) const; - VSOMEIP_EXPORT uint16_t get_multicast_group(service_t _service, - instance_t _instance) const; VSOMEIP_EXPORT uint16_t get_reliable_port(service_t _service, instance_t _instance) const; VSOMEIP_EXPORT bool has_enabled_magic_cookies(std::string _address, uint16_t _port) const; @@ -59,17 +69,28 @@ public: VSOMEIP_EXPORT bool is_someip(service_t _service, instance_t _instance) const; + VSOMEIP_EXPORT bool get_client_port(service_t _service, instance_t _instance, bool _reliable, + std::map<bool, std::set<uint16_t> > &_used, uint16_t &_port) const; + VSOMEIP_EXPORT const std::string & get_routing_host() const; VSOMEIP_EXPORT client_t get_id(const std::string &_name) const; - VSOMEIP_EXPORT std::size_t get_num_dispatchers(const std::string &_name) const; + VSOMEIP_EXPORT bool is_configured_client_id(client_t _id) const; + + VSOMEIP_EXPORT std::size_t get_max_dispatchers(const std::string &_name) const; + VSOMEIP_EXPORT std::size_t get_max_dispatch_time(const std::string &_name) const; VSOMEIP_EXPORT std::set<std::pair<service_t, instance_t> > get_remote_services() const; + VSOMEIP_EXPORT bool get_multicast(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, std::string &_address, uint16_t &_port) const; + VSOMEIP_EXPORT std::uint32_t get_max_message_size_local() const; VSOMEIP_EXPORT std::uint32_t get_message_size_reliable(const std::string& _address, std::uint16_t _port) const; + VSOMEIP_EXPORT bool supports_selective_broadcasts(boost::asio::ip::address _address) const; + // Service Discovery configuration VSOMEIP_EXPORT bool is_sd_enabled() const; @@ -85,31 +106,65 @@ public: VSOMEIP_EXPORT int32_t get_sd_cyclic_offer_delay() const; VSOMEIP_EXPORT int32_t get_sd_request_response_delay() const; + // Trace configuration + VSOMEIP_EXPORT std::shared_ptr<cfg::trace> get_trace() const; + + VSOMEIP_EXPORT bool is_watchdog_enabled() const; + VSOMEIP_EXPORT uint32_t get_watchdog_timeout() const; + VSOMEIP_EXPORT uint32_t get_allowed_missing_pongs() const; + + + VSOMEIP_EXPORT std::uint32_t get_umask() const; + VSOMEIP_EXPORT std::uint32_t get_permissions_shm() const; + private: - void get_logging_configuration(const boost::property_tree::ptree &_tree); + void get_logging_configuration(const element &_element, + std::set<std::string> &_warnings); - void get_someip_configuration(const boost::property_tree::ptree &_tree); + void get_someip_configuration(const element &_element); void get_services_configuration(const boost::property_tree::ptree &_tree); + void get_clients_configuration(const boost::property_tree::ptree &_tree); void get_payload_sizes_configuration(const boost::property_tree::ptree &_tree); - void get_routing_configuration(const boost::property_tree::ptree &_tree); - void get_service_discovery_configuration( - const boost::property_tree::ptree &_tree); - void get_applications_configuration(const boost::property_tree::ptree &_tree); + void get_routing_configuration(const element &_element); + void get_service_discovery_configuration(const element &_element); + void get_applications_configuration(const element &_tree); + void get_trace_configuration(const element &_tree); + void get_supports_selective_broadcasts(const boost::property_tree::ptree &_tree); + void get_watchdog_configuration(const element &_element); void get_servicegroup_configuration( const boost::property_tree::ptree &_tree); void get_delays_configuration(const boost::property_tree::ptree &_tree); void get_service_configuration(const boost::property_tree::ptree &_tree, const std::string &_unicast_address); + void get_client_configuration(const boost::property_tree::ptree &_tree); + std::set<uint16_t> get_client_port_configuration( + const boost::property_tree::ptree &_tree); void get_event_configuration(std::shared_ptr<service> &_service, const boost::property_tree::ptree &_tree); void get_eventgroup_configuration(std::shared_ptr<service> &_service, const boost::property_tree::ptree &_tree); void get_application_configuration( + const boost::property_tree::ptree &_tree, const std::string &_file_name); + void get_trace_channels_configuration( const boost::property_tree::ptree &_tree); - - servicegroup * find_servicegroup(const std::string &_name) const; - service * find_service(service_t _service, instance_t _instance) const; + void get_trace_channel_configuration( + const boost::property_tree::ptree &_tree); + void get_trace_filters_configuration( + const boost::property_tree::ptree &_tree); + void get_trace_filter_configuration( + const boost::property_tree::ptree &_tree); + void get_trace_filter_expressions( + const boost::property_tree::ptree &_tree, + std::string &_criteria, + std::shared_ptr<trace_filter_rule> &_filter_rule); + void get_permission_configuration(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<eventgroup> find_eventgroup(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const; private: static std::shared_ptr<configuration_impl> the_configuration; @@ -118,6 +173,7 @@ private: protected: // Configuration data boost::asio::ip::address unicast_; + unsigned short diagnosis_; bool has_console_log_; bool has_file_log_; @@ -125,12 +181,17 @@ protected: std::string logfile_; boost::log::trivial::severity_level loglevel_; - std::map<std::string, std::pair<client_t, std::size_t>> applications_; + std::map<std::string, std::tuple<client_t, std::size_t, std::size_t>> applications_; + std::set<client_t> client_identifiers_; std::map<service_t, std::map<instance_t, std::shared_ptr<service> > > services_; + std::map<service_t, + std::map<instance_t, + std::shared_ptr<client> > > clients_; + std::string routing_host_; bool is_sd_enabled_; @@ -150,6 +211,42 @@ protected: std::map<std::string, std::map<std::uint16_t, std::uint32_t>> message_sizes_; std::uint32_t max_configured_message_size_; + + std::shared_ptr<trace> trace_; + + std::unordered_set<std::string> supported_selective_addresses; + + std::shared_ptr<watchdog> watchdog_; + + enum element_type_e { + ET_UNICAST, + ET_DIAGNOSIS, + ET_LOGGING_CONSOLE, + ET_LOGGING_FILE, + ET_LOGGING_DLT, + ET_LOGGING_LEVEL, + ET_ROUTING, + ET_SERVICE_DISCOVERY_ENABLE, + ET_SERVICE_DISCOVERY_PROTOCOL, + ET_SERVICE_DISCOVERY_MULTICAST, + ET_SERVICE_DISCOVERY_PORT, + ET_SERVICE_DISCOVERY_INITIAL_DELAY_MIN, + ET_SERVICE_DISCOVERY_INITIAL_DELAY_MAX, + ET_SERVICE_DISCOVERY_REPETITION_BASE_DELAY, + ET_SERVICE_DISCOVERY_REPETITION_MAX, + ET_SERVICE_DISCOVERY_TTL, + ET_SERVICE_DISCOVERY_CYCLIC_OFFER_DELAY, + ET_SERVICE_DISCOVERY_REQUEST_RESPONSE_DELAY, + ET_WATCHDOG_ENABLE, + ET_WATCHDOG_TIMEOUT, + ET_WATCHDOG_ALLOWED_MISSING_PONGS, + ET_TRACING_ENABLE, + ET_MAX = 22 + }; + + bool is_configured_[ET_MAX]; + std::uint32_t permissions_shm_; + std::uint32_t umask_; }; } // namespace cfg diff --git a/implementation/configuration/include/event.hpp b/implementation/configuration/include/event.hpp index e932289..d488ec4 100644 --- a/implementation/configuration/include/event.hpp +++ b/implementation/configuration/include/event.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/configuration/include/eventgroup.hpp b/implementation/configuration/include/eventgroup.hpp index 27bf722..93a91a3 100644 --- a/implementation/configuration/include/eventgroup.hpp +++ b/implementation/configuration/include/eventgroup.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -18,6 +18,8 @@ struct event; struct eventgroup { eventgroup_t id_; std::set<std::shared_ptr<event> > events_; + std::string multicast_address_; + uint16_t multicast_port_; }; } // namespace cfg diff --git a/implementation/configuration/include/internal.hpp.in b/implementation/configuration/include/internal.hpp.in index 64b7105..d7770c9 100644 --- a/implementation/configuration/include/internal.hpp.in +++ b/implementation/configuration/include/internal.hpp.in @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -26,20 +26,25 @@ #define VSOMEIP_ROUTING "@VSOMEIP_ROUTING@" #define VSOMEIP_ROUTING_CLIENT 0 +#define VSOMEIP_ROUTING_INFO_SIZE_INIT 256 #ifdef WIN32 #define VSOMEIP_INTERNAL_BASE_PORT 51234 +#define __func__ __FUNCTION__ #endif #define VSOMEIP_UNICAST_ADDRESS "@VSOMEIP_UNICAST_ADDRESS@" #define VSOMEIP_DEFAULT_CONNECT_TIMEOUT 100 +#define VSOMEIP_MAX_CONNECT_TIMEOUT 1000 #define VSOMEIP_DEFAULT_FLUSH_TIMEOUT 1000 -#define VSOMEIP_DEFAULT_WATCHDOG_CYCLE 5000 #define VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT 5000 #define VSOMEIP_DEFAULT_MAX_MISSING_PONGS 3 +#define VSOMEIP_MAX_DISPATCHERS 10 +#define VSOMEIP_MAX_DISPATCH_TIME 100 + #define VSOMEIP_COMMAND_HEADER_SIZE 7 #define VSOMEIP_COMMAND_TYPE_POS 0 @@ -62,33 +67,53 @@ #define VSOMEIP_UNSUBSCRIBE 0x13 #define VSOMEIP_REQUEST_SERVICE 0x14 #define VSOMEIP_RELEASE_SERVICE 0x15 - -#define VSOMEIP_SEND 0x17 -#define VSOMEIP_NOTIFY 0x18 - -#define VSOMEIP_REGISTER_EVENT 0x19 -#define VSOMEIP_UNREGISTER_EVENT 0x1A - -#define VSOMEIP_OFFER_SERVICE_COMMAND_SIZE 20 -#define VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE 21 -#define VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE 11 -#define VSOMEIP_SUBSCRIBE_COMMAND_SIZE 19 +#define VSOMEIP_SUBSCRIBE_NACK 0x16 +#define VSOMEIP_SUBSCRIBE_ACK 0x17 + +#define VSOMEIP_SEND 0x18 +#define VSOMEIP_NOTIFY 0x19 +#define VSOMEIP_NOTIFY_ONE 0x1A + +#define VSOMEIP_REGISTER_EVENT 0x1B +#define VSOMEIP_UNREGISTER_EVENT 0x1C +#define VSOMEIP_ID_RESPONSE 0x1D + +#define VSOMEIP_OFFER_SERVICE_COMMAND_SIZE 16 +#define VSOMEIP_REQUEST_SERVICE_COMMAND_SIZE 17 +#define VSOMEIP_RELEASE_SERVICE_COMMAND_SIZE 11 +#define VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE 16 +#define VSOMEIP_SUBSCRIBE_COMMAND_SIZE 16 +#define VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE 13 +#define VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE 13 #define VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE 13 #define VSOMEIP_REGISTER_EVENT_COMMAND_SIZE 15 -#define VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE 13 +#define VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE 14 -#include <mutex> +#ifndef WIN32 +#include <pthread.h> +#endif #define VSOMEIP_DATA_ID 0x677D #define VSOMEIP_SHM_NAME "/vsomeip" #define VSOMEIP_DIAGNOSIS_ADDRESS @VSOMEIP_DIAGNOSIS_ADDRESS@ +#define VSOMEIP_DEFAULT_SHM_PERMISSION 0666 +#define VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS 0000 + +#define VSOMEIP_MAX_CLIENTS 255 + namespace vsomeip { struct configuration_data_t { - std::mutex mutex_; - unsigned short next_client_id_; - unsigned short ref_; +#ifdef WIN32 + void* mutex_; +#else + pthread_mutex_t mutex_; +#endif + unsigned short client_base_; + + unsigned short used_client_ids_[VSOMEIP_MAX_CLIENTS]; + int max_used_client_ids_index_; }; } // namespace vsomeip diff --git a/implementation/configuration/include/service.hpp b/implementation/configuration/include/service.hpp index bbe235e..8e72a02 100644 --- a/implementation/configuration/include/service.hpp +++ b/implementation/configuration/include/service.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -27,7 +27,6 @@ struct service { std::string multicast_address_; uint16_t multicast_port_; - eventgroup_t multicast_group_; std::string protocol_; diff --git a/implementation/configuration/include/trace.hpp b/implementation/configuration/include/trace.hpp new file mode 100644 index 0000000..cba4da8 --- /dev/null +++ b/implementation/configuration/include/trace.hpp @@ -0,0 +1,62 @@ +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef CONFIGURATION_INCLUDE_TRACE_HPP_ +#define CONFIGURATION_INCLUDE_TRACE_HPP_ + +#include <vsomeip/primitive_types.hpp> + +#include "../../tracing/include/defines.hpp" + +namespace vsomeip { +namespace cfg { + +struct trace_channel { + + trace_channel() : + id_(VSOMEIP_TC_DEFAULT_CHANNEL_ID), + name_(VSOMEIP_TC_DEFAULT_CHANNEL_NAME) { + + } + + trace_channel_t id_; + std::string name_; +}; + +struct trace_filter_rule { + + trace_filter_rule() : + channel_(VSOMEIP_TC_DEFAULT_CHANNEL_ID), + services_(), + methods_(), + clients_() { + + } + + trace_channel_t channel_; + std::vector<service_t> services_; + std::vector<method_t> methods_; + std::vector<client_t> clients_; +}; + +struct trace { + + trace() : + channels_(), + filter_rules_(), + is_enabled_(false) { + channels_.push_back(std::make_shared<trace_channel>()); + } + + std::vector<std::shared_ptr<trace_channel>> channels_; + std::vector<std::shared_ptr<trace_filter_rule>> filter_rules_; + + bool is_enabled_; +}; + +} // namespace cfg +} // namespace vsomeip + +#endif /* CONFIGURATION_INCLUDE_TRACE_HPP_ */ diff --git a/implementation/configuration/include/watchdog.hpp b/implementation/configuration/include/watchdog.hpp new file mode 100644 index 0000000..1d5696d --- /dev/null +++ b/implementation/configuration/include/watchdog.hpp @@ -0,0 +1,21 @@ +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_CFG_WATCHDOG_HPP_ +#define VSOMEIP_CFG_WATCHDOG_HPP_ + +namespace vsomeip { +namespace cfg { + +struct watchdog { + bool is_enabeled_; + uint32_t timeout_in_ms_; + uint32_t missing_pongs_allowed_; +}; + +} // namespace cfg +} // namespace vsomeip + +#endif /* VSOMEIP_CFG_WATCHDOG_HPP_ */ diff --git a/implementation/configuration/src/configuration.cpp b/implementation/configuration/src/configuration.cpp index 9bc90d4..0994dcd 100644 --- a/implementation/configuration/src/configuration.cpp +++ b/implementation/configuration/src/configuration.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/configuration/src/configuration_impl.cpp b/implementation/configuration/src/configuration_impl.cpp index 66a1219..3c78de0 100644 --- a/implementation/configuration/src/configuration_impl.cpp +++ b/implementation/configuration/src/configuration_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -9,10 +9,6 @@ #define WIN32_LEAN_AND_MEAN -#if defined ( WIN32 ) -#define __func__ __FUNCTION__ -#endif - #include <boost/algorithm/string.hpp> #include <boost/filesystem.hpp> #include <boost/foreach.hpp> @@ -20,6 +16,7 @@ #include <vsomeip/constants.hpp> +#include "../include/client.hpp" #include "../include/configuration_impl.hpp" #include "../include/event.hpp" #include "../include/eventgroup.hpp" @@ -41,9 +38,12 @@ std::shared_ptr<configuration> configuration_impl::get( std::shared_ptr<configuration> its_configuration; std::lock_guard<std::mutex> its_lock(mutex_); + std::set<std::string> failed_files; + static bool has_reading_failed(false); + if (!the_configuration) { the_configuration = std::make_shared<configuration_impl>(); - std::vector<boost::property_tree::ptree> its_tree_set; + std::vector<element> its_configuration_elements; // Load logger configuration first for (auto i : _input) { @@ -51,9 +51,13 @@ std::shared_ptr<configuration> configuration_impl::get( boost::property_tree::ptree its_tree; try { boost::property_tree::json_parser::read_json(i, its_tree); - its_tree_set.push_back(its_tree); + its_configuration_elements.push_back({ i, its_tree }); } - catch (...) { + catch (boost::property_tree::json_parser_error &e) { +#ifdef WIN32 + e; // silence MSVC warining C4101 +#endif + failed_files.insert(i); } } else if (utility::is_folder(i)) { boost::filesystem::path its_path(i); @@ -66,9 +70,10 @@ std::shared_ptr<configuration> configuration_impl::get( boost::property_tree::ptree its_tree; try { boost::property_tree::json_parser::read_json(its_name, its_tree); - its_tree_set.push_back(its_tree); + its_configuration_elements.push_back({its_name, its_tree}); } catch (...) { + failed_files.insert(its_name); } } } @@ -76,13 +81,28 @@ std::shared_ptr<configuration> configuration_impl::get( } // Load log configuration - the_configuration->load_log(its_tree_set); - - // Load other configuration parts - for (auto t : its_tree_set) - the_configuration->load(t); + the_configuration->load_log(its_configuration_elements); + + // Check whether reading of configuration file(s) succeeded. + if (!failed_files.empty()) { + has_reading_failed = true; + for (auto its_failed : failed_files) + VSOMEIP_ERROR << "Reading of configuration file \"" + << its_failed << "\" failed."; + } else { + // Load other configuration parts + std::sort(its_configuration_elements.begin(), + its_configuration_elements.end()); + for (auto e : its_configuration_elements) + the_configuration->load(e); + } } + // There is only one attempt to read the configuration file(s). + // If it has failed, we must not return the configuration object. + if (has_reading_failed) + return nullptr; + return the_configuration; } @@ -91,6 +111,7 @@ void configuration_impl::reset() { } configuration_impl::configuration_impl() : + diagnosis_(VSOMEIP_DIAGNOSIS_ADDRESS), has_console_log_(true), has_file_log_(false), has_dlt_log_(false), @@ -107,18 +128,26 @@ configuration_impl::configuration_impl() : sd_ttl_(VSOMEIP_SD_DEFAULT_TTL), sd_cyclic_offer_delay_(VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY), sd_request_response_delay_(VSOMEIP_SD_DEFAULT_REQUEST_RESPONSE_DELAY), - max_configured_message_size_(0) { - + max_configured_message_size_(0), + trace_(std::make_shared<trace>()), + watchdog_(std::make_shared<watchdog>()), + permissions_shm_(VSOMEIP_DEFAULT_SHM_PERMISSION), + umask_(VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS) { unicast_ = unicast_.from_string(VSOMEIP_UNICAST_ADDRESS); + for (auto i = 0; i < ET_MAX; i++) + is_configured_[i] = false; } configuration_impl::configuration_impl(const configuration_impl &_other) : - max_configured_message_size_(0) { + max_configured_message_size_(0), + permissions_shm_(VSOMEIP_DEFAULT_SHM_PERMISSION), + umask_(VSOMEIP_DEFAULT_UMASK_LOCAL_ENDPOINTS) { applications_.insert(_other.applications_.begin(), _other.applications_.end()); services_.insert(_other.services_.begin(), _other.services_.end()); unicast_ = _other.unicast_; + diagnosis_ = _other.diagnosis_; has_console_log_ = _other.has_console_log_; has_file_log_ = _other.has_file_log_; @@ -142,72 +171,116 @@ configuration_impl::configuration_impl(const configuration_impl &_other) : sd_cyclic_offer_delay_= _other.sd_cyclic_offer_delay_; sd_request_response_delay_= _other.sd_request_response_delay_; + trace_ = std::make_shared<trace>(*_other.trace_.get()); + watchdog_ = std::make_shared<watchdog>(*_other.watchdog_.get()); + magic_cookies_.insert(_other.magic_cookies_.begin(), _other.magic_cookies_.end()); + + for (auto i = 0; i < ET_MAX; i++) + is_configured_[i] = _other.is_configured_[i]; } configuration_impl::~configuration_impl() { } -void configuration_impl::load(const boost::property_tree::ptree &_tree) { +void configuration_impl::load(const element &_element) { try { // Read the configuration data - get_someip_configuration(_tree); - get_services_configuration(_tree); - get_payload_sizes_configuration(_tree); - get_routing_configuration(_tree); - get_service_discovery_configuration(_tree); - get_applications_configuration(_tree); + get_someip_configuration(_element); + get_services_configuration(_element.tree_); + get_clients_configuration(_element.tree_); + get_payload_sizes_configuration(_element.tree_); + get_routing_configuration(_element); + get_permission_configuration(_element); + get_service_discovery_configuration(_element); + get_applications_configuration(_element); + get_trace_configuration(_element); + get_supports_selective_broadcasts(_element.tree_); + get_watchdog_configuration(_element); } catch (std::exception &e) { +#ifdef WIN32 + e; // silence MSVC warning C4101 +#endif } } -void configuration_impl::load_log(const std::vector<boost::property_tree::ptree> &_trees) { +void configuration_impl::load_log(const std::vector<element> &_elements) { + std::set<std::string> its_warnings; + // Read the logger configuration(s) - for (auto t : _trees) - get_logging_configuration(t); + for (auto e : _elements) + get_logging_configuration(e, its_warnings); // Initialize logger logger_impl::init(the_configuration); + + // Print warnings after(!) logger initialization + for (auto w : its_warnings) + VSOMEIP_WARNING << w; } void configuration_impl::get_logging_configuration( - const boost::property_tree::ptree &_tree) { + const element &_element, std::set<std::string> &_warnings) { try { - auto its_logging = _tree.get_child("logging"); + auto its_logging = _element.tree_.get_child("logging"); for (auto i = its_logging.begin(); i != its_logging.end(); ++i) { std::string its_key(i->first); if (its_key == "console") { - std::string its_value(i->second.data()); - has_console_log_ = (its_value == "true"); + if (is_configured_[ET_LOGGING_CONSOLE]) { + _warnings.insert("Multiple definitions for logging.console." + " Ignoring definition from " + _element.name_); + } else { + std::string its_value(i->second.data()); + has_console_log_ = (its_value == "true"); + is_configured_[ET_LOGGING_CONSOLE] = true; + } } else if (its_key == "file") { - for (auto j : i->second) { - std::string its_sub_key(j.first); - std::string its_sub_value(j.second.data()); - if (its_sub_key == "enable") { - has_file_log_ = (its_sub_value == "true"); - } else if (its_sub_key == "path") { - logfile_ = its_sub_value; + if (is_configured_[ET_LOGGING_FILE]) { + _warnings.insert("Multiple definitions for logging.file." + " Ignoring definition from " + _element.name_); + } else { + for (auto j : i->second) { + std::string its_sub_key(j.first); + std::string its_sub_value(j.second.data()); + if (its_sub_key == "enable") { + has_file_log_ = (its_sub_value == "true"); + } else if (its_sub_key == "path") { + logfile_ = its_sub_value; + } } + is_configured_[ET_LOGGING_FILE] = true; } } else if (its_key == "dlt") { - std::string its_value(i->second.data()); - has_dlt_log_ = (its_value == "true"); + if (is_configured_[ET_LOGGING_DLT]) { + _warnings.insert("Multiple definitions for logging.dlt." + " Ignoring definition from " + _element.name_); + } else { + std::string its_value(i->second.data()); + has_dlt_log_ = (its_value == "true"); + is_configured_[ET_LOGGING_DLT] = true; + } } else if (its_key == "level") { - std::string its_value(i->second.data()); - loglevel_ - = (its_value == "trace" ? - boost::log::trivial::severity_level::trace : - (its_value == "debug" ? - boost::log::trivial::severity_level::debug : - (its_value == "info" ? - boost::log::trivial::severity_level::info : - (its_value == "warning" ? - boost::log::trivial::severity_level::warning : - (its_value == "error" ? - boost::log::trivial::severity_level::error : - (its_value == "fatal" ? - boost::log::trivial::severity_level::fatal : - boost::log::trivial::severity_level::info)))))); + if (is_configured_[ET_LOGGING_LEVEL]) { + _warnings.insert("Multiple definitions for logging.level." + " Ignoring definition from " + _element.name_); + } else { + std::string its_value(i->second.data()); + loglevel_ + = (its_value == "trace" ? + boost::log::trivial::severity_level::trace : + (its_value == "debug" ? + boost::log::trivial::severity_level::debug : + (its_value == "info" ? + boost::log::trivial::severity_level::info : + (its_value == "warning" ? + boost::log::trivial::severity_level::warning : + (its_value == "error" ? + boost::log::trivial::severity_level::error : + (its_value == "fatal" ? + boost::log::trivial::severity_level::fatal : + boost::log::trivial::severity_level::info)))))); + is_configured_[ET_LOGGING_LEVEL] = true; + } } } } catch (...) { @@ -215,10 +288,34 @@ void configuration_impl::get_logging_configuration( } void configuration_impl::get_someip_configuration( - const boost::property_tree::ptree &_tree) { + const element &_element) { + try { + if (is_configured_[ET_UNICAST]) { + VSOMEIP_WARNING << "Multiple definitions for unicast." + "Ignoring definition from " << _element.name_; + } else { + std::string its_value = _element.tree_.get<std::string>("unicast"); + unicast_ = unicast_.from_string(its_value); + is_configured_[ET_UNICAST] = true; + } + } catch (...) { + } try { - std::string its_value = _tree.get<std::string>("unicast"); - unicast_ = unicast_.from_string(its_value); + if (is_configured_[ET_DIAGNOSIS]) { + VSOMEIP_WARNING << "Multiple definitions for diagnosis." + "Ignoring definition from " << _element.name_; + } else { + std::string its_value = _element.tree_.get<std::string>("diagnosis"); + std::stringstream its_converter; + + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> diagnosis_; + is_configured_[ET_DIAGNOSIS] = true; + } } catch (...) { } } @@ -240,6 +337,17 @@ void configuration_impl::get_services_configuration( } } +void configuration_impl::get_clients_configuration( + const boost::property_tree::ptree &_tree) { + try { + auto its_clients = _tree.get_child("clients"); + for (auto i = its_clients.begin(); i != its_clients.end(); ++i) + get_client_configuration(i->second); + } catch (...) { + // intentionally left empty! + } +} + void configuration_impl::get_payload_sizes_configuration( const boost::property_tree::ptree &_tree) { const std::string payload_sizes("payload-sizes"); @@ -364,7 +472,6 @@ void configuration_impl::get_service_configuration( its_service->unicast_address_ = _unicast_address; its_service->multicast_address_ = ""; its_service->multicast_port_ = ILLEGAL_PORT; - its_service->multicast_group_ = 0xFFFF; // TODO: use symbolic constant its_service->protocol_ = "someip"; for (auto i = _tree.begin(); i != _tree.end(); ++i) { @@ -383,6 +490,9 @@ void configuration_impl::get_service_configuration( its_converter << its_value; its_converter >> its_service->reliable_; } + if(!its_service->reliable_) { + its_service->reliable_ = ILLEGAL_PORT; + } try { its_value = i->second.get_child("enable-magic-cookies").data(); @@ -393,6 +503,9 @@ void configuration_impl::get_service_configuration( } else if (its_key == "unreliable") { its_converter << its_value; its_converter >> its_service->unreliable_; + if(!its_service->unreliable_) { + its_service->unreliable_ = ILLEGAL_PORT; + } } else if (its_key == "multicast") { try { its_value = i->second.get_child("address").data(); @@ -410,7 +523,7 @@ void configuration_impl::get_service_configuration( get_eventgroup_configuration(its_service, i->second); } else { // Trim "its_value" - if (its_value[0] == '0' && its_value[1] == 'x') { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { its_converter << std::hex << its_value; } else { its_converter << std::dec << its_value; @@ -429,6 +542,9 @@ void configuration_impl::get_service_configuration( auto found_instance = found_service->second.find( its_service->instance_); if (found_instance != found_service->second.end()) { + VSOMEIP_WARNING << "Multiple configurations for service [" + << std::hex << its_service->service_ << "." + << its_service->instance_ << "]"; is_loaded = false; } } @@ -437,14 +553,84 @@ void configuration_impl::get_service_configuration( services_[its_service->service_][its_service->instance_] = its_service; if (use_magic_cookies) { - magic_cookies_[its_service->unicast_address_].insert( - its_service->reliable_); + magic_cookies_[get_unicast_address(its_service->service_, + its_service->instance_)].insert(its_service->reliable_); } } } catch (...) { } } +void configuration_impl::get_client_configuration( + const boost::property_tree::ptree &_tree) { + try { + bool is_loaded(true); + + std::shared_ptr<client> its_client(std::make_shared<client>()); + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + + if (its_key == "reliable") { + its_client->ports_[true] = get_client_port_configuration(i->second); + } else if (its_key == "unreliable") { + its_client->ports_[false] = get_client_port_configuration(i->second); + } else { + // Trim "its_value" + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + + if (its_key == "service") { + its_converter >> its_client->service_; + } else if (its_key == "instance") { + its_converter >> its_client->instance_; + } + } + } + + auto found_service = clients_.find(its_client->service_); + if (found_service != clients_.end()) { + auto found_instance = found_service->second.find( + its_client->instance_); + if (found_instance != found_service->second.end()) { + VSOMEIP_ERROR << "Multiple client configurations for service [" + << std::hex << its_client->service_ << "." + << its_client->instance_ << "]"; + is_loaded = false; + } + } + + if (is_loaded) { + clients_[its_client->service_][its_client->instance_] = its_client; + } + } catch (...) { + } +} + +std::set<uint16_t> configuration_impl::get_client_port_configuration( + const boost::property_tree::ptree &_tree) { + std::set<uint16_t> its_ports; + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_value(i->second.data()); + uint16_t its_port_value; + + std::stringstream its_converter; + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_port_value; + its_ports.insert(its_port_value); + } + return its_ports; +} + void configuration_impl::get_event_configuration( std::shared_ptr<service> &_service, const boost::property_tree::ptree &_tree) { @@ -458,7 +644,7 @@ void configuration_impl::get_event_configuration( std::string its_value(j->second.data()); if (its_key == "event") { std::stringstream its_converter; - if (its_value[0] == '0' && its_value[1] == 'x') { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { its_converter << std::hex << its_value; } else { its_converter << std::dec << its_value; @@ -474,7 +660,10 @@ void configuration_impl::get_event_configuration( if (its_event_id > 0) { auto found_event = _service->events_.find(its_event_id); if (found_event != _service->events_.end()) { - found_event->second->is_field_ = its_is_field; + VSOMEIP_ERROR << "Multiple configurations for event [" + << std::hex << _service->service_ << "." + << _service->instance_ << "." + << its_event_id << "]"; } else { std::shared_ptr<event> its_event = std::make_shared<event>( its_event_id, its_is_field, its_is_reliable); @@ -487,17 +676,16 @@ void configuration_impl::get_event_configuration( void configuration_impl::get_eventgroup_configuration( std::shared_ptr<service> &_service, const boost::property_tree::ptree &_tree) { - bool is_multicast; for (auto i = _tree.begin(); i != _tree.end(); ++i) { - is_multicast = false; std::shared_ptr<eventgroup> its_eventgroup = std::make_shared<eventgroup>(); for (auto j = i->second.begin(); j != i->second.end(); ++j) { + std::stringstream its_converter; std::string its_key(j->first); if (its_key == "eventgroup") { - std::stringstream its_converter; + std::string its_value(j->second.data()); - if (its_value[0] == '0' && its_value[1] == 'x') { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { its_converter << std::hex << its_value; } else { its_converter << std::dec << its_value; @@ -505,13 +693,25 @@ void configuration_impl::get_eventgroup_configuration( its_converter >> its_eventgroup->id_; } else if (its_key == "is_multicast") { std::string its_value(j->second.data()); - is_multicast = (its_value == "true"); + if (its_value == "true") { + its_eventgroup->multicast_address_ = _service->multicast_address_; + its_eventgroup->multicast_port_ = _service->multicast_port_; + } + } else if (its_key == "multicast") { + try { + std::string its_value = j->second.get_child("address").data(); + its_eventgroup->multicast_address_ = its_value; + its_value = j->second.get_child("port").data(); + its_converter << its_value; + its_converter >> its_eventgroup->multicast_port_; + } catch (...) { + } } else if (its_key == "events") { for (auto k = j->second.begin(); k != j->second.end(); ++k) { std::stringstream its_converter; std::string its_value(k->second.data()); event_t its_event_id(0); - if (its_value[0] == '0' && its_value[1] == 'x') { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { its_converter << std::hex << its_value; } else { its_converter << std::dec << its_value; @@ -537,64 +737,170 @@ void configuration_impl::get_eventgroup_configuration( } if (its_eventgroup->id_ > 0) { - if (is_multicast) { - _service->multicast_group_ = its_eventgroup->id_; - } _service->eventgroups_[its_eventgroup->id_] = its_eventgroup; } } } -void configuration_impl::get_routing_configuration( - const boost::property_tree::ptree &_tree) { +void configuration_impl::get_routing_configuration(const element &_element) { try { - auto its_routing = _tree.get_child("routing"); - routing_host_ = its_routing.data(); + if (is_configured_[ET_ROUTING]) { + VSOMEIP_WARNING << "Multiple definitions of routing." + << " Ignoring definition from " << _element.name_; + } else { + auto its_routing = _element.tree_.get_child("routing"); + routing_host_ = its_routing.data(); + is_configured_[ET_ROUTING] = true; + } } catch (...) { } } +void configuration_impl::get_permission_configuration(const element &_element) { + const std::string file_permissions("file-permissions"); + try { + if (_element.tree_.get_child_optional(file_permissions)) { + auto its_permissions = _element.tree_.get_child(file_permissions); + for (auto i = its_permissions.begin(); i != its_permissions.end(); + ++i) { + std::string its_key(i->first); + std::stringstream its_converter; + if (its_key == "permissions-shm") { + std::string its_value(i->second.data()); + its_converter << std::oct << its_value; + its_converter >> permissions_shm_; + } else if (its_key == "umask") { + std::string its_value(i->second.data()); + its_converter << std::oct << its_value; + its_converter >> umask_; + } + } + } + } catch (...) { + } +} + +std::uint32_t configuration_impl::get_umask() const { + return umask_; +} + +std::uint32_t configuration_impl::get_permissions_shm() const { + return permissions_shm_; +} + void configuration_impl::get_service_discovery_configuration( - const boost::property_tree::ptree &_tree) { + const element &_element) { try { - auto its_service_discovery = _tree.get_child("service-discovery"); + auto its_service_discovery = _element.tree_.get_child("service-discovery"); for (auto i = its_service_discovery.begin(); i != its_service_discovery.end(); ++i) { std::string its_key(i->first); std::string its_value(i->second.data()); std::stringstream its_converter; if (its_key == "enable") { - is_sd_enabled_ = (its_value == "true"); + if (is_configured_[ET_SERVICE_DISCOVERY_ENABLE]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.enabled." + " Ignoring definition from " << _element.name_; + } else { + is_sd_enabled_ = (its_value == "true"); + is_configured_[ET_SERVICE_DISCOVERY_ENABLE] = true; + } } else if (its_key == "multicast") { - sd_multicast_ = its_value; + if (is_configured_[ET_SERVICE_DISCOVERY_MULTICAST]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.multicast." + " Ignoring definition from " << _element.name_; + } else { + sd_multicast_ = its_value; + is_configured_[ET_SERVICE_DISCOVERY_MULTICAST] = true; + } } else if (its_key == "port") { - its_converter << its_value; - its_converter >> sd_port_; + if (is_configured_[ET_SERVICE_DISCOVERY_PORT]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.port." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_port_; + if (!sd_port_) { + sd_port_ = VSOMEIP_SD_DEFAULT_PORT; + } else { + is_configured_[ET_SERVICE_DISCOVERY_PORT] = true; + } + } } else if (its_key == "protocol") { - sd_protocol_ = its_value; + if (is_configured_[ET_SERVICE_DISCOVERY_PROTOCOL]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.protocol." + " Ignoring definition from " << _element.name_; + } else { + sd_protocol_ = its_value; + is_configured_[ET_SERVICE_DISCOVERY_PROTOCOL] = true; + } } else if (its_key == "initial_delay_min") { - its_converter << its_value; - its_converter >> sd_initial_delay_min_; + if (is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MIN]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.initial_delay_min." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_initial_delay_min_; + is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MIN] = true; + } } else if (its_key == "initial_delay_max") { - its_converter << its_value; - its_converter >> sd_initial_delay_max_; + if (is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MAX]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.initial_delay_max." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_initial_delay_max_; + is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MAX] = true; + } } else if (its_key == "repetitions_base_delay") { - its_converter << its_value; - its_converter >> sd_repetitions_base_delay_; + if (is_configured_[ET_SERVICE_DISCOVERY_REPETITION_BASE_DELAY]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.repetition_base_delay." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_repetitions_base_delay_; + is_configured_[ET_SERVICE_DISCOVERY_REPETITION_BASE_DELAY] = true; + } } else if (its_key == "repetitions_max") { - int tmp; - its_converter << its_value; - its_converter >> tmp; - sd_repetitions_max_ = (uint8_t)tmp; + if (is_configured_[ET_SERVICE_DISCOVERY_REPETITION_MAX]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.repetition_max." + " Ignoring definition from " << _element.name_; + } else { + int tmp; + its_converter << its_value; + its_converter >> tmp; + sd_repetitions_max_ = (uint8_t)tmp; + is_configured_[ET_SERVICE_DISCOVERY_REPETITION_MAX] = true; + } } else if (its_key == "ttl") { - its_converter << its_value; - its_converter >> sd_ttl_; + if (is_configured_[ET_SERVICE_DISCOVERY_TTL]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.ttl." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_ttl_; + // We do _not_ accept 0 as this would mean "STOP OFFER" + if (sd_ttl_ == 0) sd_ttl_ = VSOMEIP_SD_DEFAULT_TTL; + else is_configured_[ET_SERVICE_DISCOVERY_TTL] = true; + } } else if (its_key == "cyclic_offer_delay") { - its_converter << its_value; - its_converter >> sd_cyclic_offer_delay_; + if (is_configured_[ET_SERVICE_DISCOVERY_CYCLIC_OFFER_DELAY]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.cyclic_offer_delay." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_cyclic_offer_delay_; + is_configured_[ET_SERVICE_DISCOVERY_CYCLIC_OFFER_DELAY] = true; + } } else if (its_key == "request_response_delay") { - its_converter << its_value; - its_converter >> sd_request_response_delay_; + if (is_configured_[ET_SERVICE_DISCOVERY_REQUEST_RESPONSE_DELAY]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.request_response_delay." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_request_response_delay_; + is_configured_[ET_SERVICE_DISCOVERY_REQUEST_RESPONSE_DELAY] = true; + } } } } catch (...) { @@ -602,24 +908,25 @@ void configuration_impl::get_service_discovery_configuration( } void configuration_impl::get_applications_configuration( - const boost::property_tree::ptree &_tree) { + const element &_element) { try { std::stringstream its_converter; - auto its_applications = _tree.get_child("applications"); + auto its_applications = _element.tree_.get_child("applications"); for (auto i = its_applications.begin(); i != its_applications.end(); ++i) { - get_application_configuration(i->second); + get_application_configuration(i->second, _element.name_); } } catch (...) { } } void configuration_impl::get_application_configuration( - const boost::property_tree::ptree &_tree) { + const boost::property_tree::ptree &_tree, const std::string &_file_name) { std::string its_name(""); - client_t its_id; - std::size_t its_num_dispatchers(0); + client_t its_id(0); + std::size_t its_max_dispatchers(VSOMEIP_MAX_DISPATCHERS); + std::size_t its_max_dispatch_time(VSOMEIP_MAX_DISPATCH_TIME); for (auto i = _tree.begin(); i != _tree.end(); ++i) { std::string its_key(i->first); std::string its_value(i->second.data()); @@ -627,23 +934,213 @@ void configuration_impl::get_application_configuration( if (its_key == "name") { its_name = its_value; } else if (its_key == "id") { - if (its_value[0] == '0' && its_value[1] == 'x') { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { its_converter << std::hex << its_value; } else { its_converter << std::dec << its_value; } its_converter >> its_id; - } else if (its_key == "num_dispatchers") { - if (its_value[0] == '0' && its_value[1] == 'x') { + } else if (its_key == "max_dispatchers") { + its_converter << std::dec << its_value; + its_converter >> its_max_dispatchers; + } else if (its_key == "max_dispatch_time") { + its_converter << std::dec << its_value; + its_converter >> its_max_dispatch_time; + } + } + if (its_name != "" && its_id != 0) { + if (applications_.find(its_name) == applications_.end()) { + if (!is_configured_client_id(its_id)) { + applications_[its_name] + = std::make_tuple(its_id, its_max_dispatchers, its_max_dispatch_time); + client_identifiers_.insert(its_id); + } else { + VSOMEIP_WARNING << "Multiple configurations for application " + << its_name << ". Ignoring a configuration from " + << _file_name; + } + } else { + VSOMEIP_WARNING << "Multiple configurations for application " + << its_name << ". Ignoring a configuration from " + << _file_name; + } + } +} + +void configuration_impl::get_trace_configuration(const element &_element) { + try { + std::stringstream its_converter; + auto its_trace_configuration = _element.tree_.get_child("tracing"); + for(auto i = its_trace_configuration.begin(); + i != its_trace_configuration.end(); + ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + if(its_key == "enable") { + if (is_configured_[ET_TRACING_ENABLE]) { + VSOMEIP_WARNING << "Multiple definitions of tracing.enable." + << " Ignoring definition from " << _element.name_; + } else { + trace_->is_enabled_ = (its_value == "true"); + is_configured_[ET_TRACING_ENABLE] = true; + } + } else if(its_key == "channels") { + get_trace_channels_configuration(i->second); + } else if(its_key == "filters") { + get_trace_filters_configuration(i->second); + } + } + } catch (...) { + } +} + +void configuration_impl::get_trace_channels_configuration( + const boost::property_tree::ptree &_tree) { + try { + for(auto i = _tree.begin(); i != _tree.end(); ++i) { + if(i == _tree.begin()) + trace_->channels_.clear(); + get_trace_channel_configuration(i->second); + } + } catch (...) { + } +} + +void configuration_impl::get_trace_channel_configuration( + const boost::property_tree::ptree &_tree) { + std::shared_ptr<trace_channel> its_channel = std::make_shared<trace_channel>(); + for(auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key = i->first; + std::string its_value = i->second.data(); + if(its_key == "name") { + its_channel->name_ = its_value; + } else if(its_key == "id") { + its_channel->id_ = its_value; + } + } + trace_->channels_.push_back(its_channel); +} + +void configuration_impl::get_trace_filters_configuration( + const boost::property_tree::ptree &_tree) { + try { + for(auto i = _tree.begin(); i != _tree.end(); ++i) { + get_trace_filter_configuration(i->second); + } + } catch (...) { + } +} + +void configuration_impl::get_trace_filter_configuration( + const boost::property_tree::ptree &_tree) { + std::shared_ptr<trace_filter_rule> its_filter_rule = std::make_shared<trace_filter_rule>(); + for(auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key = i->first; + std::string its_value = i->second.data(); + if(its_key == "channel") { + its_filter_rule->channel_ = its_value; + } else { + get_trace_filter_expressions(i->second, its_key, its_filter_rule); + } + } + trace_->filter_rules_.push_back(its_filter_rule); +} + +void configuration_impl::get_trace_filter_expressions( + const boost::property_tree::ptree &_tree, + std::string &_criteria, + std::shared_ptr<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; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_id; + _filter_rule->methods_.push_back(its_id); + } else if(_criteria == "clients") { + client_t its_id = NO_TRACE_FILTER_EXPRESSION; + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { its_converter << std::hex << its_value; } else { its_converter << std::dec << its_value; } - its_converter >> its_num_dispatchers; + its_converter >> its_id; + _filter_rule->clients_.push_back(its_id); } } - if (its_name != "" && its_id != 0) { - applications_[its_name] = {its_id, its_num_dispatchers}; +} + +void configuration_impl::get_supports_selective_broadcasts(const boost::property_tree::ptree &_tree) { + try { + auto its_service_discovery = _tree.get_child("supports_selective_broadcasts"); + for (auto i = its_service_discovery.begin(); + i != its_service_discovery.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + if (its_key == "address") { + supported_selective_addresses.insert(its_value); + } + } + } catch (...) { + } +} + +void configuration_impl::get_watchdog_configuration(const element &_element) { + watchdog_->is_enabeled_ = false; + watchdog_->timeout_in_ms_ = VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT; + watchdog_->missing_pongs_allowed_ = VSOMEIP_DEFAULT_MAX_MISSING_PONGS; + try { + auto its_service_discovery = _element.tree_.get_child("watchdog"); + for (auto i = its_service_discovery.begin(); + i != its_service_discovery.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + if (its_key == "enable") { + if (is_configured_[ET_WATCHDOG_ENABLE]) { + VSOMEIP_WARNING << "Multiple definitions of watchdog.enable." + " Ignoring definition from " << _element.name_; + } else { + watchdog_->is_enabeled_ = (its_value == "true"); + is_configured_[ET_WATCHDOG_ENABLE] = true; + } + } else if (its_key == "timeout") { + if (is_configured_[ET_WATCHDOG_TIMEOUT]) { + VSOMEIP_WARNING << "Multiple definitions of watchdog.timeout." + " Ignoring definition from " << _element.name_; + } else { + its_converter << std::dec << its_value; + its_converter >> watchdog_->timeout_in_ms_; + is_configured_[ET_WATCHDOG_TIMEOUT] = true; + } + } else if (its_key == "allowed_missing_pongs") { + if (is_configured_[ET_WATCHDOG_ALLOWED_MISSING_PONGS]) { + VSOMEIP_WARNING << "Multiple definitions of watchdog.allowed_missing_pongs." + " Ignoring definition from " << _element.name_; + } else { + its_converter << std::dec << its_value; + its_converter >> watchdog_->missing_pongs_allowed_; + is_configured_[ET_WATCHDOG_ALLOWED_MISSING_PONGS] = true; + } + } + } + } catch (...) { } } @@ -652,6 +1149,10 @@ const boost::asio::ip::address & configuration_impl::get_unicast_address() const return unicast_; } +unsigned short configuration_impl::get_diagnosis_address() const { + return diagnosis_; +} + bool configuration_impl::is_v4() const { return unicast_.is_v4(); } @@ -683,7 +1184,7 @@ boost::log::trivial::severity_level configuration_impl::get_loglevel() const { std::string configuration_impl::get_unicast_address(service_t _service, instance_t _instance) const { std::string its_unicast_address(""); - service *its_service = find_service(_service, _instance); + auto its_service = find_service(_service, _instance); if (its_service) { its_unicast_address = its_service->unicast_address_; } @@ -694,52 +1195,60 @@ std::string configuration_impl::get_unicast_address(service_t _service, return its_unicast_address; } -std::string configuration_impl::get_multicast_address(service_t _service, - instance_t _instance) const { - std::string its_multicast_address(""); - service *its_service = find_service(_service, _instance); - if (its_service) - its_multicast_address = its_service->multicast_address_; - return its_multicast_address; -} - -uint16_t configuration_impl::get_multicast_port(service_t _service, +uint16_t configuration_impl::get_reliable_port(service_t _service, instance_t _instance) const { - uint16_t its_multicast_port(ILLEGAL_PORT); - service *its_service = find_service(_service, _instance); + uint16_t its_reliable(ILLEGAL_PORT); + auto its_service = find_service(_service, _instance); if (its_service) - its_multicast_port = its_service->multicast_port_; - return its_multicast_port; -} + its_reliable = its_service->reliable_; -uint16_t configuration_impl::get_multicast_group(service_t _service, - instance_t _instance) const { - uint16_t its_multicast_group(0xFFFF); - service *its_service = find_service(_service, _instance); - if (its_service) - its_multicast_group = its_service->multicast_group_; - return its_multicast_group; + return its_reliable; } -uint16_t configuration_impl::get_reliable_port(service_t _service, +uint16_t configuration_impl::get_unreliable_port(service_t _service, instance_t _instance) const { - uint16_t its_reliable(ILLEGAL_PORT); - service *its_service = find_service(_service, _instance); + uint16_t its_unreliable = ILLEGAL_PORT; + auto its_service = find_service(_service, _instance); if (its_service) - its_reliable = its_service->reliable_; + its_unreliable = its_service->unreliable_; - return its_reliable; + return its_unreliable; } bool configuration_impl::is_someip(service_t _service, instance_t _instance) const { - service *its_service = find_service(_service, _instance); + auto its_service = find_service(_service, _instance); if (its_service) return (its_service->protocol_ == "someip"); return true; // we need to explicitely configure a service to // be something else than SOME/IP } +bool configuration_impl::get_client_port( + service_t _service, instance_t _instance, bool _reliable, + std::map<bool, std::set<uint16_t> > &_used, + uint16_t &_port) const { + _port = ILLEGAL_PORT; + auto its_client = find_client(_service, _instance); + + // If no client ports are configured, return true + if (!its_client || its_client->ports_[_reliable].empty()) { + return true; + } + + for (auto its_port : its_client->ports_[_reliable]) { + // Found free configured port + if (_used[_reliable].find(its_port) == _used[_reliable].end()) { + _port = its_port; + return true; + } + } + + // Configured ports do exist, but they are all in use + VSOMEIP_ERROR << "Cannot find free client port!"; + return false; +} + bool configuration_impl::has_enabled_magic_cookies(std::string _address, uint16_t _port) const { bool has_enabled(false); @@ -753,16 +1262,6 @@ bool configuration_impl::has_enabled_magic_cookies(std::string _address, return has_enabled; } -uint16_t configuration_impl::get_unreliable_port(service_t _service, - instance_t _instance) const { - uint16_t its_unreliable = ILLEGAL_PORT; - - service *its_service = find_service(_service, _instance); - if (its_service) - its_unreliable = its_service->unreliable_; - - return its_unreliable; -} const std::string & configuration_impl::get_routing_host() const { return routing_host_; @@ -773,22 +1272,38 @@ client_t configuration_impl::get_id(const std::string &_name) const { auto found_application = applications_.find(_name); if (found_application != applications_.end()) { - its_client = found_application->second.first; + its_client = std::get<0>(found_application->second); } return its_client; } -std::size_t configuration_impl::get_num_dispatchers( +bool configuration_impl::is_configured_client_id(client_t _id) const { + return (client_identifiers_.find(_id) != client_identifiers_.end()); +} + +std::size_t configuration_impl::get_max_dispatchers( + const std::string &_name) const { + std::size_t its_max_dispatchers = VSOMEIP_MAX_DISPATCHERS; + + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + its_max_dispatchers = std::get<1>(found_application->second); + } + + return its_max_dispatchers; +} + +std::size_t configuration_impl::get_max_dispatch_time( const std::string &_name) const { - std::size_t its_num_dispatchers = 0; + std::size_t its_max_dispatch_time = VSOMEIP_MAX_DISPATCH_TIME; auto found_application = applications_.find(_name); if (found_application != applications_.end()) { - its_num_dispatchers = found_application->second.second; + its_max_dispatch_time = std::get<2>(found_application->second); } - return its_num_dispatchers; + return its_max_dispatch_time; } std::set<std::pair<service_t, instance_t> > @@ -796,26 +1311,73 @@ configuration_impl::get_remote_services() const { std::set<std::pair<service_t, instance_t> > its_remote_services; for (auto i : services_) { for (auto j : i.second) { - if (j.second->unicast_address_ != "local" && j.second->unicast_address_ != "") + if (j.second->unicast_address_ != "local" && + j.second->unicast_address_ != "" && + j.second->unicast_address_ != unicast_.to_string() && + j.second->unicast_address_ != VSOMEIP_UNICAST_ADDRESS) its_remote_services.insert(std::make_pair(i.first, j.first)); } } return its_remote_services; } -service *configuration_impl::find_service(service_t _service, +bool configuration_impl::get_multicast(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + std::string &_address, uint16_t &_port) const +{ + std::shared_ptr<eventgroup> its_eventgroup + = find_eventgroup(_service, _instance, _eventgroup); + if (!its_eventgroup) + return false; + + if (its_eventgroup->multicast_address_.empty()) + return false; + + _address = its_eventgroup->multicast_address_; + _port = its_eventgroup->multicast_port_; + return true; +} + +std::shared_ptr<client> configuration_impl::find_client(service_t _service, + instance_t _instance) const { + std::shared_ptr<client> its_client; + auto find_service = clients_.find(_service); + if (find_service != clients_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + its_client = find_instance->second; + } + } + return its_client; +} + +std::shared_ptr<service> configuration_impl::find_service(service_t _service, instance_t _instance) const { - service *its_service(0); + std::shared_ptr<service> its_service; auto find_service = services_.find(_service); if (find_service != services_.end()) { auto find_instance = find_service->second.find(_instance); if (find_instance != find_service->second.end()) { - its_service = find_instance->second.get(); + its_service = find_instance->second; } } return its_service; } +std::shared_ptr<eventgroup> configuration_impl::find_eventgroup( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const { + std::shared_ptr<eventgroup> its_eventgroup; + auto its_service = find_service(_service, _instance); + if (its_service) { + auto find_eventgroup = its_service->eventgroups_.find(_eventgroup); + if (find_eventgroup != its_service->eventgroups_.end()) { + its_eventgroup = find_eventgroup->second; + } + } + return its_eventgroup; +} + std::uint32_t configuration_impl::get_max_message_size_local() const { uint32_t its_max_message_size = VSOMEIP_MAX_LOCAL_MESSAGE_SIZE; if (VSOMEIP_MAX_TCP_MESSAGE_SIZE > its_max_message_size) { @@ -832,7 +1394,7 @@ std::uint32_t configuration_impl::get_max_message_size_local() const { // to the routing_manager stub return std::uint32_t(its_max_message_size + VSOMEIP_COMMAND_HEADER_SIZE + sizeof(instance_t) - + sizeof(bool) + sizeof(bool)); + + sizeof(bool) + sizeof(bool) + sizeof(bool)); } std::uint32_t configuration_impl::get_message_size_reliable( @@ -847,6 +1409,10 @@ std::uint32_t configuration_impl::get_message_size_reliable( return VSOMEIP_MAX_TCP_MESSAGE_SIZE; } +bool configuration_impl::supports_selective_broadcasts(boost::asio::ip::address _address) const { + return supported_selective_addresses.find(_address.to_string()) != supported_selective_addresses.end(); +} + // Service Discovery configuration bool configuration_impl::is_sd_enabled() const { return is_sd_enabled_; @@ -892,5 +1458,24 @@ int32_t configuration_impl::get_sd_request_response_delay() const { return sd_request_response_delay_; } +// Trace configuration +std::shared_ptr<cfg::trace> configuration_impl::get_trace() const { + return trace_; +} + +// Watchdog config +bool configuration_impl::is_watchdog_enabled() const { + return watchdog_->is_enabeled_; +} + +uint32_t configuration_impl::get_watchdog_timeout() const { + return watchdog_->timeout_in_ms_; +} + +uint32_t configuration_impl::get_allowed_missing_pongs() const { + return watchdog_->missing_pongs_allowed_; +} + + } // namespace config } // namespace vsomeip diff --git a/implementation/endpoints/include/buffer.hpp b/implementation/endpoints/include/buffer.hpp index 5641117..1dac89a 100644 --- a/implementation/endpoints/include/buffer.hpp +++ b/implementation/endpoints/include/buffer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/endpoints/include/client_endpoint_impl.hpp b/implementation/endpoints/include/client_endpoint_impl.hpp index 29f42a3..f80e385 100644 --- a/implementation/endpoints/include/client_endpoint_impl.hpp +++ b/implementation/endpoints/include/client_endpoint_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -16,6 +16,8 @@ #include <boost/asio/ip/udp.hpp>
#include <boost/utility.hpp>
+#include <vsomeip/constants.hpp>
+
#include "buffer.hpp"
#include "endpoint_impl.hpp"
@@ -24,22 +26,23 @@ namespace vsomeip { class endpoint;
class endpoint_host;
-template<typename Protocol, int MaxBufferSize>
-class client_endpoint_impl: public endpoint_impl<MaxBufferSize>,
- public std::enable_shared_from_this<
- client_endpoint_impl<Protocol, MaxBufferSize> > {
+template<typename Protocol>
+class client_endpoint_impl: public endpoint_impl<Protocol>,
+ public std::enable_shared_from_this<client_endpoint_impl<Protocol> > {
public:
+ typedef typename Protocol::endpoint endpoint_type;
typedef typename Protocol::socket socket_type;
- typedef typename Protocol::endpoint endpoint_type;
client_endpoint_impl(std::shared_ptr<endpoint_host> _host,
- endpoint_type _remote, boost::asio::io_service &_io,
+ endpoint_type _local, endpoint_type _remote,
+ boost::asio::io_service &_io,
std::uint32_t _max_message_size);
virtual ~client_endpoint_impl();
- bool send(const uint8_t *_data, uint32_t _size, bool _flush);bool send_to(
- const std::shared_ptr<endpoint_definition> _target,
- const byte_t *_data, uint32_t _size, bool _flush = true);bool flush();
+ bool send(const uint8_t *_data, uint32_t _size, bool _flush);
+ bool send_to(const std::shared_ptr<endpoint_definition> _target,
+ const byte_t *_data, uint32_t _size, bool _flush = true);
+ bool flush();
void stop();
void restart();
@@ -64,6 +67,8 @@ protected: socket_type socket_;
endpoint_type remote_;
+ uint16_t local_port_;
+
boost::asio::system_timer flush_timer_;
boost::asio::system_timer connect_timer_;
uint32_t connect_timeout_;
@@ -74,6 +79,8 @@ protected: std::deque<message_buffer_ptr_t> queue_;
std::mutex mutex_;
+
+ bool was_not_connected_;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/endpoint.hpp b/implementation/endpoints/include/endpoint.hpp index 6acf164..c063f2a 100644 --- a/implementation/endpoints/include/endpoint.hpp +++ b/implementation/endpoints/include/endpoint.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -33,9 +33,9 @@ public: virtual void join(const std::string &_address) = 0;
virtual void leave(const std::string &_address) = 0;
- virtual void add_multicast(service_t _service, event_t _event,
+ virtual void add_default_target(service_t _service,
const std::string &_address, uint16_t _port) = 0;
- virtual void remove_multicast(service_t _service, event_t _event) = 0;
+ virtual void remove_default_target(service_t _service) = 0;
virtual bool get_remote_address(boost::asio::ip::address &_address) const = 0;
virtual unsigned short get_local_port() const = 0;
diff --git a/implementation/endpoints/include/endpoint_definition.hpp b/implementation/endpoints/include/endpoint_definition.hpp index d7fb3a2..e4a3290 100644 --- a/implementation/endpoints/include/endpoint_definition.hpp +++ b/implementation/endpoints/include/endpoint_definition.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/endpoints/include/endpoint_host.hpp b/implementation/endpoints/include/endpoint_host.hpp index d526ab4..1c78f39 100644 --- a/implementation/endpoints/include/endpoint_host.hpp +++ b/implementation/endpoints/include/endpoint_host.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -8,6 +8,8 @@ #include <memory> +#include <boost/asio/ip/address.hpp> + #include <vsomeip/primitive_types.hpp> namespace vsomeip { @@ -21,9 +23,11 @@ public: virtual void on_connect(std::shared_ptr<endpoint> _endpoint) = 0; virtual void on_disconnect(std::shared_ptr<endpoint> _endpoint) = 0; virtual void on_message(const byte_t *_data, length_t _length, - endpoint *_receiver) = 0; + endpoint *_receiver, const boost::asio::ip::address &_destination + = boost::asio::ip::address()) = 0; virtual void on_error(const byte_t *_data, length_t _length, endpoint *_receiver) = 0; + virtual void release_port(uint16_t _port, bool _reliable) = 0; }; } // namespace vsomeip diff --git a/implementation/endpoints/include/endpoint_impl.hpp b/implementation/endpoints/include/endpoint_impl.hpp index 5d8350a..bd05698 100644 --- a/implementation/endpoints/include/endpoint_impl.hpp +++ b/implementation/endpoints/include/endpoint_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -19,10 +19,13 @@ namespace vsomeip { class endpoint_host;
-template<int MaxBufferSize>
+template<typename Protocol>
class endpoint_impl: public endpoint {
public:
+ typedef typename Protocol::endpoint endpoint_type;
+
endpoint_impl(std::shared_ptr<endpoint_host> _adapter,
+ endpoint_type _local,
boost::asio::io_service &_io,
std::uint32_t _max_message_size);
virtual ~endpoint_impl();
@@ -33,11 +36,10 @@ public: // TODO: redesign
void join(const std::string &);
void leave(const std::string &);
- void add_multicast(service_t, event_t, const std::string &, uint16_t);
- void remove_multicast(service_t, event_t);
- // Dummy implementation as we only need this for IP client endpoints
- // TODO: redesign
+ void add_default_target(service_t, const std::string &, uint16_t);
+ void remove_default_target(service_t);
+
bool get_remote_address(boost::asio::ip::address &_address) const;
// Dummy implementations as we only need these for server endpoints
@@ -76,6 +78,10 @@ protected: std::uint32_t max_message_size_;
uint32_t use_count_;
+
+ bool sending_blocked_;
+
+ endpoint_type local_;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/local_client_endpoint_impl.hpp b/implementation/endpoints/include/local_client_endpoint_impl.hpp index 97f01ce..a6d777e 100644 --- a/implementation/endpoints/include/local_client_endpoint_impl.hpp +++ b/implementation/endpoints/include/local_client_endpoint_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -20,17 +20,19 @@ namespace vsomeip { #ifdef WIN32 -typedef client_endpoint_impl<boost::asio::ip::tcp, - VSOMEIP_MAX_TCP_MESSAGE_SIZE > local_client_endpoint_base_impl; +typedef client_endpoint_impl< + boost::asio::ip::tcp + > local_client_endpoint_base_impl; #else -typedef client_endpoint_impl<boost::asio::local::stream_protocol, - VSOMEIP_MAX_LOCAL_MESSAGE_SIZE> local_client_endpoint_base_impl; +typedef client_endpoint_impl< + boost::asio::local::stream_protocol + > local_client_endpoint_base_impl; #endif class local_client_endpoint_impl: public local_client_endpoint_base_impl { public: local_client_endpoint_impl(std::shared_ptr<endpoint_host> _host, - endpoint_type _local, + endpoint_type _remote, boost::asio::io_service &_io, std::uint32_t _max_message_size); @@ -43,21 +45,10 @@ public: private: void send_queued(); - void send_start_tag(); - void send_queued_data(); - void send_end_tag(); - void send_magic_cookie(); void connect(); void receive(); - - void send_start_tag_cbk(boost::system::error_code const &_error, - std::size_t _bytes); - void send_queued_data_cbk(boost::system::error_code const &_error, - std::size_t _bytes); - void receive_cbk(boost::system::error_code const &_error, - std::size_t _bytes); }; } // namespace vsomeip diff --git a/implementation/endpoints/include/local_server_endpoint_impl.hpp b/implementation/endpoints/include/local_server_endpoint_impl.hpp index 626b30e..d8f5288 100644 --- a/implementation/endpoints/include/local_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/local_server_endpoint_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -24,11 +24,13 @@ namespace vsomeip { #ifdef WIN32 -typedef server_endpoint_impl<boost::asio::ip::tcp, - VSOMEIP_MAX_TCP_MESSAGE_SIZE > local_server_endpoint_base_impl; +typedef server_endpoint_impl< + boost::asio::ip::tcp + > local_server_endpoint_base_impl; #else -typedef server_endpoint_impl<boost::asio::local::stream_protocol, - VSOMEIP_MAX_LOCAL_MESSAGE_SIZE> local_server_endpoint_base_impl; +typedef server_endpoint_impl< + boost::asio::local::stream_protocol + > local_server_endpoint_base_impl; #endif class local_server_endpoint_impl: public local_server_endpoint_base_impl { @@ -51,10 +53,12 @@ public: void send_queued(queue_iterator_type _queue_iterator); endpoint_type get_remote() const; - bool get_multicast(service_t, event_t, endpoint_type &) const; + bool get_default_target(service_t, endpoint_type &) const; bool is_local() const; + bool queue_message(const byte_t *_data, uint32_t _size); + private: class connection: public boost::enable_shared_from_this<connection> { @@ -69,6 +73,8 @@ private: void send_queued(queue_iterator_type _queue_iterator); + bool queue_message(const byte_t *_data, uint32_t _size); + private: connection(local_server_endpoint_impl *_owner, std::uint32_t _max_message_size); @@ -82,6 +88,8 @@ private: receive_buffer_t recv_buffer_; size_t recv_buffer_size_; + static std::vector<byte_t> queued_data_; + private: void receive_cbk(boost::system::error_code const &_error, std::size_t _bytes); @@ -94,7 +102,7 @@ private: #endif std::map<endpoint_type, connection::ptr> connections_; - connection *current_; + connection::ptr current_; private: void remove_connection(connection *_connection); diff --git a/implementation/endpoints/include/server_endpoint_impl.hpp b/implementation/endpoints/include/server_endpoint_impl.hpp index c51cb49..15d001b 100644 --- a/implementation/endpoints/include/server_endpoint_impl.hpp +++ b/implementation/endpoints/include/server_endpoint_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -21,25 +21,26 @@ namespace vsomeip {
-template<typename Protocol, int MaxBufferSize>
-class server_endpoint_impl: public endpoint_impl<MaxBufferSize>,
- public std::enable_shared_from_this<
- server_endpoint_impl<Protocol, MaxBufferSize> > {
+template<typename Protocol>
+class server_endpoint_impl: public endpoint_impl<Protocol>,
+ public std::enable_shared_from_this<server_endpoint_impl<Protocol> > {
public:
typedef typename Protocol::socket socket_type;
typedef typename Protocol::endpoint endpoint_type;
- typedef boost::array<uint8_t, MaxBufferSize> buffer_type;
typedef typename std::map<endpoint_type, std::deque<message_buffer_ptr_t> > queue_type;
typedef typename queue_type::iterator queue_iterator_type;
server_endpoint_impl(std::shared_ptr<endpoint_host> _host,
endpoint_type _local, boost::asio::io_service &_io,
std::uint32_t _max_message_size);
+ virtual ~server_endpoint_impl();
bool is_client() const;
bool is_connected() const;
bool send(const uint8_t *_data, uint32_t _size, bool _flush);
+
+ virtual void stop();
bool flush(endpoint_type _target);
public:
@@ -55,19 +56,19 @@ public: virtual void send_queued(queue_iterator_type _queue_iterator) = 0;
virtual endpoint_type get_remote() const = 0;
- virtual bool get_multicast(service_t _service, event_t _event,
- endpoint_type &_target) const = 0;
+
+ virtual bool get_default_target(service_t _service,
+ endpoint_type &_target) const = 0;
protected:
std::map<endpoint_type, message_buffer_ptr_t> packetizer_;
queue_type queues_;
+ std::mutex clients_mutex_;
std::map<client_t, std::map<session_t, endpoint_type> > clients_;
boost::asio::system_timer flush_timer_;
- endpoint_type local_;
-
std::mutex mutex_;
};
diff --git a/implementation/endpoints/include/tcp_client_endpoint_impl.hpp b/implementation/endpoints/include/tcp_client_endpoint_impl.hpp index e5bf987..e6aaa33 100644 --- a/implementation/endpoints/include/tcp_client_endpoint_impl.hpp +++ b/implementation/endpoints/include/tcp_client_endpoint_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -13,13 +13,15 @@ namespace vsomeip {
-typedef client_endpoint_impl<boost::asio::ip::tcp,
- VSOMEIP_MAX_TCP_MESSAGE_SIZE> tcp_client_endpoint_base_impl;
+typedef client_endpoint_impl<
+ boost::asio::ip::tcp
+ > tcp_client_endpoint_base_impl;
class tcp_client_endpoint_impl: public tcp_client_endpoint_base_impl {
public:
tcp_client_endpoint_impl(std::shared_ptr<endpoint_host> _host,
endpoint_type _local,
+ endpoint_type _remote,
boost::asio::io_service &_io,
std::uint32_t _max_message_size);
virtual ~tcp_client_endpoint_impl();
diff --git a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp index 7295868..16197cc 100644 --- a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -12,12 +12,14 @@ #include <boost/enable_shared_from_this.hpp>
#include <vsomeip/defines.hpp>
+#include <vsomeip/export.hpp>
#include "server_endpoint_impl.hpp"
namespace vsomeip {
-typedef server_endpoint_impl<boost::asio::ip::tcp,
- VSOMEIP_MAX_TCP_MESSAGE_SIZE> tcp_server_endpoint_base_impl;
+typedef server_endpoint_impl<
+ boost::asio::ip::tcp
+ > tcp_server_endpoint_base_impl;
class tcp_server_endpoint_impl: public tcp_server_endpoint_base_impl {
@@ -35,9 +37,12 @@ public: const byte_t *_data, uint32_t _size, bool _flush);
void send_queued(queue_iterator_type _queue_iterator);
+ VSOMEIP_EXPORT bool is_established(std::shared_ptr<endpoint_definition> _endpoint);
+
endpoint_type get_remote() const;
bool get_remote_address(boost::asio::ip::address &_address) const;
- bool get_multicast(service_t, event_t, endpoint_type &) const;
+ unsigned short get_remote_port() const;
+ bool get_default_target(service_t, endpoint_type &) const;
unsigned short get_local_port() const;
bool is_reliable() const;
diff --git a/implementation/endpoints/include/udp_client_endpoint_impl.hpp b/implementation/endpoints/include/udp_client_endpoint_impl.hpp index 4a51db6..07d2179 100644 --- a/implementation/endpoints/include/udp_client_endpoint_impl.hpp +++ b/implementation/endpoints/include/udp_client_endpoint_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -19,13 +19,15 @@ namespace vsomeip { class endpoint_adapter;
-typedef client_endpoint_impl<boost::asio::ip::udp,
- VSOMEIP_MAX_UDP_MESSAGE_SIZE> udp_client_endpoint_base_impl;
+typedef client_endpoint_impl<
+ boost::asio::ip::udp
+ > udp_client_endpoint_base_impl;
class udp_client_endpoint_impl: virtual public udp_client_endpoint_base_impl {
public:
udp_client_endpoint_impl(std::shared_ptr<endpoint_host> _host,
+ endpoint_type _local,
endpoint_type _remote,
boost::asio::io_service &_io);
virtual ~udp_client_endpoint_impl();
@@ -46,7 +48,6 @@ private: void receive();
receive_buffer_t recv_buffer_;
- size_t recv_buffer_size_;
};
} // namespace vsomeip
diff --git a/implementation/endpoints/include/udp_server_endpoint_impl.hpp b/implementation/endpoints/include/udp_server_endpoint_impl.hpp index c03a7b4..907e022 100644 --- a/implementation/endpoints/include/udp_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/udp_server_endpoint_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -7,15 +7,17 @@ #define VSOMEIP_INTERNAL_UDP_SERVICE_IMPL_HPP
#include <boost/asio/io_service.hpp>
-#include <boost/asio/ip/udp.hpp>
+#include <boost/asio/ip/udp_ext.hpp>
#include <vsomeip/defines.hpp>
+
#include "server_endpoint_impl.hpp"
namespace vsomeip {
-typedef server_endpoint_impl<boost::asio::ip::udp,
- VSOMEIP_MAX_UDP_MESSAGE_SIZE> udp_server_endpoint_base_impl;
+typedef server_endpoint_impl<
+ boost::asio::ip::udp_ext
+ > udp_server_endpoint_base_impl;
class udp_server_endpoint_impl: public udp_server_endpoint_base_impl {
@@ -37,14 +39,15 @@ public: endpoint_type get_remote() const;
bool get_remote_address(boost::asio::ip::address &_address) const;
- bool get_multicast(service_t _service, event_t _event,
- endpoint_type &_target) const;
+ unsigned short get_remote_port() const;
void join(const std::string &_address);
void leave(const std::string &_address);
- void add_multicast(service_t _service, instance_t _instance,
- const std::string &_address, uint16_t _port);
- void remove_multicast(service_t _service, instance_t _instance);
+
+ void add_default_target(service_t _service,
+ const std::string &_address, uint16_t _port);
+ void remove_default_target(service_t _service);
+ bool get_default_target(service_t _service, endpoint_type &_target) const;
unsigned short get_local_port() const;
bool is_local() const;
@@ -53,18 +56,21 @@ public: public:
void receive_cbk(boost::system::error_code const &_error,
- std::size_t _size);
+ std::size_t _size,
+ boost::asio::ip::address const &_destination);
private:
void set_broadcast();
+ bool is_joined(const std::string &_address) const;
private:
socket_type socket_;
endpoint_type remote_;
- std::map<service_t, std::map<instance_t, endpoint_type> > multicasts_;
+
+ std::map<service_t, endpoint_type> default_targets_;
+ std::set<std::string> joined_;
receive_buffer_t recv_buffer_;
- size_t recv_buffer_size_;
std::mutex stop_mutex_;
};
diff --git a/implementation/endpoints/include/virtual_server_endpoint_impl.hpp b/implementation/endpoints/include/virtual_server_endpoint_impl.hpp index 12484f5..2fd7005 100644 --- a/implementation/endpoints/include/virtual_server_endpoint_impl.hpp +++ b/implementation/endpoints/include/virtual_server_endpoint_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -35,9 +35,9 @@ public: void join(const std::string &_address); void leave(const std::string &_address); - void add_multicast(service_t _service, event_t _event, + void add_default_target(service_t _service, const std::string &_address, uint16_t _port); - void remove_multicast(service_t _service, event_t _event); + void remove_default_target(service_t _service); bool get_remote_address(boost::asio::ip::address &_address) const; unsigned short get_local_port() const; diff --git a/implementation/endpoints/src/client_endpoint_impl.cpp b/implementation/endpoints/src/client_endpoint_impl.cpp index 6ed812a..f68bad7 100644 --- a/implementation/endpoints/src/client_endpoint_impl.cpp +++ b/implementation/endpoints/src/client_endpoint_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -23,46 +23,74 @@ namespace vsomeip {
-template<typename Protocol, int MaxBufferSize>
-client_endpoint_impl<Protocol, MaxBufferSize>::client_endpoint_impl(
- std::shared_ptr<endpoint_host> _host, endpoint_type _remote,
- boost::asio::io_service &_io, std::uint32_t _max_message_size)
- : endpoint_impl<MaxBufferSize>(_host, _io, _max_message_size),
+template<typename Protocol>
+client_endpoint_impl<Protocol>::client_endpoint_impl(
+ std::shared_ptr<endpoint_host> _host,
+ endpoint_type _local,
+ endpoint_type _remote,
+ boost::asio::io_service &_io,
+ std::uint32_t _max_message_size)
+ : endpoint_impl<Protocol>(_host, _local, _io, _max_message_size),
socket_(_io), remote_(_remote),
flush_timer_(_io), connect_timer_(_io),
connect_timeout_(VSOMEIP_DEFAULT_CONNECT_TIMEOUT), // TODO: use config variable
is_connected_(false),
- packetizer_(std::make_shared<message_buffer_t>()) {
+ packetizer_(std::make_shared<message_buffer_t>()),
+ was_not_connected_(false) {
}
-template<typename Protocol, int MaxBufferSize>
-client_endpoint_impl<Protocol, MaxBufferSize>::~client_endpoint_impl() {
+template<typename Protocol>
+client_endpoint_impl<Protocol>::~client_endpoint_impl() {
}
-template<typename Protocol, int MaxBufferSize>
-bool client_endpoint_impl<Protocol, MaxBufferSize>::is_client() const {
+template<typename Protocol>
+bool client_endpoint_impl<Protocol>::is_client() const {
return true;
}
-template<typename Protocol, int MaxBufferSize>
-bool client_endpoint_impl<Protocol, MaxBufferSize>::is_connected() const {
+template<typename Protocol>
+bool client_endpoint_impl<Protocol>::is_connected() const {
return is_connected_;
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::stop() {
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::stop() {
if (socket_.is_open()) {
- socket_.close();
+ connect_timer_.cancel();
+ connect_timeout_ = VSOMEIP_DEFAULT_CONNECT_TIMEOUT;
+ endpoint_impl<Protocol>::sending_blocked_ = true;
+ bool send_queue_empty(false);
+ std::uint32_t times_slept(0);
+
+ while (times_slept <= 50) {
+ mutex_.lock();
+ send_queue_empty = (queue_.size() == 0);
+ mutex_.unlock();
+ if (send_queue_empty) {
+ break;
+ } else {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ times_slept++;
+ }
+ }
+
+ boost::system::error_code its_error;
+ socket_.close(its_error);
}
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::restart() {
- receive();
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::restart() {
+ is_connected_ = false;
+ connect_timer_.expires_from_now(
+ std::chrono::milliseconds(connect_timeout_));
+ connect_timer_.async_wait(
+ std::bind(&client_endpoint_impl<Protocol>::wait_connect_cbk,
+ this->shared_from_this(), std::placeholders::_1));
}
-template<typename Protocol, int MaxBufferSize>
-bool client_endpoint_impl<Protocol, MaxBufferSize>::send_to(
+template<typename Protocol>
+bool client_endpoint_impl<Protocol>::send_to(
const std::shared_ptr<endpoint_definition> _target, const byte_t *_data,
uint32_t _size, bool _flush) {
(void)_target;
@@ -70,16 +98,18 @@ bool client_endpoint_impl<Protocol, MaxBufferSize>::send_to( (void)_size;
(void)_flush;
- VSOMEIP_ERROR<< "Clients endpoints must not be used to "
- << "send to explicitely specified targets";
+ VSOMEIP_ERROR << "Clients endpoints must not be used to "
+ << "send to explicitely specified targets";
return false;
}
-template<typename Protocol, int MaxBufferSize>
-bool client_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data,
+template<typename Protocol>
+bool client_endpoint_impl<Protocol>::send(const uint8_t *_data,
uint32_t _size, bool _flush) {
std::lock_guard<std::mutex> its_lock(mutex_);
- bool is_flushing(false);
+ if (endpoint_impl<Protocol>::sending_blocked_) {
+ return false;
+ }
#if 0
std::stringstream msg;
msg << "cei::send: ";
@@ -89,9 +119,10 @@ bool client_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data, VSOMEIP_DEBUG << msg.str();
#endif
- if (packetizer_->size() + _size > endpoint_impl<MaxBufferSize>::max_message_size_) {
+ const bool queue_size_zero_on_entry(queue_.empty());
+ if (packetizer_->size() + _size > endpoint_impl<Protocol>::max_message_size_
+ && !packetizer_->empty()) {
queue_.push_back(packetizer_);
- is_flushing = true;
packetizer_ = std::make_shared<message_buffer_t>();
}
@@ -100,28 +131,26 @@ bool client_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data, if (_flush) {
flush_timer_.cancel();
queue_.push_back(packetizer_);
- is_flushing = true;
packetizer_ = std::make_shared<message_buffer_t>();
} else {
flush_timer_.expires_from_now(
std::chrono::milliseconds(VSOMEIP_DEFAULT_FLUSH_TIMEOUT)); // TODO: use config variable
flush_timer_.async_wait(
std::bind(
- &client_endpoint_impl<
- Protocol, MaxBufferSize>::flush_cbk,
+ &client_endpoint_impl<Protocol>::flush_cbk,
this->shared_from_this(),
std::placeholders::_1));
}
- if (is_flushing && queue_.size() == 1) { // no writing in progress
+ if (queue_size_zero_on_entry && !queue_.empty()) { // no writing in progress
send_queued();
}
return (true);
}
-template<typename Protocol, int MaxBufferSize>
-bool client_endpoint_impl<Protocol, MaxBufferSize>::flush() {
+template<typename Protocol>
+bool client_endpoint_impl<Protocol>::flush() {
bool is_successful(true);
if (!packetizer_->empty()) {
@@ -138,23 +167,26 @@ bool client_endpoint_impl<Protocol, MaxBufferSize>::flush() { return is_successful;
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::connect_cbk(
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::connect_cbk(
boost::system::error_code const &_error) {
std::shared_ptr<endpoint_host> its_host = this->host_.lock();
if (its_host) {
- if (_error) {
- socket_.close();
+ if (_error && _error != boost::asio::error::already_connected) {
+ if(socket_.is_open()) {
+ boost::system::error_code its_error;
+ socket_.close(its_error);
+ }
connect_timer_.expires_from_now(
std::chrono::milliseconds(connect_timeout_));
connect_timer_.async_wait(
- std::bind(&client_endpoint_impl<
- Protocol, MaxBufferSize>::wait_connect_cbk,
+ std::bind(&client_endpoint_impl<Protocol>::wait_connect_cbk,
this->shared_from_this(), std::placeholders::_1));
- // next time we wait longer
- connect_timeout_ <<= 1;
+ // Double the timeout as long as the maximum allowed is larger
+ if (connect_timeout_ < VSOMEIP_MAX_CONNECT_TIMEOUT)
+ connect_timeout_ <<= 1;
if (is_connected_) {
is_connected_ = false;
@@ -170,37 +202,54 @@ void client_endpoint_impl<Protocol, MaxBufferSize>::connect_cbk( }
receive();
+
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ if (queue_.size() > 0 && was_not_connected_) {
+ was_not_connected_ = false;
+ send_queued();
+ }
}
}
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::wait_connect_cbk(
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::wait_connect_cbk(
boost::system::error_code const &_error) {
if (!_error) {
connect();
}
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::send_cbk(
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::send_cbk(
boost::system::error_code const &_error, std::size_t _bytes) {
(void)_bytes;
if (!_error) {
std::lock_guard<std::mutex> its_lock(mutex_);
- queue_.pop_front();
if (queue_.size() > 0) {
+ queue_.pop_front();
send_queued();
}
} else if (_error == boost::asio::error::broken_pipe) {
is_connected_ = false;
- socket_.close();
+ if (endpoint_impl<Protocol>::sending_blocked_) {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ queue_.clear();
+ }
+ if (socket_.is_open()) {
+ boost::system::error_code its_error;
+ socket_.close(its_error);
+ }
+ connect();
+ } else if (_error == boost::asio::error::not_connected
+ || _error == boost::asio::error::bad_descriptor) {
+ was_not_connected_ = true;
connect();
}
}
-template<typename Protocol, int MaxBufferSize>
-void client_endpoint_impl<Protocol, MaxBufferSize>::flush_cbk(
+template<typename Protocol>
+void client_endpoint_impl<Protocol>::flush_cbk(
boost::system::error_code const &_error) {
if (!_error) {
(void) flush();
@@ -209,13 +258,9 @@ void client_endpoint_impl<Protocol, MaxBufferSize>::flush_cbk( // Instantiate template
#ifndef WIN32
-template class client_endpoint_impl<boost::asio::local::stream_protocol,
-VSOMEIP_MAX_LOCAL_MESSAGE_SIZE> ;
+template class client_endpoint_impl<boost::asio::local::stream_protocol>;
#endif
-template class client_endpoint_impl<boost::asio::ip::tcp,
-VSOMEIP_MAX_TCP_MESSAGE_SIZE> ;
-template class client_endpoint_impl<boost::asio::ip::udp,
-VSOMEIP_MAX_UDP_MESSAGE_SIZE> ;
-
+template class client_endpoint_impl<boost::asio::ip::tcp>;
+template class client_endpoint_impl<boost::asio::ip::udp>;
} // namespace vsomeip
diff --git a/implementation/endpoints/src/endpoint_definition.cpp b/implementation/endpoints/src/endpoint_definition.cpp index d748aa3..fe7e7d6 100644 --- a/implementation/endpoints/src/endpoint_definition.cpp +++ b/implementation/endpoints/src/endpoint_definition.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/endpoints/src/endpoint_impl.cpp b/implementation/endpoints/src/endpoint_impl.cpp index 5b0e088..109cff8 100644 --- a/implementation/endpoints/src/endpoint_impl.cpp +++ b/implementation/endpoints/src/endpoint_impl.cpp @@ -1,8 +1,13 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/ip/udp.hpp>
+#include <boost/asio/ip/udp_ext.hpp>
+#include <boost/asio/local/stream_protocol.hpp>
+
#include <vsomeip/constants.hpp>
#include <vsomeip/defines.hpp>
@@ -12,33 +17,38 @@ namespace vsomeip {
-template<int MaxBufferSize>
-endpoint_impl<MaxBufferSize>::endpoint_impl(
- std::shared_ptr<endpoint_host> _host, boost::asio::io_service &_io,
- std::uint32_t _max_message_size)
+template<typename Protocol>
+endpoint_impl<Protocol>::endpoint_impl(
+ std::shared_ptr<endpoint_host> _host,
+ endpoint_type _local,
+ boost::asio::io_service &_io,
+ std::uint32_t _max_message_size)
: service_(_io),
host_(_host),
is_supporting_magic_cookies_(false),
has_enabled_magic_cookies_(false),
- max_message_size_(_max_message_size) {
+ max_message_size_(_max_message_size),
+ use_count_(0),
+ sending_blocked_(false),
+ local_(_local) {
}
-template<int MaxBufferSize>
-endpoint_impl<MaxBufferSize>::~endpoint_impl() {
+template<typename Protocol>
+endpoint_impl<Protocol>::~endpoint_impl() {
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::enable_magic_cookies() {
+template<typename Protocol>
+void endpoint_impl<Protocol>::enable_magic_cookies() {
has_enabled_magic_cookies_ = is_supporting_magic_cookies_;
}
-template<int MaxBufferSize>
-bool endpoint_impl<MaxBufferSize>::is_magic_cookie() const {
+template<typename Protocol>
+bool endpoint_impl<Protocol>::is_magic_cookie() const {
return false;
}
-template<int MaxBufferSize>
-uint32_t endpoint_impl<MaxBufferSize>::find_magic_cookie(
+template<typename Protocol>
+uint32_t endpoint_impl<Protocol>::find_magic_cookie(
byte_t *_buffer, size_t _size) {
bool is_found(false);
uint32_t its_offset = 0xFFFFFFFF;
@@ -86,64 +96,67 @@ uint32_t endpoint_impl<MaxBufferSize>::find_magic_cookie( return (is_found ? its_offset : 0xFFFFFFFF);
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::join(const std::string &) {
+template<typename Protocol>
+void endpoint_impl<Protocol>::join(const std::string &) {
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::leave(const std::string &) {
+template<typename Protocol>
+void endpoint_impl<Protocol>::leave(const std::string &) {
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::add_multicast(
- service_t, event_t, const std::string &, uint16_t) {
+template<typename Protocol>
+void endpoint_impl<Protocol>::add_default_target(
+ service_t, const std::string &, uint16_t) {
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::remove_multicast(service_t, event_t) {
+template<typename Protocol>
+void endpoint_impl<Protocol>::remove_default_target(service_t) {
}
-template<int MaxBufferSize>
-bool endpoint_impl<MaxBufferSize>::get_remote_address(
+template<typename Protocol>
+bool endpoint_impl<Protocol>::get_remote_address(
boost::asio::ip::address &_address) const {
(void)_address;
return false;
}
-template<int MaxBufferSize>
-unsigned short endpoint_impl<MaxBufferSize>::get_local_port() const {
+template<typename Protocol>
+unsigned short endpoint_impl<Protocol>::get_local_port() const {
return 0;
}
-template<int MaxBufferSize>
-unsigned short endpoint_impl<MaxBufferSize>::get_remote_port() const {
+template<typename Protocol>
+unsigned short endpoint_impl<Protocol>::get_remote_port() const {
return 0;
}
-template<int MaxBufferSize>
-bool endpoint_impl<MaxBufferSize>::is_reliable() const {
+template<typename Protocol>
+bool endpoint_impl<Protocol>::is_reliable() const {
return false;
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::increment_use_count() {
+template<typename Protocol>
+void endpoint_impl<Protocol>::increment_use_count() {
use_count_++;
}
-template<int MaxBufferSize>
-void endpoint_impl<MaxBufferSize>::decrement_use_count() {
+template<typename Protocol>
+void endpoint_impl<Protocol>::decrement_use_count() {
if (use_count_ > 0)
use_count_--;
}
-template<int MaxBufferSize>
-uint32_t endpoint_impl<MaxBufferSize>::get_use_count() {
+template<typename Protocol>
+uint32_t endpoint_impl<Protocol>::get_use_count() {
return use_count_;
}
// Instantiate template
-template class endpoint_impl< VSOMEIP_MAX_LOCAL_MESSAGE_SIZE> ;
-template class endpoint_impl< VSOMEIP_MAX_TCP_MESSAGE_SIZE> ;
-template class endpoint_impl< VSOMEIP_MAX_UDP_MESSAGE_SIZE> ;
+#ifndef WIN32
+template class endpoint_impl<boost::asio::local::stream_protocol>;
+#endif
+template class endpoint_impl<boost::asio::ip::tcp>;
+template class endpoint_impl<boost::asio::ip::udp>;
+template class endpoint_impl<boost::asio::ip::udp_ext>;
} // namespace vsomeip
diff --git a/implementation/endpoints/src/local_client_endpoint_impl.cpp b/implementation/endpoints/src/local_client_endpoint_impl.cpp index 116287f..62dba82 100644 --- a/implementation/endpoints/src/local_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/local_client_endpoint_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -17,9 +17,13 @@ namespace vsomeip {
local_client_endpoint_impl::local_client_endpoint_impl(
- std::shared_ptr< endpoint_host > _host, endpoint_type _remote,
- boost::asio::io_service &_io, std::uint32_t _max_message_size)
- : local_client_endpoint_base_impl(_host, _remote, _io, _max_message_size) {
+ std::shared_ptr< endpoint_host > _host,
+ endpoint_type _remote,
+ boost::asio::io_service &_io,
+ std::uint32_t _max_message_size)
+ : local_client_endpoint_base_impl(_host, _remote, _remote, _io, _max_message_size) {
+ // Using _remote for the local(!) endpoint is ok,
+ // because we have no bind for local endpoints!
is_supporting_magic_cookies_ = false;
}
@@ -32,69 +36,65 @@ bool local_client_endpoint_impl::is_local() const { }
void local_client_endpoint_impl::start() {
- connect();
+ if (socket_.is_open()) {
+ sending_blocked_ = false;
+ boost::system::error_code its_error;
+ socket_.cancel(its_error);
+ socket_.close(its_error);
+ restart();
+ } else {
+ connect();
+ }
}
void local_client_endpoint_impl::connect() {
- socket_.open(remote_.protocol());
-
- boost::system::error_code error;
- error = socket_.connect(remote_, error);
- connect_cbk(error);
+ boost::system::error_code its_error;
+ socket_.open(remote_.protocol(), its_error);
+
+ if (!its_error || its_error == boost::asio::error::already_open) {
+ socket_.set_option(boost::asio::socket_base::reuse_address(true));
+ boost::system::error_code error;
+ error = socket_.connect(remote_, error);
+ connect_cbk(error);
+ } else {
+ VSOMEIP_WARNING << "local_client_endpoint::connect: Error opening socket: "
+ << its_error.message();
+ }
}
void local_client_endpoint_impl::receive() {
- receive_buffer_t its_buffer(VSOMEIP_MAX_LOCAL_MESSAGE_SIZE , 0);
- socket_.async_receive(
- boost::asio::buffer(its_buffer),
- std::bind(
- &local_client_endpoint_impl::receive_cbk,
- std::dynamic_pointer_cast<
- local_client_endpoint_impl
- >(shared_from_this()),
- std::placeholders::_1,
- std::placeholders::_2
- )
- );
}
void local_client_endpoint_impl::send_queued() {
static byte_t its_start_tag[] = { 0x67, 0x37, 0x6D, 0x07 };
+ static byte_t its_end_tag[] = { 0x07, 0x6D, 0x37, 0x67 };
+ std::vector<boost::asio::const_buffer> bufs;
+
+ message_buffer_ptr_t its_buffer;
+ if(queue_.size()) {
+ its_buffer = queue_.front();
+ } else {
+ return;
+ }
+
+#if 0
+std::stringstream msg;
+msg << "lce<" << this << ">::sq: ";
+for (std::size_t i = 0; i < its_buffer->size(); i++)
+ msg << std::setw(2) << std::setfill('0') << std::hex
+ << (int)(*its_buffer)[i] << " ";
+VSOMEIP_DEBUG << msg.str();
+#endif
+
+ bufs.push_back(boost::asio::buffer(its_start_tag));
+ bufs.push_back(boost::asio::buffer(*its_buffer));
+ bufs.push_back(boost::asio::buffer(its_end_tag));
boost::asio::async_write(
socket_,
- boost::asio::buffer(
- its_start_tag,
- sizeof(its_start_tag)
- ),
- std::bind(
- &local_client_endpoint_impl::send_start_tag_cbk,
- std::dynamic_pointer_cast<
- local_client_endpoint_impl
- >(shared_from_this()),
- std::placeholders::_1,
- std::placeholders::_2
- )
- );
-}
-
-void local_client_endpoint_impl::send_queued_data() {
- std::lock_guard<std::mutex> its_lock(mutex_);
- message_buffer_ptr_t its_buffer = queue_.front();
- #if 0
- std::stringstream msg;
- msg << "lce<" << this << ">::sq: ";
- for (std::size_t i = 0; i < its_buffer->size(); i++)
- msg << std::setw(2) << std::setfill('0') << std::hex
- << (int)(*its_buffer)[i] << " ";
- VSOMEIP_DEBUG << msg.str();
- #endif
-
- boost::asio::async_write(
- socket_,
- boost::asio::buffer(*its_buffer),
+ bufs,
std::bind(
- &local_client_endpoint_impl::send_queued_data_cbk,
+ &client_endpoint_impl::send_cbk,
std::dynamic_pointer_cast<
local_client_endpoint_impl
>(shared_from_this()),
@@ -104,51 +104,7 @@ void local_client_endpoint_impl::send_queued_data() { );
}
-void local_client_endpoint_impl::send_end_tag() {
- static byte_t its_end_tag[] = { 0x07, 0x6D, 0x37, 0x67 };
-
- boost::asio::async_write(
- socket_,
- boost::asio::buffer(
- its_end_tag,
- sizeof(its_end_tag)
- ),
- std::bind(
- &client_endpoint_impl::send_cbk,
- shared_from_this(),
- std::placeholders::_1,
- std::placeholders::_2
- )
- );
-}
-
void local_client_endpoint_impl::send_magic_cookie() {
}
-void local_client_endpoint_impl::send_start_tag_cbk(
- boost::system::error_code const &_error, std::size_t _bytes) {
- (void)_bytes;
- if (_error)
- send_cbk(_error, 0);
-
- send_queued_data();
-}
-
-void local_client_endpoint_impl::send_queued_data_cbk(
- boost::system::error_code const &_error, std::size_t _bytes) {
- (void)_bytes;
- if (_error)
- send_cbk(_error, 0);
-
- send_end_tag();
-}
-
-void local_client_endpoint_impl::receive_cbk(
- boost::system::error_code const &_error, std::size_t _bytes) {
- (void)_error;
- (void)_bytes;
- VSOMEIP_ERROR << "Local endpoint received message ("
- << _error.message() << ")";
-}
-
} // namespace vsomeip
diff --git a/implementation/endpoints/src/local_server_endpoint_impl.cpp b/implementation/endpoints/src/local_server_endpoint_impl.cpp index b392cec..e67a646 100644 --- a/implementation/endpoints/src/local_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/local_server_endpoint_impl.cpp @@ -1,11 +1,10 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include <deque> #include <iomanip> -#include <iostream> #include <sstream> #include <boost/asio/write.hpp> @@ -22,7 +21,7 @@ local_server_endpoint_impl::local_server_endpoint_impl( endpoint_type _local, boost::asio::io_service &_io, std::uint32_t _max_message_size) : local_server_endpoint_base_impl(_host, _local, _io, _max_message_size), - acceptor_(_io, _local) { + acceptor_(_io, _local), current_(nullptr) { is_supporting_magic_cookies_ = false; } @@ -34,22 +33,27 @@ bool local_server_endpoint_impl::is_local() const { } void local_server_endpoint_impl::start() { - connection::ptr new_connection = connection::create(this, max_message_size_); + current_ = connection::create(this, max_message_size_); acceptor_.async_accept( - new_connection->get_socket(), + current_->get_socket(), std::bind( &local_server_endpoint_impl::accept_cbk, std::dynamic_pointer_cast< local_server_endpoint_impl >(shared_from_this()), - new_connection, + current_, std::placeholders::_1 ) ); } void local_server_endpoint_impl::stop() { + if (acceptor_.is_open()) { + boost::system::error_code its_error; + acceptor_.close(its_error); + } + server_endpoint_impl::stop(); } bool local_server_endpoint_impl::send_to( @@ -77,13 +81,21 @@ void local_server_endpoint_impl::restart() { current_->start(); } +bool local_server_endpoint_impl::queue_message(const byte_t *_data, uint32_t _size) { + if (current_) { + return current_->queue_message(_data, _size); + } + return false; +} + local_server_endpoint_impl::endpoint_type local_server_endpoint_impl::get_remote() const { - return current_->get_socket().remote_endpoint(); + boost::system::error_code its_error; + return current_->get_socket().remote_endpoint(its_error); } -bool local_server_endpoint_impl::get_multicast( - service_t, event_t, +bool local_server_endpoint_impl::get_default_target( + service_t, local_server_endpoint_impl::endpoint_type &) const { return false; } @@ -107,10 +119,12 @@ void local_server_endpoint_impl::accept_cbk( if (!_error) { socket_type &new_connection_socket = _connection->get_socket(); - endpoint_type remote = new_connection_socket.remote_endpoint(); - - connections_[remote] = _connection; - _connection->start(); + boost::system::error_code its_error; + endpoint_type remote = new_connection_socket.remote_endpoint(its_error); + if(!its_error) { + connections_[remote] = _connection; + _connection->start(); + } } start(); @@ -120,6 +134,8 @@ void local_server_endpoint_impl::accept_cbk( // class local_service_impl::connection /////////////////////////////////////////////////////////////////////////////// +std::vector<byte_t> local_server_endpoint_impl::connection::queued_data_; + local_server_endpoint_impl::connection::connection( local_server_endpoint_impl *_server, std::uint32_t _max_message_size) : socket_(_server->service_), server_(_server), @@ -185,6 +201,20 @@ void local_server_endpoint_impl::connection::send_queued( ); } +bool local_server_endpoint_impl::connection::queue_message(const byte_t *_data, uint32_t _size) { +#if 0 + std::stringstream msg; + msg << "lse::qm: "; + for (std::size_t i = 0; i < _size; i++) + msg << std::setw(2) << std::setfill('0') << std::hex + << (int)(_data)[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + queued_data_.resize(_size); + memcpy(&queued_data_[0], _data, _size); + return true; +} + void local_server_endpoint_impl::connection::send_magic_cookie() { } @@ -241,6 +271,12 @@ void local_server_endpoint_impl::connection::receive_cbk( its_host->on_message(&recv_buffer_[its_start], uint32_t(its_end - its_start), server_); + // If there was a queued message --> consume it now! + if (queued_data_.size() > 0) { + its_host->on_message(&queued_data_[0], static_cast<length_t>(queued_data_.size()), server_); + queued_data_.clear(); + } + #if 0 std::stringstream local_msg; local_msg << "lse::c<" << this << ">rcb::thunk: "; diff --git a/implementation/endpoints/src/server_endpoint_impl.cpp b/implementation/endpoints/src/server_endpoint_impl.cpp index b67ecec..c8e513b 100644 --- a/implementation/endpoints/src/server_endpoint_impl.cpp +++ b/implementation/endpoints/src/server_endpoint_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,7 +8,7 @@ #include <boost/asio/buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
-#include <boost/asio/ip/udp.hpp>
+#include <boost/asio/ip/udp_ext.hpp>
#include <boost/asio/local/stream_protocol.hpp>
#include <vsomeip/defines.hpp>
@@ -21,26 +21,34 @@ namespace vsomeip {
-template<typename Protocol, int MaxBufferSize>
-server_endpoint_impl<Protocol, MaxBufferSize>::server_endpoint_impl(
+template<typename Protocol>
+server_endpoint_impl<Protocol>::server_endpoint_impl(
std::shared_ptr<endpoint_host> _host, endpoint_type _local,
boost::asio::io_service &_io, std::uint32_t _max_message_size)
- : endpoint_impl<MaxBufferSize>(_host, _io, _max_message_size),
- flush_timer_(_io), local_(_local) {
+ : endpoint_impl<Protocol>(_host, _local, _io, _max_message_size),
+ flush_timer_(_io) {
}
-template<typename Protocol, int MaxBufferSize>
-bool server_endpoint_impl<Protocol, MaxBufferSize>::is_client() const {
+template<typename Protocol>
+server_endpoint_impl<Protocol>::~server_endpoint_impl() {
+}
+
+template<typename Protocol>
+void server_endpoint_impl<Protocol>::stop() {
+}
+
+template<typename Protocol>
+bool server_endpoint_impl<Protocol>::is_client() const {
return false;
}
-template<typename Protocol, int MaxBufferSize>
-bool server_endpoint_impl<Protocol, MaxBufferSize>::is_connected() const {
+template<typename Protocol>
+bool server_endpoint_impl<Protocol>::is_connected() const {
return true;
}
-template<typename Protocol, int MaxBufferSize>
-bool server_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data,
+template<typename Protocol>
+bool server_endpoint_impl<Protocol>::send(const uint8_t *_data,
uint32_t _size, bool _flush) {
#if 0
std::stringstream msg;
@@ -52,6 +60,10 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data, endpoint_type its_target;
bool is_valid_target(false);
+ if(endpoint_impl<Protocol>::sending_blocked_) {
+ return false;
+ }
+
if (VSOMEIP_SESSION_POS_MAX < _size) {
std::lock_guard<std::mutex> its_lock(mutex_);
@@ -66,6 +78,7 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data, std::memcpy(&its_session, &_data[VSOMEIP_SESSION_POS_MIN],
sizeof(session_t));
+ clients_mutex_.lock();
auto found_client = clients_.find(its_client);
if (found_client != clients_.end()) {
auto found_session = found_client->second.find(its_session);
@@ -74,12 +87,9 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data, is_valid_target = true;
}
} else {
- event_t its_event = VSOMEIP_BYTES_TO_WORD(
- _data[VSOMEIP_METHOD_POS_MIN],
- _data[VSOMEIP_METHOD_POS_MAX]);
- is_valid_target
- = get_multicast(its_service, its_event, its_target);
+ is_valid_target = get_default_target(its_service, its_target);
}
+ clients_mutex_.unlock();
if (is_valid_target) {
is_valid_target = send_intern(its_target, _data, _size, _flush);
@@ -88,15 +98,18 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send(const uint8_t *_data, return is_valid_target;
}
-template<typename Protocol, int MaxBufferSize>
-bool server_endpoint_impl<Protocol, MaxBufferSize>::send_intern(
+template<typename Protocol>
+bool server_endpoint_impl<Protocol>::send_intern(
endpoint_type _target, const byte_t *_data, uint32_t _size,
bool _flush) {
- bool is_flushing(false);
message_buffer_ptr_t target_packetizer;
queue_iterator_type target_queue_iterator;
+ if(endpoint_impl<Protocol>::sending_blocked_) {
+ return false;
+ }
+
auto found_packetizer = packetizer_.find(_target);
if (found_packetizer != packetizer_.end()) {
target_packetizer = found_packetizer->second;
@@ -115,10 +128,13 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send_intern( }
// TODO compare against value from configuration here
- if (target_packetizer->size() + _size > endpoint_impl<MaxBufferSize>::max_message_size_) {
+ const bool queue_size_zero_on_entry(target_queue_iterator->second.empty());
+ if (target_packetizer->size() + _size
+ > endpoint_impl<Protocol>::max_message_size_
+ && !target_packetizer->empty()) {
target_queue_iterator->second.push_back(target_packetizer);
- is_flushing = true;
- packetizer_[_target] = std::make_shared<message_buffer_t>();
+ target_packetizer = std::make_shared<message_buffer_t>();
+ packetizer_[_target] = target_packetizer;
}
target_packetizer->insert(target_packetizer->end(), _data, _data + _size);
@@ -126,29 +142,26 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::send_intern( if (_flush) {
flush_timer_.cancel();
target_queue_iterator->second.push_back(target_packetizer);
- is_flushing = true;
packetizer_[_target] = std::make_shared<message_buffer_t>();
} else {
std::chrono::milliseconds flush_timeout(VSOMEIP_DEFAULT_FLUSH_TIMEOUT);
flush_timer_.expires_from_now(flush_timeout); // TODO: use configured value
flush_timer_.async_wait(
- std::bind(&server_endpoint_impl<
- Protocol, MaxBufferSize
- >::flush_cbk,
+ std::bind(&server_endpoint_impl<Protocol>::flush_cbk,
this->shared_from_this(),
_target,
std::placeholders::_1));
}
- if (is_flushing && target_queue_iterator->second.size() == 1) { // no writing in progress
+ if (queue_size_zero_on_entry && !target_queue_iterator->second.empty()) { // no writing in progress
send_queued(target_queue_iterator);
}
return true;
}
-template<typename Protocol, int MaxBufferSize>
-bool server_endpoint_impl<Protocol, MaxBufferSize>::flush(
+template<typename Protocol>
+bool server_endpoint_impl<Protocol>::flush(
endpoint_type _target) {
bool is_flushed = false;
std::lock_guard<std::mutex> its_lock(mutex_);
@@ -161,14 +174,14 @@ bool server_endpoint_impl<Protocol, MaxBufferSize>::flush( return is_flushed;
}
-template<typename Protocol, int MaxBufferSize>
-void server_endpoint_impl<Protocol, MaxBufferSize>::connect_cbk(
+template<typename Protocol>
+void server_endpoint_impl<Protocol>::connect_cbk(
boost::system::error_code const &_error) {
(void)_error;
}
-template<typename Protocol, int MaxBufferSize>
-void server_endpoint_impl<Protocol, MaxBufferSize>::send_cbk(
+template<typename Protocol>
+void server_endpoint_impl<Protocol>::send_cbk(
queue_iterator_type _queue_iterator, boost::system::error_code const &_error,
std::size_t _bytes) {
(void)_bytes;
@@ -182,8 +195,8 @@ void server_endpoint_impl<Protocol, MaxBufferSize>::send_cbk( }
}
-template<typename Protocol, int MaxBufferSize>
-void server_endpoint_impl<Protocol, MaxBufferSize>::flush_cbk(
+template<typename Protocol>
+void server_endpoint_impl<Protocol>::flush_cbk(
endpoint_type _target, const boost::system::error_code &_error_code) {
if (!_error_code) {
(void) flush(_target);
@@ -192,15 +205,9 @@ void server_endpoint_impl<Protocol, MaxBufferSize>::flush_cbk( // Instantiate template
#ifndef WIN32
-template class server_endpoint_impl<
- boost::asio::local::stream_protocol,
- VSOMEIP_MAX_LOCAL_MESSAGE_SIZE> ;
+template class server_endpoint_impl<boost::asio::local::stream_protocol>;
#endif
-template class server_endpoint_impl<
- boost::asio::ip::tcp,
- VSOMEIP_MAX_TCP_MESSAGE_SIZE> ;
-template class server_endpoint_impl<
- boost::asio::ip::udp,
- VSOMEIP_MAX_UDP_MESSAGE_SIZE> ;
+template class server_endpoint_impl<boost::asio::ip::tcp>;
+template class server_endpoint_impl<boost::asio::ip::udp_ext>;
} // namespace vsomeip
diff --git a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp index 26c7424..d31a38b 100644 --- a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -20,15 +20,22 @@ namespace ip = boost::asio::ip; namespace vsomeip {
tcp_client_endpoint_impl::tcp_client_endpoint_impl(
- std::shared_ptr< endpoint_host > _host, endpoint_type _remote,
- boost::asio::io_service &_io, std::uint32_t _max_message_size)
- : tcp_client_endpoint_base_impl(_host, _remote, _io, _max_message_size),
+ std::shared_ptr< endpoint_host > _host,
+ endpoint_type _local,
+ endpoint_type _remote,
+ boost::asio::io_service &_io,
+ std::uint32_t _max_message_size)
+ : tcp_client_endpoint_base_impl(_host, _local, _remote, _io, _max_message_size),
recv_buffer_(_max_message_size, 0),
recv_buffer_size_(0) {
is_supporting_magic_cookies_ = true;
}
tcp_client_endpoint_impl::~tcp_client_endpoint_impl() {
+ std::shared_ptr<endpoint_host> its_host = host_.lock();
+ if (its_host) {
+ its_host->release_port(local_.port(), true);
+ }
}
bool tcp_client_endpoint_impl::is_local() const {
@@ -40,19 +47,41 @@ void tcp_client_endpoint_impl::start() { }
void tcp_client_endpoint_impl::connect() {
- socket_.open(remote_.protocol());
+ boost::system::error_code its_error;
+ socket_.open(remote_.protocol(), its_error);
- // Nagle algorithm off
- socket_.set_option(ip::tcp::no_delay(true));
+ if (!its_error || its_error == boost::asio::error::already_open) {
+ // Nagle algorithm off
+ socket_.set_option(ip::tcp::no_delay(true));
- socket_.async_connect(
- remote_,
- std::bind(
- &tcp_client_endpoint_base_impl::connect_cbk,
- shared_from_this(),
- std::placeholders::_1
- )
- );
+ // Enable SO_REUSEADDR to avoid bind problems with services going offline
+ // and coming online again and the user has specified only a small number
+ // of ports in the clients section for one service instance
+ socket_.set_option(boost::asio::socket_base::reuse_address(true));
+
+ // In case a client endpoint port was configured,
+ // bind to it before connecting
+ if (local_.port() != ILLEGAL_PORT) {
+ boost::system::error_code its_bind_error;
+ socket_.bind(local_, its_bind_error);
+ if(its_bind_error) {
+ VSOMEIP_WARNING << "tcp_client_endpoint::connect: "
+ "Error binding socket: " << its_bind_error.message();
+ }
+ }
+
+ socket_.async_connect(
+ remote_,
+ std::bind(
+ &tcp_client_endpoint_base_impl::connect_cbk,
+ shared_from_this(),
+ std::placeholders::_1
+ )
+ );
+ } else {
+ VSOMEIP_WARNING << "tcp_client_endpoint::connect: Error opening socket: "
+ << its_error.message();
+ }
}
void tcp_client_endpoint_impl::receive() {
@@ -73,7 +102,12 @@ void tcp_client_endpoint_impl::receive() { }
void tcp_client_endpoint_impl::send_queued() {
- message_buffer_ptr_t its_buffer = queue_.front();
+ message_buffer_ptr_t its_buffer;
+ if(queue_.size()) {
+ its_buffer = queue_.front();
+ } else {
+ return;
+ }
if (has_enabled_magic_cookies_)
send_magic_cookie(its_buffer);
@@ -107,11 +141,13 @@ bool tcp_client_endpoint_impl::get_remote_address( }
unsigned short tcp_client_endpoint_impl::get_local_port() const {
- return socket_.local_endpoint().port();
+ boost::system::error_code its_error;
+ return socket_.local_endpoint(its_error).port();
}
unsigned short tcp_client_endpoint_impl::get_remote_port() const {
- return socket_.remote_endpoint().port();
+ boost::system::error_code its_error;
+ return socket_.remote_endpoint(its_error).port();
}
bool tcp_client_endpoint_impl::is_reliable() const {
@@ -195,9 +231,22 @@ void tcp_client_endpoint_impl::receive_cbk( has_full_message = true; // trigger next loop
}
} else if (current_message_size > max_message_size_) {
- VSOMEIP_ERROR << "Message exceeds maximum message size. "
- << "Resetting receiver.";
- recv_buffer_size_ = 0;
+ if (has_enabled_magic_cookies_) {
+ VSOMEIP_ERROR << "Received a TCP message which exceeds "
+ << "maximum message size ("
+ << std::dec << current_message_size
+ << "). Magic Cookies are enabled: "
+ << "Resetting receiver.";
+ recv_buffer_size_ = 0;
+ } else {
+ VSOMEIP_ERROR << "Received a TCP message which exceeds "
+ << "maximum message size ("
+ << std::dec << current_message_size
+ << ") Magic cookies are disabled: "
+ << "Client will be disabled!";
+ recv_buffer_size_ = 0;
+ return;
+ }
}
} while (has_full_message && recv_buffer_size_);
if (its_iteration_gap) {
@@ -206,7 +255,7 @@ void tcp_client_endpoint_impl::receive_cbk( recv_buffer_[i] = recv_buffer_[i + its_iteration_gap];
}
}
- restart();
+ receive();
} else {
if (socket_.is_open()) {
receive();
diff --git a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp index 0084d8e..fc31850 100644 --- a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -46,28 +46,61 @@ void tcp_server_endpoint_impl::start() { } void tcp_server_endpoint_impl::stop() { + server_endpoint_impl::stop(); for (auto& i : connections_) i.second->stop(); - acceptor_.close(); + if(acceptor_.is_open()) { + boost::system::error_code its_error; + acceptor_.close(its_error); + } } bool tcp_server_endpoint_impl::send_to( const std::shared_ptr<endpoint_definition> _target, const byte_t *_data, uint32_t _size, bool _flush) { + std::lock_guard<std::mutex> its_lock(mutex_); endpoint_type its_target(_target->get_address(), _target->get_port()); return send_intern(its_target, _data, _size, _flush); } void tcp_server_endpoint_impl::send_queued(queue_iterator_type _queue_iterator) { auto connection_iterator = connections_.find(_queue_iterator->first); - if (connection_iterator != connections_.end()) + if (connection_iterator != connections_.end()) { connection_iterator->second->send_queued(_queue_iterator); + } else { + VSOMEIP_DEBUG << "Didn't find connection: " + << _queue_iterator->first.address().to_string() << ":" << std::dec + << static_cast<std::uint16_t>(_queue_iterator->first.port()) + << " dropping message."; + _queue_iterator->second.pop_front(); + } +} + +bool tcp_server_endpoint_impl::is_established(std::shared_ptr<endpoint_definition> _endpoint) { + bool is_connected = false; + endpoint_type endpoint(_endpoint->get_address(), _endpoint->get_port()); + auto connection_iterator = connections_.find(endpoint); + if (connection_iterator != connections_.end()) { +#if 0 + VSOMEIP_DEBUG << "tcp_server_endpoint_impl::is_established(): subscribers TCP connection for " + << endpoint.address().to_string() << ":" << std::dec + << static_cast<std::uint16_t>(endpoint.port()) + << " is established!" ; +#endif + is_connected = true; + } else { + VSOMEIP_DEBUG << "Didn't find TCP connection: Subscription rejected for: " + << endpoint.address().to_string() << ":" << std::dec + << static_cast<std::uint16_t>(endpoint.port()); + } + return is_connected; } tcp_server_endpoint_impl::endpoint_type tcp_server_endpoint_impl::get_remote() const { - return current_->get_socket().remote_endpoint(); + boost::system::error_code its_error; + return current_->get_socket().remote_endpoint(its_error); } bool tcp_server_endpoint_impl::get_remote_address( @@ -77,9 +110,7 @@ bool tcp_server_endpoint_impl::get_remote_address( boost::system::error_code its_error; tcp_server_endpoint_impl::endpoint_type its_endpoint = current_->get_socket().remote_endpoint(its_error); - if (its_error) { - return false; - } else { + if (!its_error) { boost::asio::ip::address its_address = its_endpoint.address(); if (!its_address.is_unspecified()) { _address = its_address; @@ -90,7 +121,19 @@ bool tcp_server_endpoint_impl::get_remote_address( return false; } -bool tcp_server_endpoint_impl::get_multicast(service_t, event_t, +unsigned short tcp_server_endpoint_impl::get_remote_port() const { + if (current_) { + boost::system::error_code its_error; + tcp_server_endpoint_impl::endpoint_type its_endpoint = + current_->get_socket().remote_endpoint(its_error); + if (!its_error) { + return its_endpoint.port(); + } + } + return 0; +} + +bool tcp_server_endpoint_impl::get_default_target(service_t, tcp_server_endpoint_impl::endpoint_type &) const { return false; } @@ -100,17 +143,23 @@ void tcp_server_endpoint_impl::accept_cbk(connection::ptr _connection, if (!_error) { socket_type &new_connection_socket = _connection->get_socket(); - endpoint_type remote = new_connection_socket.remote_endpoint(); - - connections_[remote] = _connection; - _connection->start(); - + boost::system::error_code its_error; + endpoint_type remote = new_connection_socket.remote_endpoint(its_error); + if(!its_error) { + connections_[remote] = _connection; + _connection->start(); + } + } + if (_error != boost::asio::error::operation_aborted) { start(); + } else { + VSOMEIP_DEBUG << "Endpoint was stopped, don't starting again"; } } unsigned short tcp_server_endpoint_impl::get_local_port() const { - return acceptor_.local_endpoint().port(); + boost::system::error_code its_error; + return acceptor_.local_endpoint(its_error).port(); } bool tcp_server_endpoint_impl::is_reliable() const { @@ -163,8 +212,10 @@ void tcp_server_endpoint_impl::connection::receive() { void tcp_server_endpoint_impl::connection::stop() { std::lock_guard<std::mutex> its_lock(stop_mutex_); if(socket_.is_open()) { - socket_.shutdown(socket_.shutdown_both); - socket_.close(); + boost::system::error_code its_shutdown_error; + socket_.shutdown(socket_.shutdown_both, its_shutdown_error); + boost::system::error_code its_close_error; + socket_.close(its_close_error); } } @@ -172,8 +223,9 @@ void tcp_server_endpoint_impl::connection::send_queued( queue_iterator_type _queue_iterator) { message_buffer_ptr_t its_buffer = _queue_iterator->second.front(); - if (server_->has_enabled_magic_cookies_) + if (server_->has_enabled_magic_cookies_) { send_magic_cookie(its_buffer); + } boost::asio::async_write(socket_, boost::asio::buffer(*its_buffer), std::bind(&tcp_server_endpoint_base_impl::send_cbk, @@ -240,20 +292,27 @@ void tcp_server_endpoint_impl::connection::receive_cbk( } } if (needs_forwarding) { - if (utility::is_request(recv_buffer_[VSOMEIP_MESSAGE_TYPE_POS])) { + if (utility::is_request( + recv_buffer_[its_iteration_gap + + VSOMEIP_MESSAGE_TYPE_POS])) { client_t its_client; std::memcpy(&its_client, - &recv_buffer_[VSOMEIP_CLIENT_POS_MIN], + &recv_buffer_[its_iteration_gap + VSOMEIP_CLIENT_POS_MIN], sizeof(client_t)); session_t its_session; std::memcpy(&its_session, - &recv_buffer_[VSOMEIP_SESSION_POS_MIN], + &recv_buffer_[its_iteration_gap + VSOMEIP_SESSION_POS_MIN], sizeof(session_t)); { std::lock_guard<std::mutex> its_lock(stop_mutex_); if (socket_.is_open()) { - server_->clients_[its_client][its_session] = - socket_.remote_endpoint(); + server_->clients_mutex_.lock(); + boost::system::error_code its_error; + endpoint_type its_endpoint(socket_.remote_endpoint(its_error)); + if (!its_error) { + server_->clients_[its_client][its_session] = its_endpoint; + } + server_->clients_mutex_.unlock(); server_->current_ = this; } } @@ -290,10 +349,22 @@ void tcp_server_endpoint_impl::connection::receive_cbk( } } } else if (current_message_size > max_message_size_) { - VSOMEIP_ERROR << "Message exceeds maximum message size (" - << std::dec << current_message_size - << "). Resetting receiver."; - recv_buffer_size_ = 0; + if (server_->has_enabled_magic_cookies_) { + VSOMEIP_ERROR << "Received a TCP message which exceeds " + << "maximum message size (" + << std::dec << current_message_size + << "). Magic Cookies are enabled: " + << "Resetting receiver."; + recv_buffer_size_ = 0; + } else { + VSOMEIP_ERROR << "Received a TCP message which exceeds " + << "maximum message size (" + << std::dec << current_message_size + << ") Magic cookies are disabled: " + << "Connection will be disabled!"; + recv_buffer_size_ = 0; + return; + } } } while (has_full_message && recv_buffer_size_); if (its_iteration_gap) { @@ -317,6 +388,7 @@ client_t tcp_server_endpoint_impl::get_client(std::shared_ptr<endpoint_definitio } client_t tcp_server_endpoint_impl::connection::get_client(endpoint_type _endpoint_type) { + std::lock_guard<std::mutex> its_lock(server_->clients_mutex_); for (auto its_client : server_->clients_) { for (auto its_session : server_->clients_[its_client.first]) { auto endpoint = its_session.second; diff --git a/implementation/endpoints/src/udp_client_endpoint_impl.cpp b/implementation/endpoints/src/udp_client_endpoint_impl.cpp index a5a90cc..a6029db 100644 --- a/implementation/endpoints/src/udp_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/udp_client_endpoint_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -16,14 +16,20 @@ namespace vsomeip {
udp_client_endpoint_impl::udp_client_endpoint_impl(
- std::shared_ptr< endpoint_host > _host, endpoint_type _remote,
+ std::shared_ptr< endpoint_host > _host,
+ endpoint_type _local,
+ endpoint_type _remote,
boost::asio::io_service &_io)
- : udp_client_endpoint_base_impl(_host, _remote, _io, VSOMEIP_MAX_UDP_MESSAGE_SIZE),
- recv_buffer_(VSOMEIP_MAX_UDP_MESSAGE_SIZE, 0),
- recv_buffer_size_(0) {
+ : udp_client_endpoint_base_impl(_host, _local, _remote, _io,
+ VSOMEIP_MAX_UDP_MESSAGE_SIZE),
+ recv_buffer_(VSOMEIP_MAX_UDP_MESSAGE_SIZE, 0) {
}
udp_client_endpoint_impl::~udp_client_endpoint_impl() {
+ std::shared_ptr<endpoint_host> its_host = host_.lock();
+ if (its_host) {
+ its_host->release_port(local_.port(), false);
+ }
}
bool udp_client_endpoint_impl::is_local() const {
@@ -31,7 +37,13 @@ bool udp_client_endpoint_impl::is_local() const { }
void udp_client_endpoint_impl::connect() {
- socket_.async_connect(
+ // In case a client endpoint port was configured,
+ // bind to it before connecting
+ if (local_.port() != ILLEGAL_PORT) {
+ socket_.bind(local_);
+ }
+
+ socket_.async_connect(
remote_,
std::bind(
&udp_client_endpoint_base_impl::connect_cbk,
@@ -42,12 +54,23 @@ void udp_client_endpoint_impl::connect() { }
void udp_client_endpoint_impl::start() {
- socket_.open(remote_.protocol());
- connect();
+ boost::system::error_code its_error;
+ socket_.open(remote_.protocol(), its_error);
+ if (!its_error || its_error == boost::asio::error::already_open) {
+ connect();
+ } else {
+ VSOMEIP_WARNING << "udp_client_endpoint::connect: Error opening socket: "
+ << its_error.message();
+ }
}
void udp_client_endpoint_impl::send_queued() {
- message_buffer_ptr_t its_buffer = queue_.front();
+ message_buffer_ptr_t its_buffer;
+ if(queue_.size()) {
+ its_buffer = queue_.front();
+ } else {
+ return;
+ }
#if 0
std::stringstream msg;
msg << "ucei<" << remote_.address() << ":"
@@ -69,13 +92,8 @@ void udp_client_endpoint_impl::send_queued() { }
void udp_client_endpoint_impl::receive() {
- if (recv_buffer_size_ == max_message_size_) {
- // Overrun -> Reset buffer
- recv_buffer_size_ = 0;
- }
- size_t buffer_size = max_message_size_ - recv_buffer_size_;
socket_.async_receive_from(
- boost::asio::buffer(&recv_buffer_[recv_buffer_size_], buffer_size),
+ boost::asio::buffer(&recv_buffer_[0], max_message_size_),
remote_,
std::bind(
&udp_client_endpoint_impl::receive_cbk,
@@ -95,11 +113,13 @@ bool udp_client_endpoint_impl::get_remote_address( }
unsigned short udp_client_endpoint_impl::get_local_port() const {
- return socket_.local_endpoint().port();
+ boost::system::error_code its_error;
+ return socket_.local_endpoint(its_error).port();
}
unsigned short udp_client_endpoint_impl::get_remote_port() const {
- return socket_.remote_endpoint().port();
+ boost::system::error_code its_error;
+ return socket_.remote_endpoint(its_error).port();
}
void udp_client_endpoint_impl::receive_cbk(
@@ -114,17 +134,15 @@ void udp_client_endpoint_impl::receive_cbk( << (int) recv_buffer_[i] << " ";
VSOMEIP_DEBUG << msg.str();
#endif
- recv_buffer_size_ += _bytes;
uint32_t current_message_size
= utility::get_message_size(&this->recv_buffer_[0],
- (uint32_t) recv_buffer_size_);
+ (uint32_t) _bytes);
if (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE &&
current_message_size <= _bytes) {
its_host->on_message(&recv_buffer_[0], current_message_size, this);
} else {
VSOMEIP_ERROR << "Received a unreliable vSomeIP message with bad length field";
}
- recv_buffer_size_ = 0;
}
if (!_error) {
receive();
diff --git a/implementation/endpoints/src/udp_server_endpoint_impl.cpp b/implementation/endpoints/src/udp_server_endpoint_impl.cpp index 4593c1f..8b3fd30 100644 --- a/implementation/endpoints/src/udp_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/udp_server_endpoint_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -8,9 +8,11 @@ #include <boost/asio/ip/multicast.hpp> + #include "../include/endpoint_definition.hpp" #include "../include/endpoint_host.hpp" #include "../include/udp_server_endpoint_impl.hpp" +#include "../../configuration/include/configuration.hpp" #include "../../logging/include/logger.hpp" #include "../../utility/include/byteorder.hpp" #include "../../utility/include/utility.hpp" @@ -24,22 +26,37 @@ udp_server_endpoint_impl::udp_server_endpoint_impl( std::shared_ptr< endpoint_host > _host, endpoint_type _local, boost::asio::io_service &_io) - : server_endpoint_impl< - ip::udp, VSOMEIP_MAX_UDP_MESSAGE_SIZE - >(_host, _local, _io, VSOMEIP_MAX_UDP_MESSAGE_SIZE), + : server_endpoint_impl<ip::udp_ext>( + _host, _local, _io, VSOMEIP_MAX_UDP_MESSAGE_SIZE), socket_(_io, _local.protocol()), - recv_buffer_(VSOMEIP_MAX_UDP_MESSAGE_SIZE, 0), - recv_buffer_size_(0) { + recv_buffer_(VSOMEIP_MAX_UDP_MESSAGE_SIZE, 0) { boost::system::error_code ec; boost::asio::socket_base::reuse_address optionReuseAddress(true); socket_.set_option(optionReuseAddress); + if (_local.address().is_v4()) { + boost::asio::ip::address_v4 its_unicast_address + = configuration::get()->get_unicast_address().to_v4(); + boost::asio::ip::multicast::outbound_interface option(its_unicast_address); + socket_.set_option(option); + } + socket_.bind(_local, ec); boost::asio::detail::throw_error(ec, "bind"); boost::asio::socket_base::broadcast option(true); socket_.set_option(option); + +#ifdef WIN32 + const char* optval("0001"); + ::setsockopt(socket_.native(), IPPROTO_IP, IP_PKTINFO, + optval, sizeof(optval)); +#else + int optval(1); + ::setsockopt(socket_.native(), IPPROTO_IP, IP_PKTINFO, + &optval, sizeof(optval)); +#endif } udp_server_endpoint_impl::~udp_server_endpoint_impl() { @@ -55,28 +72,26 @@ void udp_server_endpoint_impl::start() { void udp_server_endpoint_impl::stop() { std::lock_guard<std::mutex> its_lock(stop_mutex_); + server_endpoint_impl::stop(); if (socket_.is_open()) { - socket_.close(); + boost::system::error_code its_error; + socket_.close(its_error); } } void udp_server_endpoint_impl::receive() { - if (recv_buffer_size_ == max_message_size_) { - // Overrun -> Reset buffer - recv_buffer_size_ = 0; - } std::lock_guard<std::mutex> its_lock(stop_mutex_); if(socket_.is_open()) { - size_t buffer_size = max_message_size_ - recv_buffer_size_; socket_.async_receive_from( - boost::asio::buffer(&recv_buffer_[recv_buffer_size_], buffer_size), + boost::asio::buffer(&recv_buffer_[0], max_message_size_), remote_, std::bind( &udp_server_endpoint_impl::receive_cbk, std::dynamic_pointer_cast< udp_server_endpoint_impl >(shared_from_this()), std::placeholders::_1, - std::placeholders::_2 + std::placeholders::_2, + std::placeholders::_3 ) ); } @@ -89,8 +104,9 @@ void udp_server_endpoint_impl::restart() { bool udp_server_endpoint_impl::send_to( const std::shared_ptr<endpoint_definition> _target, const byte_t *_data, uint32_t _size, bool _flush) { - endpoint_type its_target(_target->get_address(), _target->get_port()); - return send_intern(its_target, _data, _size, _flush); + std::lock_guard<std::mutex> its_lock(mutex_); + endpoint_type its_target(_target->get_address(), _target->get_port()); + return send_intern(its_target, _data, _size, _flush); } void udp_server_endpoint_impl::send_queued( @@ -134,36 +150,31 @@ bool udp_server_endpoint_impl::get_remote_address( return true; } -bool udp_server_endpoint_impl::get_multicast(service_t _service, event_t _event, - udp_server_endpoint_impl::endpoint_type &_target) const { - bool is_valid(false); - auto find_service = multicasts_.find(_service); - if (find_service != multicasts_.end()) { - auto find_event = find_service->second.find(_event); - if (find_event != find_service->second.end()) { - _target = find_event->second; - is_valid = true; - } - } - return is_valid; +unsigned short udp_server_endpoint_impl::get_remote_port() const { + return remote_.port(); +} + +bool udp_server_endpoint_impl::is_joined(const std::string &_address) const { + return (joined_.find(_address) != joined_.end()); } void udp_server_endpoint_impl::join(const std::string &_address) { try { - if (local_.address().is_v4()) { - socket_.set_option( - boost::asio::ip::udp::socket::reuse_address(true)); - socket_.set_option( - boost::asio::ip::multicast::enable_loopback(false)); - socket_.set_option(boost::asio::ip::multicast::join_group( - boost::asio::ip::address::from_string(_address).to_v4())); - } else if (local_.address().is_v6()) { - socket_.set_option( - boost::asio::ip::udp::socket::reuse_address(true)); - socket_.set_option( - boost::asio::ip::multicast::enable_loopback(false)); - socket_.set_option(boost::asio::ip::multicast::join_group( - boost::asio::ip::address::from_string(_address).to_v6())); + if (!is_joined(_address)) { + if (local_.address().is_v4()) { + socket_.set_option(ip::udp_ext::socket::reuse_address(true)); + socket_.set_option( + boost::asio::ip::multicast::enable_loopback(false)); + socket_.set_option(boost::asio::ip::multicast::join_group( + boost::asio::ip::address::from_string(_address).to_v4())); + } else if (local_.address().is_v6()) { + socket_.set_option(ip::udp_ext::socket::reuse_address(true)); + socket_.set_option( + boost::asio::ip::multicast::enable_loopback(false)); + socket_.set_option(boost::asio::ip::multicast::join_group( + boost::asio::ip::address::from_string(_address).to_v6())); + } + joined_.insert(_address); } } catch (const std::exception &e) { @@ -173,12 +184,15 @@ void udp_server_endpoint_impl::join(const std::string &_address) { void udp_server_endpoint_impl::leave(const std::string &_address) { try { - if (local_.address().is_v4()) { - socket_.set_option(boost::asio::ip::multicast::leave_group( - boost::asio::ip::address::from_string(_address))); - } else if (local_.address().is_v6()) { - socket_.set_option(boost::asio::ip::multicast::leave_group( - boost::asio::ip::address::from_string(_address))); + if (is_joined(_address)) { + if (local_.address().is_v4()) { + socket_.set_option(boost::asio::ip::multicast::leave_group( + boost::asio::ip::address::from_string(_address))); + } else if (local_.address().is_v6()) { + socket_.set_option(boost::asio::ip::multicast::leave_group( + boost::asio::ip::address::from_string(_address))); + } + joined_.erase(_address); } } catch (const std::exception &e) { @@ -186,36 +200,41 @@ void udp_server_endpoint_impl::leave(const std::string &_address) { } } -void udp_server_endpoint_impl::add_multicast( - service_t _service, instance_t _instance, - const std::string &_address, uint16_t _port) { +void udp_server_endpoint_impl::add_default_target( + service_t _service, const std::string &_address, uint16_t _port) { endpoint_type its_endpoint( - boost::asio::ip::address::from_string(_address), _port); - multicasts_[_service][_instance] = its_endpoint; + boost::asio::ip::address::from_string(_address), _port); + default_targets_[_service] = its_endpoint; } -void udp_server_endpoint_impl::remove_multicast( - service_t _service, instance_t _instance) { - auto found_service = multicasts_.find(_service); - if (found_service != multicasts_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - found_service->second.erase(_instance); - } +void udp_server_endpoint_impl::remove_default_target(service_t _service) { + default_targets_.erase(_service); +} + +bool udp_server_endpoint_impl::get_default_target(service_t _service, + udp_server_endpoint_impl::endpoint_type &_target) const { + bool is_valid(false); + auto find_service = default_targets_.find(_service); + if (find_service != default_targets_.end()) { + _target = find_service->second; + is_valid = true; } + return is_valid; } unsigned short udp_server_endpoint_impl::get_local_port() const { - return socket_.local_endpoint().port(); + boost::system::error_code its_error; + return socket_.local_endpoint(its_error).port(); } // TODO: find a better way to structure the receive functions void udp_server_endpoint_impl::receive_cbk( - boost::system::error_code const &_error, std::size_t _bytes) { + boost::system::error_code const &_error, std::size_t _bytes, + boost::asio::ip::address const &_destination) { #if 0 std::stringstream msg; msg << "usei::rcb(" << _error.message() << "): "; - for (std::size_t i = 0; i < _bytes + recv_buffer_size_; ++i) + for (std::size_t i = 0; i < _bytes; ++i) msg << std::hex << std::setw(2) << std::setfill('0') << (int) recv_buffer_[i] << " "; VSOMEIP_DEBUG << msg.str(); @@ -223,34 +242,50 @@ void udp_server_endpoint_impl::receive_cbk( std::shared_ptr<endpoint_host> its_host = this->host_.lock(); if (its_host) { if (!_error && 0 < _bytes) { - recv_buffer_size_ += _bytes; - uint32_t current_message_size - = utility::get_message_size(&this->recv_buffer_[0], - (uint32_t) recv_buffer_size_); - if (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE && - current_message_size <= _bytes) { - if (utility::is_request( - recv_buffer_[VSOMEIP_MESSAGE_TYPE_POS])) { - client_t its_client; - std::memcpy(&its_client, - &recv_buffer_[VSOMEIP_CLIENT_POS_MIN], - sizeof(client_t)); - session_t its_session; - std::memcpy(&its_session, - &recv_buffer_[VSOMEIP_SESSION_POS_MIN], - sizeof(session_t)); - clients_[its_client][its_session] = remote_; + std::size_t remaining_bytes = _bytes; + std::size_t i = 0; + do { + uint32_t current_message_size + = utility::get_message_size(&this->recv_buffer_[i], + (uint32_t) remaining_bytes); + if (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE && + current_message_size <= remaining_bytes) { + remaining_bytes -= current_message_size; + if (utility::is_request( + recv_buffer_[i + VSOMEIP_MESSAGE_TYPE_POS])) { + client_t its_client; + std::memcpy(&its_client, + &recv_buffer_[i + VSOMEIP_CLIENT_POS_MIN], + sizeof(client_t)); + session_t its_session; + std::memcpy(&its_session, + &recv_buffer_[i + VSOMEIP_SESSION_POS_MIN], + sizeof(session_t)); + clients_mutex_.lock(); + clients_[its_client][its_session] = remote_; + clients_mutex_.unlock(); + } + service_t its_service = VSOMEIP_BYTES_TO_WORD(recv_buffer_[i + VSOMEIP_SERVICE_POS_MIN], + recv_buffer_[i + VSOMEIP_SERVICE_POS_MAX]); + if (its_service != VSOMEIP_SD_SERVICE || + (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE && + current_message_size >= remaining_bytes)) { + its_host->on_message(&recv_buffer_[i], current_message_size, this, _destination); + } else { + //ignore messages for service discovery with shorter SomeIP length + VSOMEIP_ERROR << "Received an unreliable vSomeIP SD message with too short length field"; + } + i += current_message_size; + } else { + VSOMEIP_ERROR << "Received an unreliable vSomeIP message with bad length field"; + service_t its_service = VSOMEIP_BYTES_TO_WORD(recv_buffer_[VSOMEIP_SERVICE_POS_MIN], + recv_buffer_[VSOMEIP_SERVICE_POS_MAX]); + if (its_service != VSOMEIP_SD_SERVICE) { + its_host->on_error(&recv_buffer_[i], (uint32_t)remaining_bytes, this); + } + remaining_bytes = 0; } - its_host->on_message(&recv_buffer_[0], current_message_size, this); - } else { - VSOMEIP_ERROR << "Received a unreliable vSomeIP message with bad length field"; - service_t its_service = VSOMEIP_BYTES_TO_WORD(recv_buffer_[VSOMEIP_SERVICE_POS_MIN], - recv_buffer_[VSOMEIP_SERVICE_POS_MAX]); - if (its_service != VSOMEIP_SD_SERVICE) { - its_host->on_error(&recv_buffer_[0], (uint32_t)_bytes, this); - } - } - recv_buffer_size_ = 0; + } while (remaining_bytes > 0); restart(); } else { receive(); @@ -260,6 +295,7 @@ void udp_server_endpoint_impl::receive_cbk( client_t udp_server_endpoint_impl::get_client(std::shared_ptr<endpoint_definition> _endpoint) { endpoint_type endpoint(_endpoint->get_address(), _endpoint->get_port()); + std::lock_guard<std::mutex> its_lock(clients_mutex_); for (auto its_client : clients_) { for (auto its_session : clients_[its_client.first]) { if (endpoint == its_session.second) { diff --git a/implementation/endpoints/src/virtual_server_endpoint_impl.cpp b/implementation/endpoints/src/virtual_server_endpoint_impl.cpp index 7700874..516619f 100644 --- a/implementation/endpoints/src/virtual_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/virtual_server_endpoint_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -60,19 +60,17 @@ void virtual_server_endpoint_impl::leave(const std::string &_address) { (void)_address; } -void virtual_server_endpoint_impl::add_multicast( - service_t _service, event_t _event, +void virtual_server_endpoint_impl::add_default_target( + service_t _service, const std::string &_address, uint16_t _port) { (void)_service; - (void)_event; (void)_address; (void)_port; } -void virtual_server_endpoint_impl::remove_multicast( - service_t _service, event_t _event) { +void virtual_server_endpoint_impl::remove_default_target( + service_t _service) { (void)_service; - (void)_event; } bool virtual_server_endpoint_impl::get_remote_address( diff --git a/implementation/helper/boost/asio/basic_datagram_socket_ext.hpp b/implementation/helper/boost/asio/basic_datagram_socket_ext.hpp new file mode 100644 index 0000000..c9a9123 --- /dev/null +++ b/implementation/helper/boost/asio/basic_datagram_socket_ext.hpp @@ -0,0 +1,954 @@ +//
+// basic_datagram_socket_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_BASIC_DATAGRAM_SOCKET_EXT_HPP
+#define BOOST_ASIO_BASIC_DATAGRAM_SOCKET_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <iostream>
+
+#include <boost/asio/detail/config.hpp>
+#include <cstddef>
+#include <boost/asio/basic_socket.hpp>
+#include <boost/asio/datagram_socket_service_ext.hpp>
+#include <boost/asio/detail/handler_type_requirements_ext.hpp>
+#include <boost/asio/detail/throw_error.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+#include <boost/asio/error.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+
+/// Provides datagram-oriented socket functionality.
+/**
+ * The basic_datagram_socket class template provides asynchronous and blocking
+ * datagram-oriented socket functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Protocol,
+ typename DatagramSocketService = datagram_socket_service_ext<Protocol> >
+class basic_datagram_socket_ext
+ : public basic_socket<Protocol, DatagramSocketService>
+{
+public:
+ /// (Deprecated: Use native_handle_type.) The native representation of a
+ /// socket.
+ typedef typename DatagramSocketService::native_handle_type native_type;
+
+ /// The native representation of a socket.
+ typedef typename DatagramSocketService::native_handle_type native_handle_type;
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ /// Construct a basic_datagram_socket without opening it.
+ /**
+ * This constructor creates a datagram socket without opening it. The open()
+ * function must be called before data can be sent or received on the socket.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ */
+ explicit basic_datagram_socket_ext(boost::asio::io_service& io_service)
+ : basic_socket<Protocol, DatagramSocketService>(io_service)
+ {
+ }
+
+ /// Construct and open a basic_datagram_socket.
+ /**
+ * This constructor creates and opens a datagram socket.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_datagram_socket_ext(boost::asio::io_service& io_service,
+ const protocol_type& protocol)
+ : basic_socket<Protocol, DatagramSocketService>(io_service, protocol)
+ {
+ }
+
+ /// Construct a basic_datagram_socket, opening it and binding it to the given
+ /// local endpoint.
+ /**
+ * This constructor creates a datagram socket and automatically opens it bound
+ * to the specified endpoint on the local machine. The protocol used is the
+ * protocol associated with the given endpoint.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the datagram
+ * socket will be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_datagram_socket_ext(boost::asio::io_service& io_service,
+ const endpoint_type& endpoint)
+ : basic_socket<Protocol, DatagramSocketService>(io_service, endpoint)
+ {
+ }
+
+ /// Construct a basic_datagram_socket on an existing native socket.
+ /**
+ * This constructor creates a datagram socket object to hold an existing
+ * native socket.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket The new underlying socket implementation.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_datagram_socket_ext(boost::asio::io_service& io_service,
+ const protocol_type& protocol, const native_handle_type& native_socket)
+ : basic_socket<Protocol, DatagramSocketService>(
+ io_service, protocol, native_socket)
+ {
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Move-construct a basic_datagram_socket from another.
+ /**
+ * This constructor moves a datagram socket from one object to another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(io_service&) constructor.
+ */
+ basic_datagram_socket_ext(basic_datagram_socket_ext&& other)
+ : basic_socket<Protocol, DatagramSocketService>(
+ BOOST_ASIO_MOVE_CAST(basic_datagram_socket_ext)(other))
+ {
+ }
+
+ /// Move-assign a basic_datagram_socket from another.
+ /**
+ * This assignment operator moves a datagram socket from one object to
+ * another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(io_service&) constructor.
+ */
+ basic_datagram_socket_ext& operator=(basic_datagram_socket_ext&& other)
+ {
+ basic_socket<Protocol, DatagramSocketService>::operator=(
+ BOOST_ASIO_MOVE_CAST(basic_datagram_socket_ext)(other));
+ return *this;
+ }
+
+ /// Move-construct a basic_datagram_socket from a socket of another protocol
+ /// type.
+ /**
+ * This constructor moves a datagram socket from one object to another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(io_service&) constructor.
+ */
+ template <typename Protocol1, typename DatagramSocketService1>
+ basic_datagram_socket_ext(
+ basic_datagram_socket_ext<Protocol1, DatagramSocketService1>&& other,
+ typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
+ : basic_socket<Protocol, DatagramSocketService>(
+ BOOST_ASIO_MOVE_CAST2(basic_datagram_socket_ext<
+ Protocol1, DatagramSocketService1>)(other))
+ {
+ }
+
+ /// Move-assign a basic_datagram_socket from a socket of another protocol
+ /// type.
+ /**
+ * This assignment operator moves a datagram socket from one object to
+ * another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(io_service&) constructor.
+ */
+ template <typename Protocol1, typename DatagramSocketService1>
+ typename enable_if<is_convertible<Protocol1, Protocol>::value,
+ basic_datagram_socket_ext>::type& operator=(
+ basic_datagram_socket_ext<Protocol1, DatagramSocketService1>&& other)
+ {
+ basic_socket<Protocol, DatagramSocketService>::operator=(
+ BOOST_ASIO_MOVE_CAST2(basic_datagram_socket_ext<
+ Protocol1, DatagramSocketService1>)(other));
+ return *this;
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One ore more data buffers to be sent on the socket.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code socket.send(boost::asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().send(
+ this->get_implementation(), buffers, 0, ec);
+ boost::asio::detail::throw_error(ec, "send");
+ return s;
+ }
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One ore more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().send(
+ this->get_implementation(), buffers, flags, ec);
+ boost::asio::detail::throw_error(ec, "send");
+ return s;
+ }
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return this->get_service().send(
+ this->get_implementation(), buffers, flags, ec);
+ }
+
+ /// Start an asynchronous send on a connected socket.
+ /**
+ * This function is used to asynchronously send data on the datagram socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @note The async_send operation can only be used with a connected socket.
+ * Use the async_send_to function to send data on an unconnected datagram
+ * socket.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_send(boost::asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send(const ConstBufferSequence& buffers,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a WriteHandler.
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ return this->get_service().async_send(this->get_implementation(),
+ buffers, 0, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+ }
+
+ /// Start an asynchronous send on a connected socket.
+ /**
+ * This function is used to asynchronously send data on the datagram socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @note The async_send operation can only be used with a connected socket.
+ * Use the async_send_to function to send data on an unconnected datagram
+ * socket.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a WriteHandler.
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ return this->get_service().async_send(this->get_implementation(),
+ buffers, flags, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * boost::asio::ip::udp::endpoint destination(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.send_to(boost::asio::buffer(data, size), destination);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().send_to(
+ this->get_implementation(), buffers, destination, 0, ec);
+ boost::asio::detail::throw_error(ec, "send_to");
+ return s;
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().send_to(
+ this->get_implementation(), buffers, destination, flags, ec);
+ boost::asio::detail::throw_error(ec, "send_to");
+ return s;
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes sent.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ return this->get_service().send_to(this->get_implementation(),
+ buffers, destination, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send a datagram to the specified
+ * remote endpoint. The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ * Copies will be made of the endpoint as required.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * boost::asio::ip::udp::endpoint destination(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.async_send_to(
+ * boost::asio::buffer(data, size), destination, handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a WriteHandler.
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ return this->get_service().async_send_to(
+ this->get_implementation(), buffers, destination, 0,
+ BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send a datagram to the specified
+ * remote endpoint. The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ * Copies will be made of the endpoint as required.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a WriteHandler.
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ return this->get_service().async_send_to(
+ this->get_implementation(), buffers, destination, flags,
+ BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code socket.receive(boost::asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().receive(
+ this->get_implementation(), buffers, 0, ec);
+ boost::asio::detail::throw_error(ec, "receive");
+ return s;
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().receive(
+ this->get_implementation(), buffers, flags, ec);
+ boost::asio::detail::throw_error(ec, "receive");
+ return s;
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes received.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return this->get_service().receive(
+ this->get_implementation(), buffers, flags, ec);
+ }
+
+ /// Start an asynchronous receive on a connected socket.
+ /**
+ * This function is used to asynchronously receive data from the datagram
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @note The async_receive operation can only be used with a connected socket.
+ * Use the async_receive_from function to receive data on an unconnected
+ * datagram socket.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.async_receive(boost::asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t))
+ async_receive(const MutableBufferSequence& buffers,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a ReadHandler.
+ BOOST_ASIO_READ_HANDLER_CHECK_EXT(ReadHandler, handler) type_check;
+
+ return this->get_service().async_receive(this->get_implementation(),
+ buffers, 0, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+ }
+
+ /// Start an asynchronous receive on a connected socket.
+ /**
+ * This function is used to asynchronously receive data from the datagram
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @note The async_receive operation can only be used with a connected socket.
+ * Use the async_receive_from function to receive data on an unconnected
+ * datagram socket.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t))
+ async_receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a ReadHandler.
+ BOOST_ASIO_READ_HANDLER_CHECK_EXT(ReadHandler, handler) type_check;
+
+ return this->get_service().async_receive(this->get_implementation(),
+ buffers, flags, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * boost::asio::ip::udp::endpoint sender_endpoint;
+ * socket.receive_from(
+ * boost::asio::buffer(data, size), sender_endpoint);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().receive_from(
+ this->get_implementation(), buffers, sender_endpoint, 0, ec);
+ boost::asio::detail::throw_error(ec, "receive_from");
+ return s;
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->get_service().receive_from(
+ this->get_implementation(), buffers, sender_endpoint, flags, ec);
+ boost::asio::detail::throw_error(ec, "receive_from");
+ return s;
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes received.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ return this->get_service().receive_from(this->get_implementation(),
+ buffers, sender_endpoint, flags, ec);
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive a datagram. The function
+ * call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram. Ownership of the sender_endpoint object
+ * is retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code socket.async_receive_from(
+ * boost::asio::buffer(data, size), sender_endpoint, handler); @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address))
+ async_receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a ReadHandler.
+ BOOST_ASIO_READ_HANDLER_CHECK_EXT(ReadHandler, handler) type_check;
+
+ return this->get_service().async_receive_from(
+ this->get_implementation(), buffers, sender_endpoint, 0,
+ BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive a datagram. The function
+ * call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram. Ownership of the sender_endpoint object
+ * is retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * boost::asio::io_service::post().
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address))
+ async_receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a ReadHandler.
+ BOOST_ASIO_READ_HANDLER_CHECK_EXT(ReadHandler, handler) type_check;
+
+ return this->get_service().async_receive_from(
+ this->get_implementation(), buffers, sender_endpoint, flags,
+ BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+ }
+};
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_BASIC_DATAGRAM_SOCKET_HPP
diff --git a/implementation/helper/boost/asio/datagram_socket_service_ext.hpp b/implementation/helper/boost/asio/datagram_socket_service_ext.hpp new file mode 100644 index 0000000..3ce03d8 --- /dev/null +++ b/implementation/helper/boost/asio/datagram_socket_service_ext.hpp @@ -0,0 +1,437 @@ +//
+// datagram_socket_service_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_EXT_ASIO_DATAGRAM_SOCKET_SERVICE_EXT_HPP
+#define BOOST_EXT_ASIO_DATAGRAM_SOCKET_SERVICE_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <iostream>
+
+#include <boost/asio/detail/config.hpp>
+#include <cstddef>
+#include <boost/asio/async_result.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+# include <boost/asio/detail/null_socket_service.hpp>
+#elif defined(BOOST_ASIO_HAS_IOCP)
+# include "detail/win_iocp_socket_service_ext.hpp"
+#else
+# include "detail/reactive_socket_service_ext.hpp"
+#endif
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+
+/// Default service implementation for a datagram socket.
+template <typename Protocol>
+class datagram_socket_service_ext
+#if defined(GENERATING_DOCUMENTATION)
+ : public boost::asio::io_service::service
+#else
+ : public boost::asio::detail::service_base<datagram_socket_service_ext<Protocol> >
+#endif
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The unique service identifier.
+ static boost::asio::io_service::id id;
+#endif
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+private:
+ // The type of the platform-specific implementation.
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+ typedef detail::null_socket_service<Protocol> service_impl_type;
+#elif defined(BOOST_ASIO_HAS_IOCP)
+ typedef detail::win_iocp_socket_service_ext<Protocol> service_impl_type;
+#else
+ typedef detail::reactive_socket_service_ext<Protocol> service_impl_type;
+#endif
+
+public:
+ /// The type of a datagram socket.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined implementation_type;
+#else
+ typedef typename service_impl_type::implementation_type implementation_type;
+#endif
+
+ /// (Deprecated: Use native_handle_type.) The native socket type.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_type;
+#else
+ typedef typename service_impl_type::native_handle_type native_type;
+#endif
+
+ /// The native socket type.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_handle_type;
+#else
+ typedef typename service_impl_type::native_handle_type native_handle_type;
+#endif
+
+ /// Construct a new datagram socket service for the specified io_service.
+ explicit datagram_socket_service_ext(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ datagram_socket_service_ext<Protocol> >(io_service),
+ service_impl_(io_service)
+ {
+ }
+
+ /// Construct a new datagram socket implementation.
+ void construct(implementation_type& impl)
+ {
+ service_impl_.construct(impl);
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Move-construct a new datagram socket implementation.
+ void move_construct(implementation_type& impl,
+ implementation_type& other_impl)
+ {
+ service_impl_.move_construct(impl, other_impl);
+ }
+
+ /// Move-assign from another datagram socket implementation.
+ void move_assign(implementation_type& impl,
+ datagram_socket_service_ext& other_service,
+ implementation_type& other_impl)
+ {
+ service_impl_.move_assign(impl, other_service.service_impl_, other_impl);
+ }
+
+ /// Move-construct a new datagram socket implementation from another protocol
+ /// type.
+ template <typename Protocol1>
+ void converting_move_construct(implementation_type& impl,
+ typename datagram_socket_service_ext<
+ Protocol1>::implementation_type& other_impl,
+ typename enable_if<is_convertible<
+ Protocol1, Protocol>::value>::type* = 0)
+ {
+ service_impl_.template converting_move_construct<Protocol1>(
+ impl, other_impl);
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+ /// Destroy a datagram socket implementation.
+ void destroy(implementation_type& impl)
+ {
+ service_impl_.destroy(impl);
+ }
+
+ // Open a new datagram socket implementation.
+ boost::system::error_code open(implementation_type& impl,
+ const protocol_type& protocol, boost::system::error_code& ec)
+ {
+ if (protocol.type() == BOOST_ASIO_OS_DEF(SOCK_DGRAM))
+ service_impl_.open(impl, protocol, ec);
+ else
+ ec = boost::asio::error::invalid_argument;
+ return ec;
+ }
+
+ /// Assign an existing native socket to a datagram socket.
+ boost::system::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_handle_type& native_socket,
+ boost::system::error_code& ec)
+ {
+ return service_impl_.assign(impl, protocol, native_socket, ec);
+ }
+
+ /// Determine whether the socket is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return service_impl_.is_open(impl);
+ }
+
+ /// Close a datagram socket implementation.
+ boost::system::error_code close(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ return service_impl_.close(impl, ec);
+ }
+
+ /// (Deprecated: Use native_handle().) Get the native socket implementation.
+ native_type native(implementation_type& impl)
+ {
+ return service_impl_.native_handle(impl);
+ }
+
+ /// Get the native socket implementation.
+ native_handle_type native_handle(implementation_type& impl)
+ {
+ return service_impl_.native_handle(impl);
+ }
+
+ /// Cancel all asynchronous operations associated with the socket.
+ boost::system::error_code cancel(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ return service_impl_.cancel(impl, ec);
+ }
+
+ /// Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return service_impl_.at_mark(impl, ec);
+ }
+
+ /// Determine the number of bytes available for reading.
+ std::size_t available(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return service_impl_.available(impl, ec);
+ }
+
+ // Bind the datagram socket to the specified local endpoint.
+ boost::system::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, boost::system::error_code& ec)
+ {
+ return service_impl_.bind(impl, endpoint, ec);
+ }
+
+ /// Connect the datagram socket to the specified endpoint.
+ boost::system::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, boost::system::error_code& ec)
+ {
+ return service_impl_.connect(impl, peer_endpoint, ec);
+ }
+
+ /// Start an asynchronous connect.
+ template <typename ConnectHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
+ void (boost::system::error_code))
+ async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint,
+ BOOST_ASIO_MOVE_ARG(ConnectHandler) handler)
+ {
+ detail::async_result_init<
+ ConnectHandler, void (boost::system::error_code)> init(
+ BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler));
+
+ service_impl_.async_connect(impl, peer_endpoint, init.handler);
+
+ return init.result.get();
+ }
+
+ /// Set a socket option.
+ template <typename SettableSocketOption>
+ boost::system::error_code set_option(implementation_type& impl,
+ const SettableSocketOption& option, boost::system::error_code& ec)
+ {
+ return service_impl_.set_option(impl, option, ec);
+ }
+
+ /// Get a socket option.
+ template <typename GettableSocketOption>
+ boost::system::error_code get_option(const implementation_type& impl,
+ GettableSocketOption& option, boost::system::error_code& ec) const
+ {
+ return service_impl_.get_option(impl, option, ec);
+ }
+
+ /// Perform an IO control command on the socket.
+ template <typename IoControlCommand>
+ boost::system::error_code io_control(implementation_type& impl,
+ IoControlCommand& command, boost::system::error_code& ec)
+ {
+ return service_impl_.io_control(impl, command, ec);
+ }
+
+ /// Gets the non-blocking mode of the socket.
+ bool non_blocking(const implementation_type& impl) const
+ {
+ return service_impl_.non_blocking(impl);
+ }
+
+ /// Sets the non-blocking mode of the socket.
+ boost::system::error_code non_blocking(implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ return service_impl_.non_blocking(impl, mode, ec);
+ }
+
+ /// Gets the non-blocking mode of the native socket implementation.
+ bool native_non_blocking(const implementation_type& impl) const
+ {
+ return service_impl_.native_non_blocking(impl);
+ }
+
+ /// Sets the non-blocking mode of the native socket implementation.
+ boost::system::error_code native_non_blocking(implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ return service_impl_.native_non_blocking(impl, mode, ec);
+ }
+
+ /// Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return service_impl_.local_endpoint(impl, ec);
+ }
+
+ /// Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return service_impl_.remote_endpoint(impl, ec);
+ }
+
+ /// Disable sends or receives on the socket.
+ boost::system::error_code shutdown(implementation_type& impl,
+ socket_base::shutdown_type what, boost::system::error_code& ec)
+ {
+ return service_impl_.shutdown(impl, what, ec);
+ }
+
+ /// Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ std::size_t send(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return service_impl_.send(impl, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send(implementation_type& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ detail::async_result_init<
+ WriteHandler, void (boost::system::error_code, std::size_t)> init(
+ BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+
+ service_impl_.async_send(impl, buffers, flags, init.handler);
+
+ return init.result.get();
+ }
+
+ /// Send a datagram to the specified endpoint.
+ template <typename ConstBufferSequence>
+ std::size_t send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers, const endpoint_type& destination,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return service_impl_.send_to(impl, buffers, destination, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers, const endpoint_type& destination,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ detail::async_result_init<
+ WriteHandler, void (boost::system::error_code, std::size_t)> init(
+ BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
+
+ service_impl_.async_send_to(impl, buffers,
+ destination, flags, init.handler);
+
+ return init.result.get();
+ }
+
+ /// Receive some data from the peer.
+ template <typename MutableBufferSequence>
+ std::size_t receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return service_impl_.receive(impl, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous receive.
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t))
+ async_receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ detail::async_result_init<
+ ReadHandler, void (boost::system::error_code, std::size_t)> init(
+ BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+
+ service_impl_.async_receive(impl, buffers, flags, init.handler);
+
+ return init.result.get();
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return service_impl_.receive_from(impl, buffers, sender_endpoint, flags,
+ ec);
+ }
+
+ /// Start an asynchronous receive that will get the endpoint of the sender.
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address))
+ async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ detail::async_result_init<
+ ReadHandler, void (boost::system::error_code, std::size_t)> init(
+ BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
+
+ service_impl_.async_receive_from(impl, buffers,
+ sender_endpoint, flags, init.handler);
+
+ return init.result.get();
+ }
+
+private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
+ // The platform-specific implementation.
+ service_impl_type service_impl_;
+};
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DATAGRAM_SOCKET_SERVICE_HPP
diff --git a/implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp b/implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp new file mode 100644 index 0000000..d81fb42 --- /dev/null +++ b/implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp @@ -0,0 +1,516 @@ +//
+// detail/handler_type_requirements_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_HPP
+#define BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+// Older versions of gcc have difficulty compiling the sizeof expressions where
+// we test the handler type requirements. We'll disable checking of handler type
+// requirements for those compilers, but otherwise enable it by default.
+#if !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+# if !defined(__GNUC__) || (__GNUC__ >= 4)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS 1
+# endif // !defined(__GNUC__) || (__GNUC__ >= 4)
+#endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+
+// With C++0x we can use a combination of enhanced SFINAE and static_assert to
+// generate better template error messages. As this technique is not yet widely
+// portable, we'll only enable it for tested compilers.
+#if !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1600)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // (_MSC_VER >= 1600)
+# endif // defined(BOOST_ASIO_MSVC)
+# if defined(__clang__)
+# if __has_feature(__cxx_static_assert__)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // __has_feature(cxx_static_assert)
+# endif // defined(__clang__)
+#endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+# include <boost/asio/handler_type.hpp>
+#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+// Newer gcc, clang need special treatment to suppress unused typedef warnings.
+#if defined(__clang__)
+# if defined(__apple_build_version__)
+# if (__clang_major__ >= 7)
+# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif // (__clang_major__ >= 7)
+# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \
+ || (__clang_major__ > 3)
+# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6))
+ // || (__clang_major__ > 3)
+#elif defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#endif // defined(__GNUC__)
+#if !defined(BOOST_ASIO_UNUSED_TYPEDEF)
+# define BOOST_ASIO_UNUSED_TYPEDEF
+#endif // !defined(BOOST_ASIO_UNUSED_TYPEDEF)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+# if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+template <typename Handler>
+auto zero_arg_handler_test(Handler h, void*)
+ -> decltype(
+ sizeof(Handler(static_cast<const Handler&>(h))),
+ ((h)()),
+ char(0));
+
+template <typename Handler>
+char (&zero_arg_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1>
+auto one_arg_handler_test(Handler h, Arg1* a1)
+ -> decltype(
+ sizeof(Handler(static_cast<const Handler&>(h))),
+ ((h)(*a1)),
+ char(0));
+
+template <typename Handler>
+char (&one_arg_handler_test(Handler h, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2>
+auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2)
+ -> decltype(
+ sizeof(Handler(static_cast<const Handler&>(h))),
+ ((h)(*a1, *a2)),
+ char(0));
+
+template <typename Handler>
+char (&two_arg_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+auto three_arg_handler_test(Handler h, Arg1* a1, Arg2* a2, Arg3* a3)
+ -> decltype(
+ sizeof(Handler(static_cast<const Handler&>(h))),
+ ((h)(*a1, *a2, *a3)),
+ char(0));
+
+template <typename Handler>
+char (&three_arg_handler_test(Handler, ...))[2];
+
+# define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \
+ static_assert(expr, msg);
+
+# else // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+# define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg)
+
+# endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+template <typename T> T& lvref();
+template <typename T> T& lvref(T);
+template <typename T> const T& clvref();
+template <typename T> const T& clvref(T);
+template <typename T> char argbyv(T);
+
+#if 0
+template <int>
+struct handler_type_requirements
+{
+};
+#endif
+
+#define BOOST_ASIO_COMPLETION_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void()) asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::zero_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), 0)) == 1, \
+ "CompletionHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()(), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_READ_HANDLER_CHECK_EXT( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t, \
+ boost::asio::ip::address)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::three_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const std::size_t*>(0), \
+ static_cast<const boost::asio::ip::address*>(0))) == 1, \
+ "ReadHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>(), \
+ boost::asio::detail::lvref<const boost::asio::ip::address>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+
+#define BOOST_ASIO_WRITE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const std::size_t*>(0))) == 1, \
+ "WriteHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::one_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0))) == 1, \
+ "AcceptHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::one_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0))) == 1, \
+ "ConnectHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, iter_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const iter_type*>(0))) == 1, \
+ "ComposedConnectHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const iter_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, iter_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const iter_type*>(0))) == 1, \
+ "ResolveHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const iter_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WAIT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::one_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0))) == 1, \
+ "WaitHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SIGNAL_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, int)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const int*>(0))) == 1, \
+ "SignalHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const int>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::one_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0))) == 1, \
+ "HandshakeHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const std::size_t*>(0))) == 1, \
+ "BufferedHandshakeHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SHUTDOWN_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::one_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0))) == 1, \
+ "ShutdownHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#else // !defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#define BOOST_ASIO_COMPLETION_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_READ_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WRITE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WAIT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SIGNAL_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SHUTDOWN_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#endif // !defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp b/implementation/helper/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp new file mode 100644 index 0000000..fe50185 --- /dev/null +++ b/implementation/helper/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp @@ -0,0 +1,270 @@ +//
+// detail/reactive_socket_service_base_ext.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_IPP
+#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP) \
+ && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#include <boost/asio/detail/reactive_socket_service_base_ext.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+reactive_socket_service_base_ext::reactive_socket_service_base_ext(
+ boost::asio::io_service& io_service)
+ : reactor_(use_service<reactor>(io_service))
+{
+ reactor_.init_task();
+}
+
+void reactive_socket_service_base_ext::shutdown_service()
+{
+}
+
+void reactive_socket_service_base_ext::construct(
+ reactive_socket_service_base_ext::base_implementation_type& impl)
+{
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+}
+
+void reactive_socket_service_base_ext::base_move_construct(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactive_socket_service_base_ext::base_implementation_type& other_impl)
+{
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = invalid_socket;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ reactor_.move_descriptor(impl.socket_,
+ impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_socket_service_base_ext::base_move_assign(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactive_socket_service_base_ext& other_service,
+ reactive_socket_service_base_ext::base_implementation_type& other_impl)
+{
+ destroy(impl);
+
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = invalid_socket;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ other_service.reactor_.move_descriptor(impl.socket_,
+ impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_socket_service_base_ext::destroy(
+ reactive_socket_service_base_ext::base_implementation_type& impl)
+{
+ if (impl.socket_ != invalid_socket)
+ {
+ BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close"));
+
+ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
+ (impl.state_ & socket_ops::possible_dup) == 0);
+
+ boost::system::error_code ignored_ec;
+ socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+ }
+}
+
+boost::system::error_code reactive_socket_service_base_ext::close(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close"));
+
+ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
+ (impl.state_ & socket_ops::possible_dup) == 0);
+ }
+
+ socket_ops::close(impl.socket_, impl.state_, false, ec);
+
+ // The descriptor is closed by the OS even if close() returns an error.
+ //
+ // (Actually, POSIX says the state of the descriptor is unspecified. On
+ // Linux the descriptor is apparently closed anyway; e.g. see
+ // http://lkml.org/lkml/2005/9/10/129
+ // We'll just have to assume that other OSes follow the same behaviour. The
+ // known exception is when Windows's closesocket() function fails with
+ // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close().
+ construct(impl);
+
+ return ec;
+}
+
+boost::system::error_code reactive_socket_service_base_ext::cancel(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ boost::system::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "cancel"));
+
+ reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
+ ec = boost::system::error_code();
+ return ec;
+}
+
+boost::system::error_code reactive_socket_service_base_ext::do_open(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ int af, int type, int protocol, boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ socket_holder sock(socket_ops::socket(af, type, protocol, ec));
+ if (sock.get() == invalid_socket)
+ return ec;
+
+ if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = sock.release();
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ ec = boost::system::error_code();
+ return ec;
+}
+
+boost::system::error_code reactive_socket_service_base_ext::do_assign(
+ reactive_socket_service_base_ext::base_implementation_type& impl, int type,
+ const reactive_socket_service_base_ext::native_handle_type& native_socket,
+ boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(
+ native_socket, impl.reactor_data_))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = native_socket;
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ impl.state_ |= socket_ops::possible_dup;
+ ec = boost::system::error_code();
+ return ec;
+}
+
+void reactive_socket_service_base_ext::start_op(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ int op_type, reactor_op* op, bool is_continuation,
+ bool is_non_blocking, bool noop)
+{
+ if (!noop)
+ {
+ if ((impl.state_ & socket_ops::non_blocking)
+ || socket_ops::set_internal_non_blocking(
+ impl.socket_, impl.state_, true, op->ec_))
+ {
+ reactor_.start_op(op_type, impl.socket_,
+ impl.reactor_data_, op, is_continuation, is_non_blocking);
+ return;
+ }
+ }
+
+ reactor_.post_immediate_completion(op, is_continuation);
+}
+
+void reactive_socket_service_base_ext::start_accept_op(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactor_op* op, bool is_continuation, bool peer_is_open)
+{
+ if (!peer_is_open)
+ start_op(impl, reactor::read_op, op, true, is_continuation, false);
+ else
+ {
+ op->ec_ = boost::asio::error::already_open;
+ reactor_.post_immediate_completion(op, is_continuation);
+ }
+}
+
+void reactive_socket_service_base_ext::start_connect_op(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactor_op* op, bool is_continuation,
+ const socket_addr_type* addr, size_t addrlen)
+{
+ if ((impl.state_ & socket_ops::non_blocking)
+ || socket_ops::set_internal_non_blocking(
+ impl.socket_, impl.state_, true, op->ec_))
+ {
+ if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
+ {
+ if (op->ec_ == boost::asio::error::in_progress
+ || op->ec_ == boost::asio::error::would_block)
+ {
+ op->ec_ = boost::system::error_code();
+ reactor_.start_op(reactor::connect_op, impl.socket_,
+ impl.reactor_data_, op, is_continuation, false);
+ return;
+ }
+ }
+ }
+
+ reactor_.post_immediate_completion(op, is_continuation);
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_IPP
diff --git a/implementation/helper/boost/asio/detail/impl/socket_ops_ext.ipp b/implementation/helper/boost/asio/detail/impl/socket_ops_ext.ipp new file mode 100644 index 0000000..cf80670 --- /dev/null +++ b/implementation/helper/boost/asio/detail/impl/socket_ops_ext.ipp @@ -0,0 +1,210 @@ +//
+// detail/impl/socket_ops_ext.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_IPP
+#define BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_IPP
+
+#include <boost/asio/detail/impl/socket_ops.ipp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+signed_size_type recvfrom(socket_type s, buf* bufs, size_t count,
+ int flags, socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec, boost::asio::ip::address& da)
+{
+ clear_last_error();
+#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+ GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
+ LPFN_WSARECVMSG WSARecvMsg;
+ DWORD NumberOfBytes;
+
+ error_wrapper(WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID,
+ &WSARecvMsg, sizeof WSARecvMsg,
+ &NumberOfBytes, NULL, NULL), ec);
+ if (ec.value() == SOCKET_ERROR) {
+ WSARecvMsg = NULL;
+ return 0;
+ }
+
+ WSABUF wsaBuf;
+ WSAMSG msg;
+ char controlBuffer[1024];
+ msg.name = addr;
+ msg.namelen = *addrlen;
+ wsaBuf.buf = bufs->buf;
+ wsaBuf.len = bufs->len;
+ msg.lpBuffers = &wsaBuf;
+ msg.dwBufferCount = count;
+ msg.Control.len = sizeof controlBuffer;
+ msg.Control.buf = controlBuffer;
+ msg.dwFlags = flags;
+
+ DWORD dwNumberOfBytesRecvd;
+ signed_size_type result = error_wrapper(WSARecvMsg(s, &msg, &dwNumberOfBytesRecvd, NULL, NULL), ec);
+
+ if (result >= 0) {
+ ec = boost::system::error_code();
+
+ // Find destination address
+ for (LPWSACMSGHDR cmsg = WSA_CMSG_FIRSTHDR(&msg);
+ cmsg != NULL;
+ cmsg = WSA_CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level != IPPROTO_IP || cmsg->cmsg_type != IP_PKTINFO)
+ continue;
+
+ struct in_pktinfo *pi = (struct in_pktinfo *) WSA_CMSG_DATA(cmsg);
+ if (pi)
+ {
+ da = boost::asio::ip::address_v4(ntohl(pi->ipi_addr.s_addr));
+ }
+ }
+ } else {
+ dwNumberOfBytesRecvd = -1;
+ }
+ return dwNumberOfBytesRecvd;
+#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+ char cmbuf[0x100];
+ msghdr msg = msghdr();
+ init_msghdr_msg_name(msg.msg_name, addr);
+ msg.msg_namelen = static_cast<int>(*addrlen);
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = static_cast<int>(count);
+ msg.msg_control = cmbuf;
+ msg.msg_controllen = sizeof(cmbuf);
+ signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec);
+ *addrlen = msg.msg_namelen;
+ if (result >= 0) {
+ ec = boost::system::error_code();
+
+ // Find destination address
+ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level != IPPROTO_IP || cmsg->cmsg_type != IP_PKTINFO)
+ continue;
+
+ struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cmsg);
+ if (pi)
+ {
+ da = boost::asio::ip::address_v4(ntohl(pi->ipi_addr.s_addr));
+ }
+ }
+ }
+ return result;
+#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,
+ size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec, boost::asio::ip::address& da)
+{
+ if (s == invalid_socket)
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ signed_size_type bytes = socket_ops::recvfrom(
+ s, bufs, count, flags, addr, addrlen, ec, da);
+
+ // Check if operation succeeded.
+ if (bytes >= 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(s, 0, ec) < 0)
+ return 0;
+ }
+}
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ boost::system::error_code& ec, boost::asio::ip::address& da)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (cancel_token.expired())
+ ec = boost::asio::error::operation_aborted;
+ else
+ ec = boost::asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
+}
+
+#else // defined(BOOST_ASIO_HAS_IOCP)
+
+bool non_blocking_recvfrom(socket_type s,
+ buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec, size_t& bytes_transferred, boost::asio::ip::address& da)
+{
+ for (;;)
+ {
+ // Read some data.
+ signed_size_type bytes = socket_ops::recvfrom(
+ s, bufs, count, flags, addr, addrlen, ec, da);
+
+ // Retry operation if interrupted by signal.
+ if (ec == boost::asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = boost::system::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_IPP
diff --git a/implementation/helper/boost/asio/detail/reactive_socket_recv_op_ext.hpp b/implementation/helper/boost/asio/detail/reactive_socket_recv_op_ext.hpp new file mode 100644 index 0000000..c4f4547 --- /dev/null +++ b/implementation/helper/boost/asio/detail/reactive_socket_recv_op_ext.hpp @@ -0,0 +1,126 @@ +//
+// detail/reactive_socket_recv_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/reactor_op_ext.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recv_op_base_ext : public reactor_op_ext
+{
+public:
+ reactive_socket_recv_op_base_ext(socket_type socket,
+ socket_ops::state_type state, const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op_ext(&reactive_socket_recv_op_base_ext::do_perform, complete_func),
+ socket_(socket),
+ state_(state),
+ buffers_(buffers),
+ flags_(flags)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_recv_op_base_ext* o(
+ static_cast<reactive_socket_recv_op_base_ext*>(base));
+
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ return socket_ops::non_blocking_recv(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ (o->state_ & socket_ops::stream_oriented) != 0,
+ o->ec_, o->bytes_transferred_);
+ }
+
+private:
+ socket_type socket_;
+ socket_ops::state_type state_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler>
+class reactive_socket_recv_op_ext :
+ public reactive_socket_recv_op_base_ext<MutableBufferSequence>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op_ext);
+
+ reactive_socket_recv_op_ext(socket_type socket,
+ socket_ops::state_type state, const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ : reactive_socket_recv_op_base_ext<MutableBufferSequence>(socket, state,
+ buffers, flags, &reactive_socket_recv_op_ext::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recv_op_ext* o(static_cast<reactive_socket_recv_op_ext*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((o));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder3<Handler, boost::system::error_code, std::size_t, boost::asio::ip::address>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->da_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3_));
+ boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp b/implementation/helper/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp new file mode 100644 index 0000000..afa6a66 --- /dev/null +++ b/implementation/helper/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp @@ -0,0 +1,136 @@ +//
+// detail/reactive_socket_recvfrom_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/reactor_op_ext.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint>
+class reactive_socket_recvfrom_op_base_ext : public reactor_op_ext
+{
+public:
+ reactive_socket_recvfrom_op_base_ext(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op_ext(&reactive_socket_recvfrom_op_base_ext::do_perform, complete_func),
+ socket_(socket),
+ protocol_type_(protocol_type),
+ buffers_(buffers),
+ sender_endpoint_(endpoint),
+ flags_(flags)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_recvfrom_op_base_ext* o(
+ static_cast<reactive_socket_recvfrom_op_base_ext*>(base));
+
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ std::size_t addr_len = o->sender_endpoint_.capacity();
+ bool result = socket_ops::non_blocking_recvfrom(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ o->sender_endpoint_.data(), &addr_len,
+ o->ec_, o->bytes_transferred_, o->da_);
+
+ if (result && !o->ec_)
+ o->sender_endpoint_.resize(addr_len);
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ int protocol_type_;
+ MutableBufferSequence buffers_;
+ Endpoint& sender_endpoint_;
+ socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Endpoint, typename Handler>
+class reactive_socket_recvfrom_op_ext :
+ public reactive_socket_recvfrom_op_base_ext<MutableBufferSequence, Endpoint>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op_ext);
+
+ reactive_socket_recvfrom_op_ext(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, Handler& handler)
+ : reactive_socket_recvfrom_op_base_ext<MutableBufferSequence, Endpoint>(
+ socket, protocol_type, buffers, endpoint, flags,
+ &reactive_socket_recvfrom_op_ext::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recvfrom_op_ext* o(
+ static_cast<reactive_socket_recvfrom_op_ext*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((o));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder3<Handler, boost::system::error_code, std::size_t, boost::asio::ip::address>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->da_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3_));
+ boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp b/implementation/helper/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp new file mode 100644 index 0000000..ba0a714 --- /dev/null +++ b/implementation/helper/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp @@ -0,0 +1,128 @@ +//
+// detail/reactive_socket_recvmsg_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/reactor_op_ext.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+#include <boost/asio/socket_base.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recvmsg_op_base_ext : public reactor_op_ext
+{
+public:
+ reactive_socket_recvmsg_op_base_ext(socket_type socket,
+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, func_type complete_func)
+ : reactor_op_ext(&reactive_socket_recvmsg_op_base_ext::do_perform, complete_func),
+ socket_(socket),
+ buffers_(buffers),
+ in_flags_(in_flags),
+ out_flags_(out_flags)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_recvmsg_op_base_ext* o(
+ static_cast<reactive_socket_recvmsg_op_base_ext*>(base));
+
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ return socket_ops::non_blocking_recvmsg(o->socket_,
+ bufs.buffers(), bufs.count(),
+ o->in_flags_, o->out_flags_,
+ o->ec_, o->bytes_transferred_);
+ }
+
+private:
+ socket_type socket_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags in_flags_;
+ socket_base::message_flags& out_flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler>
+class reactive_socket_recvmsg_op_ext :
+ public reactive_socket_recvmsg_op_base_ext<MutableBufferSequence>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op_ext);
+
+ reactive_socket_recvmsg_op_ext(socket_type socket,
+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler)
+ : reactive_socket_recvmsg_op_base_ext<MutableBufferSequence>(socket, buffers,
+ in_flags, out_flags, &reactive_socket_recvmsg_op_ext::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recvmsg_op_ext* o(
+ static_cast<reactive_socket_recvmsg_op_ext*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((o));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder3<Handler, boost::system::error_code, std::size_t, boost::asio::ip::address>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->da_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3_));
+ boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/reactive_socket_service_base_ext.hpp b/implementation/helper/boost/asio/detail/reactive_socket_service_base_ext.hpp new file mode 100644 index 0000000..cd0b19f --- /dev/null +++ b/implementation/helper/boost/asio/detail/reactive_socket_service_base_ext.hpp @@ -0,0 +1,455 @@ +//
+// detail/reactive_socket_service_base_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <iostream>
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP) \
+ && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/socket_base.hpp>
+#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/reactive_null_buffers_op.hpp>
+#include <boost/asio/detail/reactive_socket_recv_op_ext.hpp>
+#include <boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp>
+#include <boost/asio/detail/reactive_socket_send_op.hpp>
+#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
+#include <boost/asio/detail/socket_holder.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class reactive_socket_service_base_ext
+{
+public:
+ // The native type of a socket.
+ typedef socket_type native_handle_type;
+
+ // The implementation type of the socket.
+ struct base_implementation_type
+ {
+ // The native socket representation.
+ socket_type socket_;
+
+ // The current state of the socket.
+ socket_ops::state_type state_;
+
+ // Per-descriptor data used by the reactor.
+ reactor::per_descriptor_data reactor_data_;
+ };
+
+ // Constructor.
+ BOOST_ASIO_DECL reactive_socket_service_base_ext(
+ boost::asio::io_service& io_service);
+
+ // Destroy all user-defined handler objects owned by the service.
+ BOOST_ASIO_DECL void shutdown_service();
+
+ // Construct a new socket implementation.
+ BOOST_ASIO_DECL void construct(base_implementation_type& impl);
+
+ // Move-construct a new socket implementation.
+ BOOST_ASIO_DECL void base_move_construct(base_implementation_type& impl,
+ base_implementation_type& other_impl);
+
+ // Move-assign from another socket implementation.
+ BOOST_ASIO_DECL void base_move_assign(base_implementation_type& impl,
+ reactive_socket_service_base_ext& other_service,
+ base_implementation_type& other_impl);
+
+ // Destroy a socket implementation.
+ BOOST_ASIO_DECL void destroy(base_implementation_type& impl);
+
+ // Determine whether the socket is open.
+ bool is_open(const base_implementation_type& impl) const
+ {
+ return impl.socket_ != invalid_socket;
+ }
+
+ // Destroy a socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code close(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
+ // Get the native socket representation.
+ native_handle_type native_handle(base_implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Cancel all operations associated with the socket.
+ BOOST_ASIO_DECL boost::system::error_code cancel(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const base_implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return socket_ops::sockatmark(impl.socket_, ec);
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const base_implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return socket_ops::available(impl.socket_, ec);
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ boost::system::error_code listen(base_implementation_type& impl,
+ int backlog, boost::system::error_code& ec)
+ {
+ socket_ops::listen(impl.socket_, backlog, ec);
+ return ec;
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ boost::system::error_code io_control(base_implementation_type& impl,
+ IO_Control_Command& command, boost::system::error_code& ec)
+ {
+ socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the socket.
+ bool non_blocking(const base_implementation_type& impl) const
+ {
+ return (impl.state_ & socket_ops::user_set_non_blocking) != 0;
+ }
+
+ // Sets the non-blocking mode of the socket.
+ boost::system::error_code non_blocking(base_implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the native socket implementation.
+ bool native_non_blocking(const base_implementation_type& impl) const
+ {
+ return (impl.state_ & socket_ops::internal_non_blocking) != 0;
+ }
+
+ // Sets the non-blocking mode of the native socket implementation.
+ boost::system::error_code native_non_blocking(base_implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);
+ return ec;
+ }
+
+ // Disable sends or receives on the socket.
+ boost::system::error_code shutdown(base_implementation_type& impl,
+ socket_base::shutdown_type what, boost::system::error_code& ec)
+ {
+ socket_ops::shutdown(impl.socket_, what, ec);
+ return ec;
+ }
+
+ // Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ size_t send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_send(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, impl.state_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_send_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, buffers, flags, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, true,
+ ((impl.state_ & socket_ops::stream_oriented)
+ && buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence>::all_empty(buffers)));
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_send(null_buffers)"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_recv(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recv_op_ext<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation,
+ (flags & socket_base::message_out_of_band) == 0,
+ ((impl.state_ & socket_ops::stream_oriented)
+ && buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(buffers)));
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_receive(null_buffers)"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive some data with associated flags. Returns the number of bytes
+ // received.
+ template <typename MutableBufferSequence>
+ size_t receive_with_flags(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_recvmsg(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), in_flags, out_flags, ec);
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_with_flags(base_implementation_type& impl,
+ const null_buffers&, socket_base::message_flags,
+ socket_base::message_flags& out_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, ec);
+
+ // Clear out_flags, since we cannot give it any other sensible value when
+ // performing a null_buffers operation.
+ out_flags = 0;
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive_with_flags(base_implementation_type& impl,
+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recvmsg_op_ext<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, buffers, in_flags, out_flags, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_receive_with_flags"));
+
+ start_op(impl,
+ (in_flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation,
+ (in_flags & socket_base::message_out_of_band) == 0, false);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive_with_flags(base_implementation_type& impl,
+ const null_buffers&, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl,
+ "async_receive_with_flags(null_buffers)"));
+
+ // Clear out_flags, since we cannot give it any other sensible value when
+ // performing a null_buffers operation.
+ out_flags = 0;
+
+ start_op(impl,
+ (in_flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+protected:
+ // Open a new socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code do_open(
+ base_implementation_type& impl, int af,
+ int type, int protocol, boost::system::error_code& ec);
+
+ // Assign a native socket to a socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code do_assign(
+ base_implementation_type& impl, int type,
+ const native_handle_type& native_socket, boost::system::error_code& ec);
+
+ // Start the asynchronous read or write operation.
+ BOOST_ASIO_DECL void start_op(base_implementation_type& impl, int op_type,
+ reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);
+
+ // Start the asynchronous accept operation.
+ BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl,
+ reactor_op* op, bool is_continuation, bool peer_is_open);
+
+ // Start the asynchronous connect operation.
+ BOOST_ASIO_DECL void start_connect_op(base_implementation_type& impl,
+ reactor_op* op, bool is_continuation,
+ const socket_addr_type* addr, size_t addrlen);
+
+ // The selector that performs event demultiplexing for the service.
+ reactor& reactor_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_ASIO_HEADER_ONLY)
+# include <boost/asio/detail/impl/reactive_socket_service_base_ext.ipp>
+#endif // defined(BOOST_ASIO_HEADER_ONLY)
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/reactive_socket_service_ext.hpp b/implementation/helper/boost/asio/detail/reactive_socket_service_ext.hpp new file mode 100644 index 0000000..a13e5c8 --- /dev/null +++ b/implementation/helper/boost/asio/detail/reactive_socket_service_ext.hpp @@ -0,0 +1,462 @@ +//
+// detail/reactive_socket_service_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <iostream>
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/socket_base.hpp>
+#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/reactive_null_buffers_op.hpp>
+#include <boost/asio/detail/reactive_socket_accept_op.hpp>
+#include <boost/asio/detail/reactive_socket_connect_op.hpp>
+#include <boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp>
+#include <boost/asio/detail/reactive_socket_sendto_op.hpp>
+#include <boost/asio/detail/reactive_socket_service_base_ext.hpp>
+#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
+#include <boost/asio/detail/socket_holder.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class reactive_socket_service_ext :
+ public reactive_socket_service_base_ext
+{
+public:
+ // The protocol type.
+ typedef Protocol protocol_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The native type of a socket.
+ typedef socket_type native_handle_type;
+
+ // The implementation type of the socket.
+ struct implementation_type :
+ reactive_socket_service_base_ext::base_implementation_type
+ {
+ // Default constructor.
+ implementation_type()
+ : protocol_(endpoint_type().protocol())
+ {
+ }
+
+ // The protocol associated with the socket.
+ protocol_type protocol_;
+ };
+
+ // Constructor.
+ reactive_socket_service_ext(boost::asio::io_service& io_service)
+ : reactive_socket_service_base_ext(io_service)
+ {
+ }
+
+ // Move-construct a new socket implementation.
+ void move_construct(implementation_type& impl,
+ implementation_type& other_impl)
+ {
+ this->base_move_construct(impl, other_impl);
+
+ impl.protocol_ = other_impl.protocol_;
+ other_impl.protocol_ = endpoint_type().protocol();
+ }
+
+ // Move-assign from another socket implementation.
+ void move_assign(implementation_type& impl,
+ reactive_socket_service_base_ext& other_service,
+ implementation_type& other_impl)
+ {
+ this->base_move_assign(impl, other_service, other_impl);
+
+ impl.protocol_ = other_impl.protocol_;
+ other_impl.protocol_ = endpoint_type().protocol();
+ }
+
+ // Move-construct a new socket implementation from another protocol type.
+ template <typename Protocol1>
+ void converting_move_construct(implementation_type& impl,
+ typename reactive_socket_service_ext<
+ Protocol1>::implementation_type& other_impl)
+ {
+ this->base_move_construct(impl, other_impl);
+
+ impl.protocol_ = protocol_type(other_impl.protocol_);
+ other_impl.protocol_ = typename Protocol1::endpoint().protocol();
+ }
+
+ // Open a new socket implementation.
+ boost::system::error_code open(implementation_type& impl,
+ const protocol_type& protocol, boost::system::error_code& ec)
+ {
+ if (!do_open(impl, protocol.family(),
+ protocol.type(), protocol.protocol(), ec))
+ impl.protocol_ = protocol;
+ return ec;
+ }
+
+ // Assign a native socket to a socket implementation.
+ boost::system::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_handle_type& native_socket,
+ boost::system::error_code& ec)
+ {
+ if (!do_assign(impl, protocol.type(), native_socket, ec))
+ impl.protocol_ = protocol;
+ return ec;
+ }
+
+ // Get the native socket representation.
+ native_handle_type native_handle(implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Bind the socket to the specified local endpoint.
+ boost::system::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, boost::system::error_code& ec)
+ {
+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code set_option(implementation_type& impl,
+ const Option& option, boost::system::error_code& ec)
+ {
+ socket_ops::setsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), option.size(impl.protocol_), ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code get_option(const implementation_type& impl,
+ Option& option, boost::system::error_code& ec) const
+ {
+ std::size_t size = option.size(impl.protocol_);
+ socket_ops::getsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), &size, ec);
+ if (!ec)
+ option.resize(impl.protocol_, size);
+ return ec;
+ }
+
+ // Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getpeername(impl.socket_,
+ endpoint.data(), &addr_len, false, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Send a datagram to the specified endpoint. Returns the number of bytes
+ // sent.
+ template <typename ConstBufferSequence>
+ size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_sendto(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags,
+ destination.data(), destination.size(), ec);
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send_to(implementation_type& impl, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags,
+ boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, impl.state_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_sendto_op<ConstBufferSequence,
+ endpoint_type, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send_to"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, true, false);
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send_to(implementation_type& impl, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_send_to(null_buffers)"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive a datagram with the endpoint of the sender. Returns the number of
+ // bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ std::size_t addr_len = sender_endpoint.capacity();
+ std::size_t bytes_recvd = socket_ops::sync_recvfrom(
+ impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
+ flags, sender_endpoint.data(), &addr_len, ec);
+
+ if (!ec)
+ sender_endpoint.resize(addr_len);
+
+ return bytes_recvd;
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_from(implementation_type& impl, const null_buffers&,
+ endpoint_type& sender_endpoint, socket_base::message_flags,
+ boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, ec);
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received and
+ // the sender_endpoint object must both be valid for the lifetime of the
+ // asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recvfrom_op_ext<MutableBufferSequence,
+ endpoint_type, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ int protocol = impl.protocol_.type();
+ p.p = new (p.v) op(impl.socket_, protocol,
+ buffers, sender_endpoint, flags, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_receive_from"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, true, false);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive_from(implementation_type& impl,
+ const null_buffers&, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
+ &impl, "async_receive_from(null_buffers)"));
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Accept a new connection.
+ template <typename Socket>
+ boost::system::error_code accept(implementation_type& impl,
+ Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec)
+ {
+ // We cannot accept a socket that is already open.
+ if (peer.is_open())
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
+ socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
+ impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
+ peer_endpoint ? &addr_len : 0, ec));
+
+ // On success, assign new connection to peer socket object.
+ if (new_socket.get() != invalid_socket)
+ {
+ if (peer_endpoint)
+ peer_endpoint->resize(addr_len);
+ if (!peer.assign(impl.protocol_, new_socket.get(), ec))
+ new_socket.release();
+ }
+
+ return ec;
+ }
+
+ // Start an asynchronous accept. The peer and peer_endpoint objects
+ // must be valid until the accept's handler is invoked.
+ template <typename Socket, typename Handler>
+ void async_accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_accept_op<Socket, Protocol, Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, impl.state_, peer,
+ impl.protocol_, peer_endpoint, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_accept"));
+
+ start_accept_op(impl, p.p, is_continuation, peer.is_open());
+ p.v = p.p = 0;
+ }
+
+ // Connect the socket to the specified endpoint.
+ boost::system::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, boost::system::error_code& ec)
+ {
+ socket_ops::sync_connect(impl.socket_,
+ peer_endpoint.data(), peer_endpoint.size(), ec);
+ return ec;
+ }
+
+ // Start an asynchronous connect.
+ template <typename Handler>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, Handler& handler)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_connect_op<Handler> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ boost_asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, handler);
+
+ BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect"));
+
+ start_connect_op(impl, p.p, is_continuation,
+ peer_endpoint.data(), peer_endpoint.size());
+ p.v = p.p = 0;
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/reactor_op_ext.hpp b/implementation/helper/boost/asio/detail/reactor_op_ext.hpp new file mode 100644 index 0000000..575fba2 --- /dev/null +++ b/implementation/helper/boost/asio/detail/reactor_op_ext.hpp @@ -0,0 +1,42 @@ +//
+// detail/reactor_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTOR_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTOR_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/reactor_op.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class reactor_op_ext
+ : public reactor_op
+{
+public:
+ // The destination address
+ boost::asio::ip::address da_;
+
+ reactor_op_ext(perform_func_type perform_func, func_type complete_func)
+ : reactor_op(perform_func, complete_func)
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_REACTOR_OP_EXT_HPP
diff --git a/implementation/helper/boost/asio/detail/socket_ops_ext.hpp b/implementation/helper/boost/asio/detail/socket_ops_ext.hpp new file mode 100644 index 0000000..9280830 --- /dev/null +++ b/implementation/helper/boost/asio/detail/socket_ops_ext.hpp @@ -0,0 +1,62 @@ +//
+// detail/socket_ops_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_HPP
+#define BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/socket_ops.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+BOOST_ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs,
+ size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec,
+ boost::asio::ip::address& da);
+
+BOOST_ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state,
+ buf* bufs, size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec, boost::asio::ip::address& da);
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+BOOST_ASIO_DECL void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ boost::system::error_code& ec,
+ boost::asio::ip::address& da);
+
+#else // defined(BOOST_ASIO_HAS_IOCP)
+
+BOOST_ASIO_DECL bool non_blocking_recvfrom(socket_type s,
+ buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec, size_t& bytes_transferred,
+ boost::asio::ip::address& da);
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+
+#if defined(BOOST_ASIO_HEADER_ONLY)
+# include <boost/asio/detail/impl/socket_ops_ext.ipp>
+#endif // defined(BOOST_ASIO_HEADER_ONLY)
+
+#endif // BOOST_EXT_ASIO_DETAIL_SOCKET_OPS_HPP
diff --git a/implementation/helper/boost/asio/ip/udp_ext.hpp b/implementation/helper/boost/asio/ip/udp_ext.hpp new file mode 100644 index 0000000..d5f054e --- /dev/null +++ b/implementation/helper/boost/asio/ip/udp_ext.hpp @@ -0,0 +1,115 @@ +//
+// ip/udp_ext.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_IP_UDP_EXT_HPP
+#define BOOST_ASIO_IP_UDP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/basic_datagram_socket_ext.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/ip/basic_endpoint.hpp>
+#include <boost/asio/ip/basic_resolver.hpp>
+#include <boost/asio/ip/basic_resolver_iterator.hpp>
+#include <boost/asio/ip/basic_resolver_query.hpp>
+#include <boost/asio/ip/udp.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace ip {
+
+/// Encapsulates the flags needed for UDP.
+/**
+ * The boost::asio::ip::udp_ext class contains flags necessary for UDP sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol, InternetProtocol.
+ */
+class udp_ext
+{
+public:
+ /// The type of a UDP endpoint.
+ typedef basic_endpoint<udp> endpoint;
+
+ /// Construct to represent the IPv4 UDP protocol.
+ static udp_ext v4()
+ {
+ return udp_ext(BOOST_ASIO_OS_DEF(AF_INET));
+ }
+
+ /// Construct to represent the IPv6 UDP protocol.
+ static udp_ext v6()
+ {
+ return udp_ext(BOOST_ASIO_OS_DEF(AF_INET6));
+ }
+
+ /// Obtain an identifier for the type of the protocol.
+ int type() const
+ {
+ return BOOST_ASIO_OS_DEF(SOCK_DGRAM);
+ }
+
+ /// Obtain an identifier for the protocol.
+ int protocol() const
+ {
+ return BOOST_ASIO_OS_DEF(IPPROTO_UDP);
+ }
+
+ /// Obtain an identifier for the protocol family.
+ int family() const
+ {
+ return family_;
+ }
+
+ /// The UDP socket type.
+ typedef basic_datagram_socket_ext<udp> socket;
+
+ /// The UDP resolver type.
+ typedef basic_resolver<udp> resolver;
+
+ /// Compare two protocols for equality.
+ friend bool operator==(const udp_ext& p1, const udp_ext& p2)
+ {
+ return p1.family_ == p2.family_;
+ }
+
+ /// Compare two protocols for inequality.
+ friend bool operator!=(const udp_ext& p1, const udp_ext& p2)
+ {
+ return p1.family_ != p2.family_;
+ }
+
+private:
+ // Construct with a specific family.
+ explicit udp_ext(int protocol_family)
+ : family_(protocol_family)
+ {
+ }
+
+ int family_;
+};
+
+} // namespace ip
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_IP_UDP_EXT_HPP
diff --git a/implementation/logging/include/defines.hpp b/implementation/logging/include/defines.hpp new file mode 100644 index 0000000..bef1a72 --- /dev/null +++ b/implementation/logging/include/defines.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef LOGGING_DEFINES_HPP_ +#define LOGGING_DEFINES_HPP_ + +#define VSOMEIP_LOG_DEFAULT_APPLICATION_ID "VSIP" +#define VSOMEIP_LOG_DEFAULT_APPLICATION_NAME "vSomeIP application" + +#define VSOMEIP_LOG_DEFAULT_CONTEXT_ID "VSIP" +#define VSOMEIP_LOG_DEFAULT_CONTEXT_NAME "vSomeIP context" + +#endif /* LOGGING_DEFINES_HPP_ */ diff --git a/implementation/logging/include/dlt_sink_backend.hpp b/implementation/logging/include/dlt_sink_backend.hpp index 1b7fd09..2031158 100644 --- a/implementation/logging/include/dlt_sink_backend.hpp +++ b/implementation/logging/include/dlt_sink_backend.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -27,12 +27,14 @@ class dlt_sink_backend : >::type > { public: - dlt_sink_backend(); + dlt_sink_backend(const std::string &_app_id, + const std::string &_context_id); virtual ~dlt_sink_backend(); void consume(const logging::record_view &rec); private: + #ifdef USE_DLT DltLogLevelType level_as_dlt(logging::trivial::severity_level _level); DLT_DECLARE_CONTEXT(dlt_); diff --git a/implementation/logging/include/logger.hpp b/implementation/logging/include/logger.hpp index 555f15e..7bbc00a 100644 --- a/implementation/logging/include/logger.hpp +++ b/implementation/logging/include/logger.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/logging/include/logger_impl.hpp b/implementation/logging/include/logger_impl.hpp index ddc4eb2..3916874 100644 --- a/implementation/logging/include/logger_impl.hpp +++ b/implementation/logging/include/logger_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -43,7 +43,8 @@ public: private:
void enable_console();
void enable_file(const std::string &_path);
- void enable_dlt();
+ void enable_dlt(const std::string &_app_id,
+ const std::string &_context_id);
private:
boost::log::sources::severity_logger<
diff --git a/implementation/logging/src/dlt_sink_backend.cpp b/implementation/logging/src/dlt_sink_backend.cpp index b4d2864..9da5ae9 100644 --- a/implementation/logging/src/dlt_sink_backend.cpp +++ b/implementation/logging/src/dlt_sink_backend.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -10,23 +10,28 @@ #endif #include <boost/log/expressions.hpp> +#include "../include/defines.hpp" namespace expressions = boost::log::expressions; namespace vsomeip { -dlt_sink_backend::dlt_sink_backend() { +dlt_sink_backend::dlt_sink_backend(const std::string &_app_id, + const std::string &_context_id) { + (void)_app_id; #ifdef USE_DLT - DLT_REGISTER_APP("vSIP", "vSomeIP application"); - DLT_REGISTER_CONTEXT(dlt_, "vSIP", "vSomeIP context"); + DLT_REGISTER_CONTEXT_LL_TS(dlt_, _context_id.c_str(), + VSOMEIP_LOG_DEFAULT_CONTEXT_NAME, DLT_LOG_DEBUG, + DLT_TRACE_STATUS_ON); +#else + (void)_context_id; #endif } dlt_sink_backend::~dlt_sink_backend() { #ifdef USE_DLT DLT_UNREGISTER_CONTEXT(dlt_); - DLT_UNREGISTER_APP(); #endif } diff --git a/implementation/logging/src/logger.cpp b/implementation/logging/src/logger.cpp index 03f05aa..54b5d75 100644 --- a/implementation/logging/src/logger.cpp +++ b/implementation/logging/src/logger.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/logging/src/logger_impl.cpp b/implementation/logging/src/logger_impl.cpp index 6bf4e08..3934c1e 100644 --- a/implementation/logging/src/logger_impl.cpp +++ b/implementation/logging/src/logger_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -29,8 +29,11 @@ #include <boost/core/null_deleter.hpp>
#endif
+#include <vsomeip/runtime.hpp>
+
#include "../include/logger_impl.hpp"
#include "../../configuration/include/configuration.hpp"
+#include "../include/defines.hpp"
namespace logging = boost::log;
namespace sources = boost::log::sources;
@@ -71,8 +74,13 @@ void logger_impl::init(const std::shared_ptr<configuration> &_configuration) { if (_configuration->has_file_log())
get()->enable_file(_configuration->get_logfile());
- if (_configuration->has_dlt_log())
- get()->enable_dlt();
+ if (_configuration->has_dlt_log()) {
+ std::string app_id = runtime::get_property("LogApplication");
+ if (app_id == "") app_id = VSOMEIP_LOG_DEFAULT_APPLICATION_ID;
+ std::string context_id = runtime::get_property("LogContext");
+ if (context_id == "") context_id = VSOMEIP_LOG_DEFAULT_CONTEXT_ID;
+ get()->enable_dlt(app_id, context_id);
+ }
}
void logger_impl::enable_console() {
@@ -123,14 +131,19 @@ void logger_impl::enable_file(const std::string &_path) { logging::core::get()->add_sink(file_sink_);
}
-void logger_impl::enable_dlt() {
+void logger_impl::enable_dlt(const std::string &_app_id,
+ const std::string &_context_id) {
#ifdef USE_DLT
if (dlt_sink_)
return;
- boost::shared_ptr<dlt_sink_backend> backend = boost::make_shared<dlt_sink_backend>();
+ boost::shared_ptr<dlt_sink_backend> backend = boost::make_shared<dlt_sink_backend>(_app_id,
+ _context_id);
dlt_sink_ = boost::make_shared<dlt_sink_t>(backend);
logging::core::get()->add_sink(dlt_sink_);
+#else
+ (void)_app_id;
+ (void)_context_id;
#endif
}
diff --git a/implementation/message/include/deserializer.hpp b/implementation/message/include/deserializer.hpp index 941358b..0588aa7 100644 --- a/implementation/message/include/deserializer.hpp +++ b/implementation/message/include/deserializer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/message/include/message_base_impl.hpp b/implementation/message/include/message_base_impl.hpp index 58562f1..40486a2 100644 --- a/implementation/message/include/message_base_impl.hpp +++ b/implementation/message/include/message_base_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -56,12 +56,16 @@ public: VSOMEIP_EXPORT bool is_reliable() const;
VSOMEIP_EXPORT void set_reliable(bool _is_reliable);
+ VSOMEIP_EXPORT virtual bool is_initial() const;
+ VSOMEIP_EXPORT virtual void set_initial(bool _is_initial);
+
VSOMEIP_EXPORT message * get_owner() const;
VSOMEIP_EXPORT void set_owner(message *_owner);
protected: // members
message_header_impl header_;
bool is_reliable_;
+ bool is_initial_;
};
} // namespace vsomeip
diff --git a/implementation/message/include/message_header_impl.hpp b/implementation/message/include/message_header_impl.hpp index b233d75..18f734d 100644 --- a/implementation/message/include/message_header_impl.hpp +++ b/implementation/message/include/message_header_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/message/include/message_impl.hpp b/implementation/message/include/message_impl.hpp index 7c8902c..102833a 100644 --- a/implementation/message/include/message_impl.hpp +++ b/implementation/message/include/message_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -11,6 +11,16 @@ #include <vsomeip/export.hpp>
#include "message_base_impl.hpp"
+# if _MSC_VER >= 1300
+/*
+* Diamond inheritance is used for the vsomeip::message_base base class.
+* The Microsoft compiler put warning (C4250) using a desired c++ feature: "Delegating to a sister class"
+* A powerful technique that arises from using virtual inheritance is to delegate a method from a class in another class
+* by using a common abstract base class. This is also called cross delegation.
+*/
+# pragma warning( disable : 4250 )
+# endif
+
namespace vsomeip {
class payload;
diff --git a/implementation/message/include/payload_impl.hpp b/implementation/message/include/payload_impl.hpp index 2530ac8..66b3afa 100644 --- a/implementation/message/include/payload_impl.hpp +++ b/implementation/message/include/payload_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/message/include/serializer.hpp b/implementation/message/include/serializer.hpp index 427ee20..7928a52 100644 --- a/implementation/message/include/serializer.hpp +++ b/implementation/message/include/serializer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/message/src/deserializer.cpp b/implementation/message/src/deserializer.cpp index 6017d5a..fb6f670 100644 --- a/implementation/message/src/deserializer.cpp +++ b/implementation/message/src/deserializer.cpp @@ -8,12 +8,11 @@ #ifdef VSOMEIP_DEBUGGING
#include <iomanip>
#include <sstream>
-
-#include "../../logging/include/logger.hpp"
#endif
#include "../include/message_impl.hpp"
#include "../include/deserializer.hpp"
+#include "../../logging/include/logger.hpp"
#include "../../utility/include/byteorder.hpp"
namespace vsomeip {
@@ -148,8 +147,9 @@ message * deserializer::deserialize_message() { message_impl* deserialized_message = new message_impl;
if (0 != deserialized_message) {
if (false == deserialized_message->deserialize(this)) {
+ VSOMEIP_ERROR << "SOME/IP message deserialization failed!";
delete deserialized_message;
- deserialized_message = 0;
+ deserialized_message = nullptr;
}
}
diff --git a/implementation/message/src/message_base_impl.cpp b/implementation/message/src/message_base_impl.cpp index 616ed63..c9597fc 100644 --- a/implementation/message/src/message_base_impl.cpp +++ b/implementation/message/src/message_base_impl.cpp @@ -9,7 +9,8 @@ namespace vsomeip {
message_base_impl::message_base_impl()
- : is_reliable_(false) {
+ : is_reliable_(false),
+ is_initial_(false) {
header_.set_owner(this);
}
@@ -110,4 +111,11 @@ void message_base_impl::set_reliable(bool _is_reliable) { is_reliable_ = _is_reliable;
}
+bool message_base_impl::is_initial() const {
+ return is_initial_;
+}
+void message_base_impl::set_initial(bool _is_initial) {
+ is_initial_ = _is_initial;
+}
+
} // namespace vsomeip
diff --git a/implementation/routing/include/event.hpp b/implementation/routing/include/event.hpp index 2036636..9033160 100644 --- a/implementation/routing/include/event.hpp +++ b/implementation/routing/include/event.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -27,7 +27,7 @@ class routing_manager; class event: public std::enable_shared_from_this<event> { public: - event(routing_manager *_routing); + event(routing_manager *_routing, bool _is_shadow = false); service_t get_service() const; void set_service(service_t _service); @@ -48,8 +48,10 @@ public: void set_payload(std::shared_ptr<payload> _payload, const std::shared_ptr<endpoint_definition> _target); + void set_payload_dont_notify(std::shared_ptr<payload> _payload); + void set_payload(std::shared_ptr<payload> _payload); - void unset_payload(); + void unset_payload(bool _force = false); bool is_field() const; void set_field(bool _is_field); @@ -57,6 +59,8 @@ public: bool is_provided() const; void set_provided(bool _is_provided); + bool is_set() const; + // SIP_RPC_357 void set_update_cycle(std::chrono::milliseconds &_cycle); @@ -70,10 +74,17 @@ public: void set_eventgroups(const std::set<eventgroup_t> &_eventgroups); void notify_one(const std::shared_ptr<endpoint_definition> &_target); - void notify_one(client_t _client); + void notify_one(client_t _client, bool _is_initial = false); + + void add_ref(client_t _client, bool _is_provided); + void remove_ref(client_t _client, bool _is_provided); + bool has_ref(); - void add_ref(); - uint32_t remove_ref(); + bool is_shadow() const; + void set_shadow(bool _shadow); + + bool is_cache_placeholder() const; + void set_cache_placeholder(bool _is_cache_place_holder); private: void update_cbk(boost::system::error_code const &_error); @@ -99,7 +110,11 @@ private: bool is_set_; bool is_provided_; - uint32_t ref_; + std::map<client_t, std::map<bool, uint32_t>> refs_; + + bool is_shadow_; + + bool is_cache_placeholder_; }; } // namespace vsomeip diff --git a/implementation/routing/include/eventgroupinfo.hpp b/implementation/routing/include/eventgroupinfo.hpp index 08536e0..7e832a1 100644 --- a/implementation/routing/include/eventgroupinfo.hpp +++ b/implementation/routing/include/eventgroupinfo.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -6,6 +6,8 @@ #ifndef VSOMEIP_EVENTGROUPINFO_HPP #define VSOMEIP_EVENTGROUPINFO_HPP +#include <chrono> +#include <list> #include <memory> #include <set> @@ -21,6 +23,15 @@ class event; class eventgroupinfo { public: + struct target_t { + std::shared_ptr<endpoint_definition> endpoint_; + std::chrono::high_resolution_clock::time_point expiration_; + + bool operator==(const target_t &_other) const { + return (endpoint_ == _other.endpoint_); + } + }; + VSOMEIP_EXPORT eventgroupinfo(); VSOMEIP_EXPORT eventgroupinfo(major_version_t _major, ttl_t _ttl); VSOMEIP_EXPORT ~eventgroupinfo(); @@ -41,22 +52,32 @@ public: VSOMEIP_EXPORT void add_event(std::shared_ptr<event> _event); VSOMEIP_EXPORT void remove_event(std::shared_ptr<event> _event); - VSOMEIP_EXPORT const std::set< - std::shared_ptr<endpoint_definition> > get_targets() const; - VSOMEIP_EXPORT bool add_target(std::shared_ptr<endpoint_definition> _target); - VSOMEIP_EXPORT bool remove_target(std::shared_ptr<endpoint_definition> _target); + VSOMEIP_EXPORT const std::list<target_t> get_targets() const; + VSOMEIP_EXPORT uint32_t get_unreliable_target_count(); + + VSOMEIP_EXPORT bool add_target(const target_t &_target); + VSOMEIP_EXPORT bool add_target(const target_t &_target, const target_t &_subscriber); + VSOMEIP_EXPORT bool update_target( + const std::shared_ptr<endpoint_definition> &_target, + const std::chrono::high_resolution_clock::time_point &_expiration); + VSOMEIP_EXPORT bool remove_target( + const std::shared_ptr<endpoint_definition> &_target); VSOMEIP_EXPORT void clear_targets(); + VSOMEIP_EXPORT void add_multicast_target(const target_t &_multicast_target); + VSOMEIP_EXPORT void clear_multicast_targets(); + VSOMEIP_EXPORT const std::list<target_t> get_multicast_targets() const; + private: major_version_t major_; ttl_t ttl_; - bool is_multicast_; boost::asio::ip::address address_; uint16_t port_; std::set<std::shared_ptr<event> > events_; - std::set<std::shared_ptr<endpoint_definition> > targets_; + std::list<target_t> targets_; + std::list<target_t> multicast_targets_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager.hpp b/implementation/routing/include/routing_manager.hpp index 2642677..ee18957 100644 --- a/implementation/routing/include/routing_manager.hpp +++ b/implementation/routing/include/routing_manager.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -13,6 +13,7 @@ #include <boost/asio/io_service.hpp> #include <vsomeip/message.hpp> +#include <vsomeip/handler.hpp> namespace vsomeip { @@ -39,7 +40,7 @@ public: minor_version_t _minor) = 0; virtual void stop_offer_service(client_t _client, service_t _service, - instance_t _instance) = 0; + instance_t _instance, major_version_t _major, minor_version_t _minor) = 0; virtual void request_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, @@ -50,7 +51,8 @@ public: virtual void subscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, subscription_type_e _subscription_type) = 0; + major_version_t _major, + subscription_type_e _subscription_type) = 0; virtual void unsubscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup) = 0; @@ -59,7 +61,7 @@ public: bool _flush) = 0; virtual bool send(client_t _client, const byte_t *_data, uint32_t _size, - instance_t _instance, bool _flush, bool _reliable) = 0; + instance_t _instance, bool _flush, bool _reliable, bool _initial) = 0; virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message>) = 0; @@ -69,17 +71,26 @@ public: virtual void register_event(client_t _client, service_t _service, instance_t _instance, event_t _event, const std::set<eventgroup_t> &_eventgroups, - bool _is_field, bool _is_provided) = 0; + bool _is_field, bool _is_provided, bool _is_shadow = false, + bool _is_cache_placeholder = false) = 0; virtual void unregister_event(client_t _client, service_t _service, instance_t _instance, event_t _event, bool _is_provided) = 0; + virtual std::shared_ptr<event> get_event(service_t _service, + instance_t _instance, event_t _event) const = 0; + + virtual std::set<std::shared_ptr<event>> find_events(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const = 0; + virtual void notify(service_t _service, instance_t _instance, event_t _event, std::shared_ptr<payload> _payload) = 0; virtual void notify_one(service_t _service, instance_t _instance, event_t _event, std::shared_ptr<payload> _payload, client_t _client) = 0; + virtual void on_identify_response(client_t _client, service_t _service, instance_t _instance, + bool _reliable) = 0; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_adapter.hpp b/implementation/routing/include/routing_manager_adapter.hpp index fc0e55d..0dfe703 100644 --- a/implementation/routing/include/routing_manager_adapter.hpp +++ b/implementation/routing/include/routing_manager_adapter.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/routing/include/routing_manager_base.hpp b/implementation/routing/include/routing_manager_base.hpp new file mode 100644 index 0000000..1d69f6f --- /dev/null +++ b/implementation/routing/include/routing_manager_base.hpp @@ -0,0 +1,193 @@ +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_ROUTING_MANAGER_BASE +#define VSOMEIP_ROUTING_MANAGER_BASE + +#include <mutex> +#include <unordered_set> + +#include <vsomeip/constants.hpp> +#include "routing_manager.hpp" +#include "routing_manager_host.hpp" +#include "types.hpp" +#include "serviceinfo.hpp" +#include "event.hpp" +#include "eventgroupinfo.hpp" +#include "../../message/include/serializer.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../endpoints/include/endpoint_host.hpp" + +#ifdef USE_DLT +#include "../../tracing/include/trace_connector.hpp" +#endif + +#ifdef USE_DLT +namespace tc { +class trace_connector; +} // namespace tc +#endif + +namespace vsomeip { + +class serializer; + +class routing_manager_base : public routing_manager, + public endpoint_host, + public std::enable_shared_from_this<routing_manager_base>{ + +public: + routing_manager_base(routing_manager_host *_host); + virtual ~routing_manager_base(); + + virtual boost::asio::io_service & get_io(); + virtual client_t get_client() const; + + virtual void init(); + + virtual void offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor); + + virtual void stop_offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor); + + virtual void request_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor, bool _use_exclusive_proxy); + + virtual void release_service(client_t _client, service_t _service, + instance_t _instance); + + virtual void register_event(client_t _client, service_t _service, instance_t _instance, + event_t _event, const std::set<eventgroup_t> &_eventgroups, + bool _is_field, bool _is_provided, bool _is_shadow = false, + bool _is_cache_placeholder = false); + + virtual void unregister_event(client_t _client, service_t _service, instance_t _instance, + event_t _event, bool _is_provided); + + virtual std::shared_ptr<event> get_event(service_t _service, + instance_t _instance, event_t _event) const; + + virtual std::set<std::shared_ptr<event>> find_events(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const; + + virtual void subscribe(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + major_version_t _major, + subscription_type_e _subscription_type); + + virtual void unsubscribe(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + virtual void notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload); + + virtual void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, client_t _client); + + 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 _initial) = 0; + + virtual bool queue_message(const byte_t *_data, uint32_t _size) const = 0; + + // Endpoint host ~> will be implemented by routing_manager_impl/_proxy/ + virtual void on_connect(std::shared_ptr<endpoint> _endpoint) = 0; + virtual void on_disconnect(std::shared_ptr<endpoint> _endpoint) = 0; + virtual void on_message(const byte_t *_data, length_t _length, + endpoint *_receiver, const boost::asio::ip::address &_destination + = boost::asio::ip::address()) = 0; + virtual void on_error(const byte_t *_data, length_t _length, + endpoint *_receiver) = 0; + +protected: + std::shared_ptr<serviceinfo> find_service(service_t _service, instance_t _instance) const; + std::shared_ptr<serviceinfo> create_service_info(service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor, ttl_t _ttl, bool _is_local_service); + + void clear_service_info(service_t _service, instance_t _instance, bool _reliable); + services_t get_services() const; + bool is_available(service_t _service, instance_t _instance, major_version_t _major); + client_t find_local_client(service_t _service, instance_t _instance); + + std::shared_ptr<endpoint> create_local(client_t _client); + std::shared_ptr<endpoint> find_or_create_local(client_t _client); + void remove_local(client_t _client); + std::shared_ptr<endpoint> find_local(client_t _client); + std::shared_ptr<endpoint> find_local(service_t _service, + instance_t _instance); + + std::unordered_set<client_t> get_connected_clients(); + + std::shared_ptr<event> find_event(service_t _service, instance_t _instance, + event_t _event) const; + std::shared_ptr<eventgroupinfo> find_eventgroup(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const; + + std::set<client_t> find_local_clients(service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + void remove_eventgroup_info(service_t _service, instance_t _instance, + eventgroup_t _eventgroup); + + void send_local_notification(client_t _client, + const byte_t *_data, uint32_t _size, instance_t _instance, + bool _flush = true, bool _reliable = false, bool _inital = false); + + bool send_local( + std::shared_ptr<endpoint> &_target, client_t _client, + const byte_t *_data, uint32_t _size, instance_t _instance, + bool _flush, bool _reliable, uint8_t _command, bool _queue_message = false, + bool _initial = false) const; + + bool insert_subscription(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, client_t _client); + + routing_manager_host *host_; + boost::asio::io_service &io_; + client_t client_; + + std::shared_ptr<configuration> configuration_; + std::shared_ptr<serializer> serializer_; + std::shared_ptr<deserializer> deserializer_; + + std::mutex serialize_mutex_; + + 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_; + + // Eventgroups + mutable std::mutex eventgroups_mutex_; + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, std::shared_ptr<eventgroupinfo> > > > eventgroups_; + mutable std::mutex events_mutex_; + std::map<service_t, + std::map<instance_t, std::map<event_t, std::shared_ptr<event> > > > events_; + std::mutex eventgroup_clients_mutex_; + std::map<service_t, + std::map<instance_t, std::map<eventgroup_t, std::set<client_t> > > > eventgroup_clients_; + +#ifdef USE_DLT + std::shared_ptr<tc::trace_connector> tc_; +#endif + +private: + services_t services_; + mutable std::mutex services_mutex_; + + std::map<client_t, std::shared_ptr<endpoint> > local_endpoints_; + mutable std::mutex local_endpoint_mutex_; +}; + +} // namespace vsomeip + +#endif //VSOMEIP_ROUTING_MANAGER_BASE diff --git a/implementation/routing/include/routing_manager_host.hpp b/implementation/routing/include/routing_manager_host.hpp index 7b96be0..3a60d8c 100644 --- a/implementation/routing/include/routing_manager_host.hpp +++ b/implementation/routing/include/routing_manager_host.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -28,12 +28,14 @@ public: virtual boost::asio::io_service & get_io() = 0; virtual void on_availability(service_t _service, instance_t _instance, - bool _is_available) const = 0; + bool _is_available, major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR) = 0; virtual void on_state(state_type_e _state) = 0; virtual void on_message(std::shared_ptr<message> _message) = 0; virtual void on_error(error_code_e _error) = 0; virtual bool on_subscription(service_t _service, instance_t _instance, eventgroup_t _eventgroup, client_t _client, bool _subscribed) = 0; + virtual void on_subscription_error(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, uint16_t _error) = 0; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_impl.hpp b/implementation/routing/include/routing_manager_impl.hpp index 9741f3e..13936a4 100644 --- a/implementation/routing/include/routing_manager_impl.hpp +++ b/implementation/routing/include/routing_manager_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -10,16 +10,17 @@ #include <memory> #include <mutex> #include <vector> +#include <list> #include <unordered_set> #include <boost/asio/ip/address.hpp> #include <boost/asio/io_service.hpp> #include <vsomeip/primitive_types.hpp> +#include <vsomeip/handler.hpp> -#include "routing_manager.hpp" +#include "routing_manager_base.hpp" #include "routing_manager_stub_host.hpp" -#include "../../endpoints/include/endpoint_host.hpp" #include "../../service_discovery/include/service_discovery_host.hpp" namespace vsomeip { @@ -31,24 +32,20 @@ class eventgroupinfo; class routing_manager_host; class routing_manager_stub; class servicegroup; -class serviceinfo; class serializer; class service_endpoint; namespace sd { - class service_discovery; +} // namespace sd -} // namespace sd // TODO: encapsulate common parts of classes "routing_manager_impl" // and "routing_manager_proxy" into a base class. -class routing_manager_impl: public routing_manager, - public endpoint_host, +class routing_manager_impl: public routing_manager_base, public routing_manager_stub_host, - public sd::service_discovery_host, - public std::enable_shared_from_this<routing_manager_impl> { + public sd::service_discovery_host { public: routing_manager_impl(routing_manager_host *_host); ~routing_manager_impl(); @@ -66,7 +63,7 @@ public: minor_version_t _minor); void stop_offer_service(client_t _client, service_t _service, - instance_t _instance); + instance_t _instance, major_version_t _major, minor_version_t _minor); void request_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, @@ -85,7 +82,7 @@ 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); + instance_t _instance, bool _flush, bool _reliable, bool _initial = false); bool send_to(const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message> _message); @@ -93,12 +90,15 @@ public: bool send_to(const std::shared_ptr<endpoint_definition> &_target, const byte_t *_data, uint32_t _size); - void register_event(client_t _client, service_t _service, + bool send_to(const std::shared_ptr<endpoint_definition> &_target, + const byte_t *_data, uint32_t _size, uint16_t _sd_port); + + void register_shadow_event(client_t _client, service_t _service, instance_t _instance, event_t _event, const std::set<eventgroup_t> &_eventgroups, bool _is_field, bool _is_provided); - void unregister_event(client_t _client, service_t _service, + void unregister_shadow_event(client_t _client, service_t _service, instance_t _instance, event_t _event, bool _is_provided); @@ -108,14 +108,23 @@ public: void notify_one(service_t _service, instance_t _instance, event_t _event, std::shared_ptr<payload> _payload, client_t _client); + void on_subscribe_nack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + void on_subscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + void on_identify_response(client_t _client, service_t _service, instance_t _instance, + bool _reliable); + + bool queue_message(const byte_t *_data, uint32_t _size) const; + // interface to stub - std::shared_ptr<endpoint> create_local(client_t _client); std::shared_ptr<endpoint> find_local(client_t _client); std::shared_ptr<endpoint> find_or_create_local(client_t _client); void remove_local(client_t _client); - std::shared_ptr<endpoint> find_local(service_t _service, - instance_t _instance); - void on_stop_offer_service(service_t _service, instance_t _instance); + void on_stop_offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); // interface "endpoint_host" std::shared_ptr<endpoint> find_or_create_remote_client(service_t _service, @@ -124,11 +133,14 @@ public: void on_connect(std::shared_ptr<endpoint> _endpoint); void on_disconnect(std::shared_ptr<endpoint> _endpoint); void on_error(const byte_t *_data, length_t _length, endpoint *_receiver); - void on_message(const byte_t *_data, length_t _length, endpoint *_receiver); + void on_message(const byte_t *_data, length_t _length, endpoint *_receiver, + const boost::asio::ip::address &_destination); void on_message(service_t _service, instance_t _instance, const byte_t *_data, length_t _size, bool _reliable); void on_notification(client_t _client, service_t _service, - instance_t _instance, const byte_t *_data, length_t _size); + instance_t _instance, const byte_t *_data, length_t _size, + bool _notify_one); + void release_port(uint16_t _port, bool _reliable); // interface "service_discovery_host" typedef std::map<std::string, std::shared_ptr<servicegroup> > servicegroups_t; @@ -147,12 +159,17 @@ public: uint16_t _unreliable_port); void del_routing_info(service_t _service, instance_t _instance, bool _has_reliable, bool _has_unreliable); - ttl_t update_routing_info(ttl_t _elapsed); + std::chrono::milliseconds update_routing_info(std::chrono::milliseconds _elapsed); void on_subscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, std::shared_ptr<endpoint_definition> _subscriber, - std::shared_ptr<endpoint_definition> _target); + std::shared_ptr<endpoint_definition> _target, + const std::chrono::high_resolution_clock::time_point &_expiration); + bool on_subscribe_accepted(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, + std::shared_ptr<endpoint_definition> _target, + const std::chrono::high_resolution_clock::time_point &_expiration); void on_unsubscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, std::shared_ptr<endpoint_definition> _target); @@ -162,45 +179,34 @@ public: void expire_subscriptions(const boost::asio::ip::address &_address); void expire_services(const boost::asio::ip::address &_address); + std::chrono::high_resolution_clock::time_point expire_subscriptions(); + + bool has_identified(client_t _client, service_t _service, + instance_t _instance, bool _reliable); + private: bool deliver_message(const byte_t *_data, length_t _length, instance_t _instance, bool _reliable); bool deliver_notification(service_t _service, instance_t _instance, const byte_t *_data, length_t _length, bool _reliable); - bool send_local( - std::shared_ptr<endpoint> &_target, client_t _client, - const byte_t *_data, uint32_t _size, instance_t _instance, - bool _flush, bool _reliable) const; - - client_t find_local_client(service_t _service, instance_t _instance); - std::set<client_t> find_local_clients(service_t _service, - instance_t _instance, eventgroup_t _eventgroup); + instance_t find_instance(service_t _service, endpoint *_endpoint); - std::shared_ptr<serviceinfo> find_service(service_t _service, - instance_t _instance) const; - std::shared_ptr<serviceinfo> create_service_info(service_t _service, - instance_t _instance, major_version_t _major, - minor_version_t _minor, ttl_t _ttl, bool _is_local_service); + void init_service_info(service_t _service, + instance_t _instance, bool _is_local_service); std::shared_ptr<endpoint> create_client_endpoint( - const boost::asio::ip::address &_address, uint16_t _port, + const boost::asio::ip::address &_address, + uint16_t _local_port, uint16_t _remote_port, bool _reliable, client_t _client, bool _start); - void remove_eventgroup_info(service_t _service, instance_t _instance, - eventgroup_t _eventgroup); - std::shared_ptr<endpoint> create_server_endpoint(uint16_t _port, bool _reliable, bool _start); std::shared_ptr<endpoint> find_server_endpoint(uint16_t _port, - bool _reliable); + bool _reliable) const; std::shared_ptr<endpoint> find_or_create_server_endpoint(uint16_t _port, bool _reliable, bool _start); - std::set<std::shared_ptr<event> > find_events(service_t _service, - instance_t _instance, eventgroup_t _eventgroup); - std::shared_ptr<event> find_event(service_t _service, instance_t _instance, - event_t _event) const; bool is_field(service_t _service, instance_t _instance, event_t _event) const; @@ -216,19 +222,8 @@ private: void clear_client_endpoints(service_t _service, instance_t _instance, bool _reliable); void stop_and_delete_client_endpoint(std::shared_ptr<endpoint> _endpoint); void clear_multicast_endpoints(service_t _service, instance_t _instance); - void clear_service_info(service_t _service, instance_t _instance, bool _reliable); private: - void send_subscribe(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major); - - void send_unsubscribe(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup); - - bool insert_subscription(service_t _service, instance_t _instance, - eventgroup_t _eventgroup, client_t _client); - return_code_e check_error(const byte_t *_data, length_t _size, instance_t _instance); @@ -236,23 +231,22 @@ private: length_t _size, instance_t _instance, bool _reliable, endpoint *_receiver); - routing_manager_host *host_; - boost::asio::io_service &io_; + void identify_for_subscribe(client_t _client, service_t _service, + instance_t _instance, major_version_t _major); - std::shared_ptr<deserializer> deserializer_; - std::shared_ptr<serializer> serializer_; + bool supports_selective(service_t _service, instance_t _instance); - std::shared_ptr<configuration> configuration_; + client_t find_client(service_t _service, instance_t _instance, + const std::shared_ptr<eventgroupinfo> &_eventgroup, + const std::shared_ptr<endpoint_definition> &_target) const; + + void clear_remote_subscriber(service_t _service, instance_t _instance, + client_t _client, + const std::shared_ptr<endpoint_definition> &_target); std::shared_ptr<routing_manager_stub> stub_; std::shared_ptr<sd::service_discovery> discovery_; - // Routing info - - // Local - std::map<client_t, std::shared_ptr<endpoint> > local_clients_; - std::map<service_t, std::map<instance_t, client_t> > local_services_; - // Server endpoints for local services std::map<uint16_t, std::map<bool, std::shared_ptr<endpoint> > > server_endpoints_; std::map<service_t, std::map<endpoint *, instance_t> > service_instances_; @@ -268,29 +262,27 @@ private: std::map<instance_t, std::map<client_t, std::map<bool, std::shared_ptr<endpoint> > > > >remote_services_; std::map<boost::asio::ip::address, std::map<uint16_t, std::map<bool, std::shared_ptr<endpoint> > > > client_endpoints_by_ip_; - - // Services - services_t services_; - - // Eventgroups - std::map<service_t, - std::map<instance_t, - std::map<eventgroup_t, std::shared_ptr<eventgroupinfo> > > > eventgroups_; - std::map<service_t, - std::map<instance_t, std::map<event_t, std::shared_ptr<event> > > > events_; - std::map<service_t, - std::map<instance_t, std::map<eventgroup_t, std::set<client_t> > > > eventgroup_clients_; + std::map<client_t, + std::map<service_t, + std::map<instance_t, + std::set<std::pair<major_version_t, minor_version_t>>>>> requested_services_; // Mutexes mutable std::recursive_mutex endpoint_mutex_; - mutable std::mutex local_mutex_; - std::mutex serialize_mutex_; - mutable std::mutex services_mutex_; - mutable std::mutex eventgroups_mutex_; + std::mutex identified_clients_mutex_; + std::mutex requested_services_mutex_; + + std::map<service_t, std::map<instance_t, std::map<client_t, + std::set<std::shared_ptr<endpoint_definition>>>>> remote_subscribers_; + + std::mutex specific_endpoint_clients_mutex_; + std::map<service_t, std::map<instance_t, std::unordered_set<client_t>>>specific_endpoint_clients_; + std::map<service_t, std::map<instance_t, + std::map<bool, std::unordered_set<client_t> > > >identified_clients_; - std::map<client_t, std::shared_ptr<endpoint_definition>> remote_subscriber_map_; + std::shared_ptr<serviceinfo> sd_info_; - std::unordered_set<client_t> specific_endpoint_clients; + std::map<bool, std::set<uint16_t>> used_client_ports_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_proxy.hpp index 0577597..d2f61d7 100644 --- a/implementation/routing/include/routing_manager_proxy.hpp +++ b/implementation/routing/include/routing_manager_proxy.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -11,9 +11,9 @@ #include <boost/asio/io_service.hpp> -#include "routing_manager.hpp" -#include "../../endpoints/include/endpoint_host.hpp" +#include "routing_manager_base.hpp" #include <vsomeip/enumeration_types.hpp> +#include <vsomeip/handler.hpp> namespace vsomeip { @@ -21,19 +21,11 @@ class configuration; class event; class routing_manager_host; -// TODO: encapsulate common parts of classes "routing_manager_impl" -// and "routing_manager_proxy" into a base class. - -class routing_manager_proxy: public routing_manager, - public endpoint_host, - public std::enable_shared_from_this<routing_manager_proxy> { +class routing_manager_proxy: public routing_manager_base { public: routing_manager_proxy(routing_manager_host *_host); virtual ~routing_manager_proxy(); - boost::asio::io_service & get_io(); - client_t get_client() const; - void init(); void start(); void stop(); @@ -43,7 +35,7 @@ public: minor_version_t _minor); void stop_offer_service(client_t _client, service_t _service, - instance_t _instance); + instance_t _instance, major_version_t _major, minor_version_t _minor); void request_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, @@ -59,10 +51,9 @@ public: void unsubscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup); - 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 = true, bool _reliable = false); + instance_t _instance, bool _flush = true, bool _reliable = false, + bool _initial = false); bool send_to(const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message> _message); @@ -73,7 +64,7 @@ public: void register_event(client_t _client, service_t _service, instance_t _instance, event_t _event, const std::set<eventgroup_t> &_eventgroups, - bool _is_field, bool _is_provided); + bool _is_field, bool _is_provided, bool _is_shadow, bool _is_cache_placeholder); void unregister_event(client_t _client, service_t _service, instance_t _instance, event_t _event, @@ -82,29 +73,24 @@ public: void notify(service_t _service, instance_t _instance, event_t _event, std::shared_ptr<payload> _payload); - void notify_one(service_t _service, instance_t _instance, - event_t _event, std::shared_ptr<payload> _payload, - client_t _client); - 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 _length, endpoint *_receiver, + const boost::asio::ip::address &_destination); void on_error(const byte_t *_data, length_t _length, endpoint *_receiver); + void release_port(uint16_t _port, bool _reliable); void on_routing_info(const byte_t *_data, uint32_t _size); - std::shared_ptr<endpoint> find_local(client_t _client); - std::shared_ptr<endpoint> find_local(service_t _service, - instance_t _instance); - std::shared_ptr<endpoint> find_or_create_local(client_t _client); - void remove_local(client_t _client); + void on_identify_response(client_t _client, service_t _service, instance_t _instance, + bool _reliable); + + bool queue_message(const byte_t *_data, uint32_t _size) const; private: void register_application(); void deregister_application(); - std::shared_ptr<endpoint> create_local(client_t _client); - void send_pong() const; void send_offer_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, @@ -112,6 +98,8 @@ private: void send_request_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, bool _use_exclusive_proxy); + void send_release_service(client_t _client, service_t _service, + instance_t _instance); void send_register_event(client_t _client, service_t _service, instance_t _instance, event_t _event, const std::set<eventgroup_t> &_eventgroup, @@ -120,29 +108,38 @@ private: instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, subscription_type_e _subscription_type); + void send_subscribe_nack(client_t _subscriber, service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + void send_subscribe_ack(client_t _subscriber, service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + bool is_field(service_t _service, instance_t _instance, event_t _event) const; + void on_subscribe_nack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + void on_subscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + void send_pending_subscriptions(service_t _service, instance_t _instance, + major_version_t _major); + + void cache_event_payload(const std::shared_ptr<message> &_message); + + void on_stop_offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + private: - boost::asio::io_service &io_; bool is_connected_; bool is_started_; state_type_e state_; - routing_manager_host *host_; - client_t client_; // store locally as it is needed in each message - - std::shared_ptr<configuration> configuration_; - - std::shared_ptr<serializer> serializer_; - std::shared_ptr<deserializer> deserializer_; std::shared_ptr<endpoint> sender_; // --> stub std::shared_ptr<endpoint> receiver_; // --> from everybody - std::map<client_t, std::shared_ptr<endpoint> > local_endpoints_; - std::map<service_t, std::map<instance_t, client_t> > local_services_; - std::map<service_t, std::map<instance_t, major_version_t> > service_versions_; - std::mutex local_services_mutex_; + std::unordered_set<client_t> known_clients_; struct service_data_t { service_t service_; @@ -196,6 +193,7 @@ private: } }; std::set<eventgroup_data_t> pending_subscriptions_; + std::map<client_t, std::set<eventgroup_data_t>> pending_ingoing_subscripitons_; std::map<service_t, std::map<instance_t, @@ -203,11 +201,8 @@ private: std::shared_ptr<message> > > > pending_notifications_; std::mutex send_mutex_; - std::mutex serialize_mutex_; std::mutex deserialize_mutex_; std::mutex pending_mutex_; - - std::map<service_t, std::map<instance_t, std::set<event_t> > > fields_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_stub.hpp b/implementation/routing/include/routing_manager_stub.hpp index 6a1ec38..27b8ec5 100644 --- a/implementation/routing/include/routing_manager_stub.hpp +++ b/implementation/routing/include/routing_manager_stub.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -6,11 +6,13 @@ #ifndef VSOMEIP_ROUTING_MANAGER_STUB #define VSOMEIP_ROUTING_MANAGER_STUB +#include <condition_variable> #include <list> #include <map> #include <memory> #include <mutex> #include <set> +#include <thread> #include <boost/asio/io_service.hpp> #include <boost/asio/system_timer.hpp> @@ -36,13 +38,32 @@ 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 _length, endpoint *_receiver, + const boost::asio::ip::address &_destination); void on_error(const byte_t *_data, length_t _length, endpoint *_receiver); + void release_port(uint16_t _port, bool _reliable); void on_offer_service(client_t _client, service_t _service, - instance_t _instance); + instance_t _instance, major_version_t _major, minor_version_t _minor); void on_stop_offer_service(client_t _client, service_t _service, - instance_t _instance); + instance_t _instance, major_version_t _major, minor_version_t _minor); + + bool queue_message(const byte_t *_data, uint32_t _size); + + void send_subscribe(std::shared_ptr<vsomeip::endpoint> _target, + client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + major_version_t _major, bool _is_remote_subscriber); + + void send_unsubscribe(std::shared_ptr<vsomeip::endpoint> _target, + client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + void send_subscribe_nack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + void send_subscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup); private: void broadcast(std::vector<byte_t> &_command) const; @@ -50,8 +71,8 @@ private: void on_register_application(client_t _client); void on_deregister_application(client_t _client); - void broadcast_routing_info(); - void send_routing_info(client_t _client); + void broadcast_routing_info(bool _empty = false); + void send_routing_info(client_t _client, bool _empty = false); void broadcast_ping() const; void on_pong(client_t _client); @@ -59,18 +80,30 @@ private: void check_watchdog(); void send_application_lost(std::list<client_t> &_lost); + void client_registration_func(void); + private: routing_manager_stub_host *host_; boost::asio::io_service &io_; boost::asio::system_timer watchdog_timer_; std::string endpoint_path_; + std::string local_receiver_path_; std::shared_ptr<endpoint> endpoint_; + std::shared_ptr<endpoint> local_receiver_; std::map<client_t, - std::pair<uint8_t, std::map<service_t, std::set<instance_t> > > > routing_info_; + std::pair<uint8_t, std::map<service_t, std::map<instance_t, std::pair<major_version_t, minor_version_t>> > > > routing_info_; mutable std::mutex routing_info_mutex_; std::shared_ptr<configuration> configuration_; + + size_t routingCommandSize_; + + bool client_registration_running_; + std::shared_ptr<std::thread> client_registration_thread_; + std::mutex client_registration_mutex_; + std::condition_variable client_registration_condition_; + std::map<client_t, std::vector<bool>> pending_client_registrations_; }; } // namespace vsomeip diff --git a/implementation/routing/include/routing_manager_stub_host.hpp b/implementation/routing/include/routing_manager_stub_host.hpp index d56f2d3..e216b5a 100644 --- a/implementation/routing/include/routing_manager_stub_host.hpp +++ b/implementation/routing/include/routing_manager_stub_host.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -7,6 +7,7 @@ #define VSOMEIP_ROUTING_MANAGER_STUB_HOST #include <boost/asio/io_service.hpp> +#include <vsomeip/handler.hpp> namespace vsomeip { @@ -20,7 +21,7 @@ public: minor_version_t _minor) = 0; virtual void stop_offer_service(client_t _client, service_t _service, - instance_t _instance) = 0; + instance_t _instance, major_version_t _major, minor_version_t _minor) = 0; virtual void request_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, @@ -29,17 +30,24 @@ public: virtual void release_service(client_t _client, service_t _service, instance_t _instance) = 0; - virtual void register_event(client_t _client, service_t _service, + virtual void register_shadow_event(client_t _client, service_t _service, instance_t _instance, event_t _event, const std::set<eventgroup_t> &_eventgroups, bool _is_field, bool _is_provided) = 0; - virtual void unregister_event(client_t _client, service_t _service, + virtual void unregister_shadow_event(client_t _client, service_t _service, instance_t _instance, event_t _event, bool _is_provided) = 0; virtual void subscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, subscription_type_e _subscription_type) = 0; + major_version_t _major, + subscription_type_e _subscription_type) = 0; + + virtual void on_subscribe_nack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup) = 0; + + virtual void on_subscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup) = 0; virtual void unsubscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup) = 0; @@ -49,20 +57,23 @@ public: virtual void on_notification(client_t _client, service_t _service, instance_t _instance, - const byte_t *_data, length_t _size) = 0; + const byte_t *_data, length_t _size, bool _notify_one = false) = 0; virtual void on_stop_offer_service(service_t _service, - instance_t _instance) = 0; + instance_t _instance, major_version_t _major, + minor_version_t _minor) = 0; virtual std::shared_ptr<endpoint> find_local(client_t _client) = 0; - virtual std::shared_ptr<endpoint> find_local(service_t _service, - instance_t _instance) = 0; + virtual std::shared_ptr<endpoint> find_or_create_local( client_t _client) = 0; virtual void remove_local(client_t _client) = 0; virtual boost::asio::io_service & get_io() = 0; virtual client_t get_client() const = 0; + + virtual void on_identify_response(client_t _client, service_t _service, instance_t _instance, + bool _reliable) = 0; }; } // namespace vsomeip diff --git a/implementation/routing/include/serviceinfo.hpp b/implementation/routing/include/serviceinfo.hpp index af3a50c..44050b8 100644 --- a/implementation/routing/include/serviceinfo.hpp +++ b/implementation/routing/include/serviceinfo.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -9,6 +9,7 @@ #include <memory> #include <set> #include <string> +#include <chrono> #include <vsomeip/export.hpp> #include <vsomeip/primitive_types.hpp> @@ -33,21 +34,16 @@ public: VSOMEIP_EXPORT ttl_t get_ttl() const; VSOMEIP_EXPORT void set_ttl(ttl_t _ttl); + VSOMEIP_EXPORT std::chrono::milliseconds get_precise_ttl() const; + VSOMEIP_EXPORT void set_precise_ttl(std::chrono::milliseconds _ttl); + VSOMEIP_EXPORT std::shared_ptr<endpoint> get_endpoint(bool _reliable) const; VSOMEIP_EXPORT void set_endpoint(std::shared_ptr<endpoint> _endpoint, bool _reliable); - VSOMEIP_EXPORT const std::string & get_multicast_address() const; - VSOMEIP_EXPORT void set_multicast_address(const std::string &_multicast); - - VSOMEIP_EXPORT uint16_t get_multicast_port() const; - VSOMEIP_EXPORT void set_multicast_port(uint16_t _port); - - VSOMEIP_EXPORT eventgroup_t get_multicast_group() const; - VSOMEIP_EXPORT void set_multicast_group(eventgroup_t _multicast_group); - VSOMEIP_EXPORT void add_client(client_t _client); VSOMEIP_EXPORT void remove_client(client_t _client); + VSOMEIP_EXPORT uint32_t get_requesters_size(); VSOMEIP_EXPORT bool is_local() const; @@ -56,15 +52,11 @@ private: major_version_t major_; minor_version_t minor_; - ttl_t ttl_; + std::chrono::milliseconds ttl_; std::shared_ptr<endpoint> reliable_; std::shared_ptr<endpoint> unreliable_; - std::string multicast_address_; - uint16_t multicast_port_; - eventgroup_t multicast_group_; - std::set<client_t> requesters_; bool is_local_; diff --git a/implementation/routing/include/types.hpp b/implementation/routing/include/types.hpp index 60b97bc..c483aee 100644 --- a/implementation/routing/include/types.hpp +++ b/implementation/routing/include/types.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/routing/src/event.cpp b/implementation/routing/src/event.cpp index b553415..d536597 100644 --- a/implementation/routing/src/event.cpp +++ b/implementation/routing/src/event.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -16,13 +16,16 @@ namespace vsomeip { -event::event(routing_manager *_routing) : +event::event(routing_manager *_routing, bool _is_shadow) : routing_(_routing), message_(runtime::get()->create_notification()), + is_field_(false), cycle_timer_(_routing->get_io()), is_updating_on_change_(true), is_set_(false), - ref_(0) { + is_provided_(false), + is_shadow_(_is_shadow), + is_cache_placeholder_(false) { } service_t event::get_service() const { @@ -73,10 +76,31 @@ void event::set_provided(bool _is_provided) { is_provided_ = _is_provided; } +bool event::is_set() const { + return is_set_; +} + const std::shared_ptr<payload> event::get_payload() const { return (message_->get_payload()); } +void event::set_payload_dont_notify(std::shared_ptr<payload> _payload) { + if(is_cache_placeholder_) { + std::shared_ptr<payload> its_new_payload + = runtime::get()->create_payload( + _payload->get_data(), _payload->get_length()); + message_->set_payload(its_new_payload); + is_set_ = true; + } else { + if (set_payload_helper(_payload)) { + std::shared_ptr<payload> its_new_payload + = runtime::get()->create_payload( + _payload->get_data(), _payload->get_length()); + message_->set_payload(its_new_payload); + } + } +} + void event::set_payload(std::shared_ptr<payload> _payload) { if (is_provided_) { if (set_payload_helper(_payload)) { @@ -89,6 +113,9 @@ void event::set_payload(std::shared_ptr<payload> _payload) { notify(); } } + } else { + VSOMEIP_DEBUG << "Can't set payload for event " << std::hex + << message_->get_method() << " as it isn't provided"; } } @@ -103,6 +130,9 @@ void event::set_payload(std::shared_ptr<payload> _payload, client_t _client) { if (is_updating_on_change_) { notify_one(_client); } + } else { + VSOMEIP_DEBUG << "Can't set payload for event " << std::hex + << message_->get_method() << " as it isn't provided"; } } @@ -119,13 +149,21 @@ void event::set_payload(std::shared_ptr<payload> _payload, notify_one(_target); } } + } else { + VSOMEIP_DEBUG << "Can't set payload for event " << std::hex + << message_->get_method() << " as it isn't provided"; } } -void event::unset_payload() { - if (is_provided_) { +void event::unset_payload(bool _force) { + if(_force) { is_set_ = false; message_->set_payload(std::make_shared<payload_impl>()); + } else { + if (is_provided_) { + is_set_ = false; + message_->set_payload(std::make_shared<payload_impl>()); + } } } @@ -177,17 +215,35 @@ void event::update_cbk(boost::system::error_code const &_error) { void event::notify() { if (is_set_) { routing_->send(VSOMEIP_ROUTING_CLIENT, message_, true); + } else { + VSOMEIP_DEBUG << "Notify event " << std::hex << message_->get_method() + << "failed. Event payload not set!"; } } void event::notify_one(const std::shared_ptr<endpoint_definition> &_target) { - if (is_set_) + if (is_set_) { routing_->send_to(_target, message_); + } else { + VSOMEIP_DEBUG << "Notify one event " << std::hex << message_->get_method() + << "failed. Event payload not set!"; + } } -void event::notify_one(client_t _client) { - if (is_set_) +void event::notify_one(client_t _client, bool _is_initial) { + if (is_set_) { + const bool old_initial_value(message_->is_initial()); + if(_is_initial) { + message_->set_initial(true); + } routing_->send(_client, message_, true); + if(_is_initial) { + message_->set_initial(old_initial_value); + } + } else { + VSOMEIP_DEBUG << "Notify one event " << std::hex << message_->get_method() + << " to client " << _client << " failed. Event payload not set!"; + } } bool event::set_payload_helper(std::shared_ptr<payload> _payload) { @@ -210,13 +266,54 @@ bool event::set_payload_helper(std::shared_ptr<payload> _payload) { return is_change; } -void event::add_ref() { - ref_++; +void event::add_ref(client_t _client, bool _is_provided) { + auto its_client = refs_.find(_client); + if (its_client == refs_.end()) { + refs_[_client][_is_provided] = 1; + } else { + auto its_provided = its_client->second.find(_is_provided); + if (its_provided == its_client->second.end()) { + refs_[_client][_is_provided] = 1; + } else { + its_provided->second++; + } + } +} + +void event::remove_ref(client_t _client, bool _is_provided) { + auto its_client = refs_.find(_client); + if (its_client != refs_.end()) { + auto its_provided = its_client->second.find(_is_provided); + if (its_provided != its_client->second.end()) { + its_provided->second--; + if (0 == its_provided->second) { + its_client->second.erase(_is_provided); + if (0 == its_client->second.size()) { + refs_.erase(_client); + } + } + } + } +} + +bool event::has_ref() { + return refs_.size() != 0; +} + +bool event::is_shadow() const { + return is_shadow_; +} + +void event::set_shadow(bool _shadow) { + is_shadow_ = _shadow; +} + +bool event::is_cache_placeholder() const { + return is_cache_placeholder_; } -uint32_t event::remove_ref() { - ref_--; - return ref_; +void event::set_cache_placeholder(bool _is_cache_place_holder) { + is_cache_placeholder_ = _is_cache_place_holder; } } // namespace vsomeip diff --git a/implementation/routing/src/eventgroupinfo.cpp b/implementation/routing/src/eventgroupinfo.cpp index 0d098e4..1380969 100644 --- a/implementation/routing/src/eventgroupinfo.cpp +++ b/implementation/routing/src/eventgroupinfo.cpp @@ -1,20 +1,24 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include <algorithm> + #include <vsomeip/constants.hpp> + #include "../include/eventgroupinfo.hpp" +#include "../../endpoints/include/endpoint_definition.hpp" namespace vsomeip { eventgroupinfo::eventgroupinfo() - : major_(DEFAULT_MAJOR), ttl_(DEFAULT_TTL), is_multicast_(false) { + : major_(DEFAULT_MAJOR), ttl_(DEFAULT_TTL) { } eventgroupinfo::eventgroupinfo(major_version_t _major, ttl_t _ttl) - : major_(_major), ttl_(_ttl), is_multicast_(false) { + : major_(_major), ttl_(_ttl) { } eventgroupinfo::~eventgroupinfo() { @@ -37,23 +41,24 @@ void eventgroupinfo::set_ttl(ttl_t _ttl) { } bool eventgroupinfo::is_multicast() const { - return is_multicast_; + return address_.is_multicast(); } bool eventgroupinfo::get_multicast(boost::asio::ip::address &_address, uint16_t &_port) const { - if (is_multicast_) { + + if (address_.is_multicast()) { _address = address_; _port = port_; + return true; } - return is_multicast_; + return false; } void eventgroupinfo::set_multicast(const boost::asio::ip::address &_address, uint16_t _port) { address_ = _address; port_ = _port; - is_multicast_ = true; } const std::set<std::shared_ptr<event> > eventgroupinfo::get_events() const { @@ -68,20 +73,77 @@ void eventgroupinfo::remove_event(std::shared_ptr<event> _event) { events_.erase(_event); } -const std::set<std::shared_ptr<endpoint_definition> > eventgroupinfo::get_targets() const { +const std::list<eventgroupinfo::target_t> eventgroupinfo::get_targets() const { return targets_; } -bool eventgroupinfo::add_target(std::shared_ptr<endpoint_definition> _target) { +uint32_t eventgroupinfo::get_unreliable_target_count(){ + uint32_t _count(0); + for (auto i = targets_.begin(); i != targets_.end(); i++) { + if (!i->endpoint_->is_reliable()) { + _count++; + } + } + return _count; +} + +void eventgroupinfo::add_multicast_target(const eventgroupinfo::target_t &_multicast_target) { + if (std::find(multicast_targets_.begin(), multicast_targets_.end(), _multicast_target) + == multicast_targets_.end()) { + multicast_targets_.push_back(_multicast_target); + } +} + +void eventgroupinfo::clear_multicast_targets() { + multicast_targets_.clear(); +} + +const std::list<eventgroupinfo::target_t> eventgroupinfo::get_multicast_targets() const { + return multicast_targets_; +} + +bool eventgroupinfo::add_target(const eventgroupinfo::target_t &_target) { std::size_t its_size = targets_.size(); - targets_.insert(_target); + if (std::find(targets_.begin(), targets_.end(), _target) == targets_.end()) { + targets_.push_back(_target); + } + return (its_size != targets_.size()); +} + +bool eventgroupinfo::add_target(const eventgroupinfo::target_t &_target, const eventgroupinfo::target_t &_subscriber) { + std::size_t its_size = targets_.size(); + if (std::find(targets_.begin(), targets_.end(), _subscriber) == targets_.end()) { + targets_.push_back(_subscriber); + } + if (its_size != targets_.size()) { + add_multicast_target(_target); + } return (its_size != targets_.size()); } +bool eventgroupinfo::update_target( + const std::shared_ptr<endpoint_definition> &_target, + const std::chrono::high_resolution_clock::time_point &_expiration) { + for (auto i = targets_.begin(); i != targets_.end(); i++) { + if (i->endpoint_ == _target) { + i->expiration_ = _expiration; + return true; + } + } + return false; +} + bool eventgroupinfo::remove_target( - std::shared_ptr<endpoint_definition> _target) { + const std::shared_ptr<endpoint_definition> &_target) { std::size_t its_size = targets_.size(); - targets_.erase(_target); + + for (auto i = targets_.begin(); i != targets_.end(); i++) { + if (i->endpoint_ == _target) { + targets_.erase(i); + break; + } + } + return (its_size != targets_.size()); } diff --git a/implementation/routing/src/routing_manager_base.cpp b/implementation/routing/src/routing_manager_base.cpp new file mode 100644 index 0000000..1a04a20 --- /dev/null +++ b/implementation/routing/src/routing_manager_base.cpp @@ -0,0 +1,782 @@ +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "../../utility/include/utility.hpp" +#include "../../utility/include/byteorder.hpp" +#include "../include/routing_manager_base.hpp" +#include "../../logging/include/logger.hpp" +#include "../../endpoints/include/local_client_endpoint_impl.hpp" +#include "../../endpoints/include/local_server_endpoint_impl.hpp" + +namespace vsomeip { + +routing_manager_base::routing_manager_base(routing_manager_host *_host) : + host_(_host), + io_(host_->get_io()), + client_(host_->get_client()), + configuration_(host_->get_configuration()), + serializer_(std::make_shared<serializer>()), + deserializer_(std::make_shared<deserializer>()) +#ifdef USE_DLT + , tc_(tc::trace_connector::get()) +#endif +{ +} + +routing_manager_base::~routing_manager_base() { +} + +boost::asio::io_service & routing_manager_base::get_io() { + return (io_); +} + +client_t routing_manager_base::get_client() const { + return client_; +} + +void routing_manager_base::init() { + serializer_->create_data(configuration_->get_max_message_size_local()); +} + +void routing_manager_base::offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor) { + (void)_client; + + // Remote route (incoming only) + auto its_info = find_service(_service, _instance); + if (its_info) { + if (its_info->get_major() == _major + && its_info->get_minor() == _minor) { + its_info->set_ttl(DEFAULT_TTL); + } else { + host_->on_error(error_code_e::SERVICE_PROPERTY_MISMATCH); + } + } else { + its_info = create_service_info(_service, _instance, _major, _minor, + DEFAULT_TTL, true); + } +} + +void routing_manager_base::stop_offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor) { + (void)_client; + (void)_major; + (void)_minor; + { + std::lock_guard<std::mutex> its_lock(events_mutex_); + auto its_events_service = events_.find(_service); + if (its_events_service != events_.end()) { + auto its_events_instance = its_events_service->second.find(_instance); + if (its_events_instance != its_events_service->second.end()) { + for (auto &e : its_events_instance->second) + e.second->unset_payload(); + } + } + } + { + std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_); + auto its_service = eventgroup_clients_.find(_service); + if (its_service != eventgroup_clients_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + its_instance->second.clear(); + } + } + } +} + +void routing_manager_base::request_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor, bool _use_exclusive_proxy) { + (void)_use_exclusive_proxy; + + auto its_info = find_service(_service, _instance); + if (its_info) { + if ((_major == its_info->get_major() + || DEFAULT_MAJOR == its_info->get_major()) + && (_minor <= its_info->get_minor() + || DEFAULT_MINOR == its_info->get_minor() + || _minor == ANY_MINOR)) { + its_info->add_client(_client); + } else { + host_->on_error(error_code_e::SERVICE_PROPERTY_MISMATCH); + } + } +} + +void routing_manager_base::release_service(client_t _client, service_t _service, + instance_t _instance) { + auto its_info = find_service(_service, _instance); + if (its_info) { + its_info->remove_client(_client); + } +} + +void routing_manager_base::register_event(client_t _client, service_t _service, instance_t _instance, + event_t _event, const std::set<eventgroup_t> &_eventgroups, + bool _is_field, bool _is_provided, bool _is_shadow, + bool _is_cache_placeholder) { + std::shared_ptr<event> its_event = find_event(_service, _instance, _event); + if (its_event) { + if(!its_event->is_cache_placeholder()) { + if (its_event->is_field() == _is_field) { + if (_is_provided) { + its_event->set_provided(true); + } + if (_is_shadow && _is_provided) { + its_event->set_shadow(_is_shadow); + } + for (auto eg : _eventgroups) { + its_event->add_eventgroup(eg); + } + } else { + VSOMEIP_ERROR << "Event registration update failed. " + "Specified arguments do not match existing registration."; + } + } else { + // the found event was a placeholder for caching. + // update it with the real values + if(!_is_field) { + // don't cache payload for non-fields + its_event->unset_payload(true); + } + if (_is_shadow && _is_provided) { + its_event->set_shadow(_is_shadow); + } + its_event->set_field(_is_field); + its_event->set_provided(_is_provided); + its_event->set_cache_placeholder(false); + std::shared_ptr<serviceinfo> its_service = find_service(_service, _instance); + if (its_service) { + its_event->set_version(its_service->get_major()); + } + if (_eventgroups.size() == 0) { // No eventgroup specified + std::set<eventgroup_t> its_eventgroups; + its_eventgroups.insert(_event); + its_event->set_eventgroups(its_eventgroups); + } else { + its_event->set_eventgroups(_eventgroups); + } + + } + } else { + its_event = std::make_shared<event>(this, _is_shadow); + its_event->set_service(_service); + its_event->set_instance(_instance); + its_event->set_event(_event); + its_event->set_field(_is_field); + its_event->set_provided(_is_provided); + its_event->set_cache_placeholder(_is_cache_placeholder); + std::shared_ptr<serviceinfo> its_service = find_service(_service, _instance); + if (its_service) { + its_event->set_version(its_service->get_major()); + } + + if (_eventgroups.size() == 0) { // No eventgroup specified + std::set<eventgroup_t> its_eventgroups; + its_eventgroups.insert(_event); + its_event->set_eventgroups(its_eventgroups); + } else { + its_event->set_eventgroups(_eventgroups); + } + } + + if(!_is_cache_placeholder) { + its_event->add_ref(_client, _is_provided); + } + + for (auto eg : _eventgroups) { + std::shared_ptr<eventgroupinfo> its_eventgroup_info + = find_eventgroup(_service, _instance, eg); + if (!its_eventgroup_info) { + its_eventgroup_info = std::make_shared<eventgroupinfo>(); + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + eventgroups_[_service][_instance][eg] = its_eventgroup_info; + } + its_eventgroup_info->add_event(its_event); + } + + std::lock_guard<std::mutex> its_lock(events_mutex_); + events_[_service][_instance][_event] = its_event; +} + +void routing_manager_base::unregister_event(client_t _client, service_t _service, instance_t _instance, + event_t _event, bool _is_provided) { + (void)_client; + std::lock_guard<std::mutex> its_lock(events_mutex_); + auto found_service = events_.find(_service); + if (found_service != events_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_event = found_instance->second.find(_event); + if (found_event != found_instance->second.end()) { + auto its_event = found_event->second; + its_event->remove_ref(_client, _is_provided); + if (!its_event->has_ref()) { + auto its_eventgroups = its_event->get_eventgroups(); + for (auto eg : its_eventgroups) { + std::shared_ptr<eventgroupinfo> its_eventgroup_info + = find_eventgroup(_service, _instance, eg); + if (its_eventgroup_info) { + its_eventgroup_info->remove_event(its_event); + if (0 == its_eventgroup_info->get_events().size()) { + remove_eventgroup_info(_service, _instance, eg); + } + } + } + found_instance->second.erase(_event); + } else if (_is_provided) { + its_event->set_provided(false); + } + } + } + } +} + +std::shared_ptr<event> routing_manager_base::get_event( + service_t _service, instance_t _instance, event_t _event) const { + std::shared_ptr<event> its_event; + std::lock_guard<std::mutex> its_lock(events_mutex_); + auto found_service = events_.find(_service); + if (found_service != events_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_event = found_instance->second.find(_event); + if (found_event != found_instance->second.end()) { + return found_event->second; + } + } + } + return its_event; +} + + +std::set<std::shared_ptr<event>> routing_manager_base::find_events( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + std::set<std::shared_ptr<event> > its_events; + auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + return (found_eventgroup->second->get_events()); + } + } + } + return (its_events); +} + +void routing_manager_base::subscribe(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + major_version_t _major, + subscription_type_e _subscription_type) { + + (void) _major; + (void) _subscription_type; + + bool inserted = insert_subscription(_service, _instance, _eventgroup, _client); + if (inserted) { + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + std::set<std::shared_ptr<event> > its_events + = its_eventgroup->get_events(); + for (auto e : its_events) { + if (e->is_field()) + e->notify_one(_client); + } + } + } +} + +void routing_manager_base::unsubscribe(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup) { + std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_); + auto its_service = eventgroup_clients_.find(_service); + if (its_service != eventgroup_clients_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + auto its_group = its_instance->second.find(_eventgroup); + if (its_group != its_instance->second.end()) { + its_group->second.erase(_client); + } + } + } +} + +void routing_manager_base::notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload) { + std::shared_ptr<event> its_event = find_event(_service, _instance, _event); + if (its_event) { + its_event->set_payload(_payload); + } else { + VSOMEIP_WARNING << "Attempt to update the undefined event/field [" + << std::hex << _service << "." << _instance << "." << _event + << "]"; + } +} + +void routing_manager_base::notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, client_t _client) { + std::shared_ptr<event> its_event = find_event(_service, _instance, _event); + if (its_event) { + // Event is valid for service/instance + bool found_eventgroup(false); + // Iterate over all groups of the event to ensure at least + // one valid eventgroup for service/instance exists. + for (auto its_group : its_event->get_eventgroups()) { + auto its_eventgroup = find_eventgroup(_service, _instance, its_group); + if (its_eventgroup) { + // Eventgroup is valid for service/instance + found_eventgroup = true; + break; + } + } + if (found_eventgroup) { + its_event->set_payload(_payload, _client); + } + } else { + VSOMEIP_WARNING << "Attempt to update the undefined event/field [" + << std::hex << _service << "." << _instance << "." << _event + << "]"; + } +} + +bool routing_manager_base::send(client_t its_client, + std::shared_ptr<message> _message, + bool _flush) { + bool is_sent(false); + if (utility::is_request(_message->get_message_type())) { + _message->set_client(its_client); + } + std::lock_guard<std::mutex> its_lock(serialize_mutex_); + if (serializer_->serialize(_message.get())) { + is_sent = send(its_client, serializer_->get_data(), + serializer_->get_size(), _message->get_instance(), + _flush, _message->is_reliable(), _message->is_initial()); + serializer_->reset(); + } else { + VSOMEIP_ERROR << "Failed to serialize message. Check message size!"; + } + return (is_sent); +} + +// ********************************* PROTECTED ************************************** +std::shared_ptr<serviceinfo> routing_manager_base::create_service_info( + service_t _service, instance_t _instance, major_version_t _major, + minor_version_t _minor, ttl_t _ttl, bool _is_local_service) { + std::lock_guard<std::mutex> its_lock(services_mutex_); + std::shared_ptr<serviceinfo> its_info = + std::make_shared<serviceinfo>(_major, _minor, _ttl, _is_local_service); + services_[_service][_instance] = its_info; + return its_info; +} + +std::shared_ptr<serviceinfo> routing_manager_base::find_service( + service_t _service, instance_t _instance) const { + std::shared_ptr<serviceinfo> its_info; + 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()) { + its_info = found_instance->second; + } + } + return (its_info); +} + +void routing_manager_base::clear_service_info(service_t _service, instance_t _instance, + bool _reliable) { + std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); + if (!its_info) { + return; + } + // Clear service_info and service_group + std::shared_ptr<endpoint> its_empty_endpoint; + if (!its_info->get_endpoint(!_reliable)) { + if (1 >= services_[_service].size()) { + services_.erase(_service); + } else { + services_[_service].erase(_instance); + } + } else { + its_info->set_endpoint(its_empty_endpoint, _reliable); + } +} + +services_t routing_manager_base::get_services() const { + services_t its_offers; + std::lock_guard<std::mutex> its_lock(services_mutex_); + for (auto s : services_) { + for (auto i : s.second) { + its_offers[s.first][i.first] = i.second; + } + } + return (its_offers); +} + +bool routing_manager_base::is_available(service_t _service, instance_t _instance, + major_version_t _major) { + bool available(false); + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + auto its_service = local_services_.find(_service); + if (its_service != local_services_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + if (std::get<0>(its_instance->second) == _major) { + available = true; + } + } + } + return available; +} + +client_t routing_manager_base::find_local_client(service_t _service, instance_t _instance) { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + client_t its_client(VSOMEIP_ROUTING_CLIENT); + auto its_service = local_services_.find(_service); + if (its_service != local_services_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + its_client = std::get<2>(its_instance->second); + } + } + return its_client; +} + +std::shared_ptr<endpoint> routing_manager_base::create_local(client_t _client) { + std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_); + + std::stringstream its_path; + its_path << VSOMEIP_BASE_PATH << std::hex << _client; + +#ifdef WIN32 + boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); + int port = VSOMEIP_INTERNAL_BASE_PORT + _client; + VSOMEIP_DEBUG<< "Connecting to [" + << std::hex << _client << "] at " << port; +#else + VSOMEIP_DEBUG << "Client [" << std::hex << get_client() << "] is connecting to [" + << std::hex << _client << "] at " << its_path.str(); +#endif + std::shared_ptr<endpoint> its_endpoint = std::make_shared< + local_client_endpoint_impl>(shared_from_this(), +#ifdef WIN32 + boost::asio::ip::tcp::endpoint(address, port) +#else + boost::asio::local::stream_protocol::endpoint(its_path.str()) +#endif + , io_, configuration_->get_max_message_size_local()); + + if (_client != VSOMEIP_ROUTING_CLIENT) { + // VSOMEIP_ROUTING_CLIENT must not be added here. + // The routing master should not get an end-point when calling find_local + // with VSOMEIP_ROUTING_CLIENT as parameter + // as it indicates remote communication! + + local_endpoints_[_client] = its_endpoint; + } + + return (its_endpoint); +} + +std::shared_ptr<endpoint> routing_manager_base::find_local(client_t _client) { + std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_); + std::shared_ptr<endpoint> its_endpoint; + auto found_endpoint = local_endpoints_.find(_client); + if (found_endpoint != local_endpoints_.end()) { + its_endpoint = found_endpoint->second; + } + return (its_endpoint); +} + +std::shared_ptr<endpoint> routing_manager_base::find_or_create_local(client_t _client) { + std::shared_ptr<endpoint> its_endpoint(find_local(_client)); + if (!its_endpoint) { + its_endpoint = create_local(_client); + its_endpoint->start(); + } + return (its_endpoint); +} + +void routing_manager_base::remove_local(client_t _client) { + std::shared_ptr<endpoint> its_endpoint(find_local(_client)); + if (its_endpoint) { + its_endpoint->stop(); + VSOMEIP_DEBUG << "Client [" << std::hex << get_client() << "] is closing connection to [" + << std::hex << _client << "]"; + std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_); + local_endpoints_.erase(_client); + } + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + // Finally remove all services that are implemented by the client. + std::set<std::pair<service_t, instance_t>> its_services; + for (auto& s : local_services_) { + for (auto& i : s.second) { + if (std::get<2>(i.second) == _client) + its_services.insert({ s.first, i.first }); + } + } + + for (auto& si : its_services) { + local_services_[si.first].erase(si.second); + if (local_services_[si.first].size() == 0) + local_services_.erase(si.first); + } + } + // delete client's subscriptions if he didn't unsubscribe properly + { + std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_); + for (auto service_it = eventgroup_clients_.begin(); + service_it != eventgroup_clients_.end();) { + for (auto instance_it = service_it->second.begin(); + instance_it != service_it->second.end();) { + for (auto eventgroup_it = instance_it->second.begin(); + eventgroup_it != instance_it->second.end();) { + if (eventgroup_it->second.erase(_client) > 0) { + if (eventgroup_it->second.size() == 0) { + eventgroup_it = instance_it->second.erase(eventgroup_it); + } else { + ++eventgroup_it; + } + } else { + ++eventgroup_it; + } + } + + if (instance_it->second.size() == 0) { + instance_it = service_it->second.erase(instance_it); + } else { + ++instance_it; + } + } + + if (service_it->second.size() == 0) { + service_it = eventgroup_clients_.erase(service_it); + } else { + ++service_it; + } + } + } +} + +std::shared_ptr<endpoint> routing_manager_base::find_local(service_t _service, + instance_t _instance) { + return find_local(find_local_client(_service, _instance)); +} + +std::unordered_set<client_t> routing_manager_base::get_connected_clients() { + std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_); + std::unordered_set<client_t> clients; + for (auto its_client : local_endpoints_) { + clients.insert(its_client.first); + } + return clients; +} + +std::shared_ptr<event> routing_manager_base::find_event(service_t _service, + instance_t _instance, event_t _event) const { + std::shared_ptr<event> its_event; + std::lock_guard<std::mutex> its_lock(events_mutex_); + auto find_service = events_.find(_service); + if (find_service != events_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + auto find_event = find_instance->second.find(_event); + if (find_event != find_instance->second.end()) { + its_event = find_event->second; + } + } + } + return (its_event); +} + +std::shared_ptr<eventgroupinfo> routing_manager_base::find_eventgroup( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + + std::shared_ptr<eventgroupinfo> its_info(nullptr); + auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + its_info = found_eventgroup->second; + std::shared_ptr<serviceinfo> its_service_info + = find_service(_service, _instance); + if (its_service_info) { + std::string its_multicast_address; + uint16_t its_multicast_port; + if (configuration_->get_multicast(_service, _instance, + _eventgroup, + its_multicast_address, its_multicast_port)) { + try { + its_info->set_multicast( + boost::asio::ip::address::from_string( + its_multicast_address), + its_multicast_port); + } + catch (...) { + VSOMEIP_ERROR << "Eventgroup [" + << std::hex << std::setw(4) << std::setfill('0') + << _service << "." << _instance << "." << _eventgroup + << "] is configured as multicast, but no valid " + "multicast address is configured!"; + } + } + its_info->set_major(its_service_info->get_major()); + its_info->set_ttl(its_service_info->get_ttl()); + } + } + } + } + return (its_info); +} + +void routing_manager_base::remove_eventgroup_info(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) { + std::lock_guard<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()) { + found_instance->second.erase(_eventgroup); + } + } +} + +std::set<client_t> routing_manager_base::find_local_clients(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) { + std::set<client_t> its_clients; + std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_); + auto found_service = eventgroup_clients_.find(_service); + if (found_service != eventgroup_clients_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + its_clients = found_eventgroup->second; + } + } + } + return (its_clients); +} + +void routing_manager_base::send_local_notification(client_t _client, + const byte_t *_data, uint32_t _size, instance_t _instance, + bool _flush, bool _reliable, bool _initial) { + method_t its_method = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN], + _data[VSOMEIP_METHOD_POS_MAX]); + service_t its_service = VSOMEIP_BYTES_TO_WORD( + _data[VSOMEIP_SERVICE_POS_MIN], _data[VSOMEIP_SERVICE_POS_MAX]); + std::shared_ptr<event> its_event = find_event(its_service, _instance, its_method); + if (its_event && !its_event->is_shadow()) { + std::vector< byte_t > its_data; + + for (auto its_group : its_event->get_eventgroups()) { + // local + auto its_local_clients = find_local_clients(its_service, _instance, its_group); + for (auto its_local_client : its_local_clients) { + // If we also want to receive the message, send it to the routing manager + // We cannot call deliver_message in this case as this would end in receiving + // an answer before the call to send has finished. + if (its_local_client == host_->get_client()) { + uint8_t *local_data = const_cast<uint8_t *>(_data); + local_data[VSOMEIP_CLIENT_POS_MIN] = VSOMEIP_WORD_BYTE1(its_local_client); + local_data[VSOMEIP_CLIENT_POS_MAX] = VSOMEIP_WORD_BYTE0(its_local_client); + std::shared_ptr<endpoint> its_local_target = find_local(get_client()); + if (its_local_target) { + send_local(its_local_target, _client, _data, _size, + _instance, _flush, _reliable, VSOMEIP_SEND, true, _initial); + } + std::memset(&local_data[VSOMEIP_CLIENT_POS_MIN], 0, 2); + } else { + std::shared_ptr<endpoint> its_local_target = find_local(its_local_client); + if (its_local_target) { + send_local(its_local_target, _client, _data, _size, + _instance, _flush, _reliable, VSOMEIP_SEND, false, _initial); + } + } + } + } + } +} + +bool routing_manager_base::send_local( + std::shared_ptr<endpoint>& _target, client_t _client, + const byte_t *_data, uint32_t _size, + instance_t _instance, + bool _flush, bool _reliable, uint8_t _command, bool _queue_message, bool _initial) const { + + std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_); + +#ifdef USE_DLT + uint16_t its_data_size + = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); + + tc::trace_header its_header; + if (its_header.prepare(_target, true)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, its_data_size); +#endif + + std::vector<byte_t> its_command( + VSOMEIP_COMMAND_HEADER_SIZE + _size + sizeof(instance_t) + + sizeof(bool) + sizeof(bool) + sizeof(bool)); + its_command[VSOMEIP_COMMAND_TYPE_POS] = _command; + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, + sizeof(client_t)); + std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &_size, + sizeof(_size)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], _data, + _size); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size], + &_instance, sizeof(instance_t)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size + + sizeof(instance_t)], &_flush, sizeof(bool)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size + + sizeof(instance_t) + sizeof(bool)], &_reliable, sizeof(bool)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size + + sizeof(instance_t) + sizeof(bool) + sizeof(bool)], + &_initial, sizeof(bool)); + + if (_queue_message) { + return queue_message(&its_command[0], uint32_t(its_command.size())); + } else { + return _target->send(&its_command[0], uint32_t(its_command.size())); + } +} + +bool routing_manager_base::insert_subscription( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + client_t _client) { + std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_); + auto found_service = eventgroup_clients_.find(_service); + if (found_service != eventgroup_clients_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + if (found_eventgroup->second.find(_client) + != found_eventgroup->second.end()) + return false; + } + } + } + + eventgroup_clients_[_service][_instance][_eventgroup].insert(_client); + return true; +} + +} // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_impl.cpp b/implementation/routing/src/routing_manager_impl.cpp index 13ec332..3c98334 100644 --- a/implementation/routing/src/routing_manager_impl.cpp +++ b/implementation/routing/src/routing_manager_impl.cpp @@ -1,8 +1,9 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include <climits> #include <iomanip> #include <memory> #include <sstream> @@ -40,26 +41,22 @@ namespace vsomeip { routing_manager_impl::routing_manager_impl(routing_manager_host *_host) : - host_(_host), - io_(_host->get_io()), - deserializer_(std::make_shared<deserializer>()), - serializer_(std::make_shared<serializer>()), - configuration_(host_->get_configuration()) { + routing_manager_base(_host) { } routing_manager_impl::~routing_manager_impl() { } boost::asio::io_service & routing_manager_impl::get_io() { - return (io_); + return routing_manager_base::get_io(); } client_t routing_manager_impl::get_client() const { - return host_->get_client(); + return routing_manager_base::get_client(); } void routing_manager_impl::init() { - serializer_->create_data(configuration_->get_max_message_size_local()); + routing_manager_base::init(); // TODO: Only instantiate the stub if needed stub_ = std::make_shared<routing_manager_stub>(this, configuration_); @@ -99,134 +96,184 @@ void routing_manager_impl::stop() { if (discovery_) discovery_->stop(); stub_->stop(); + + for (auto client: get_connected_clients()) { + if (client != VSOMEIP_ROUTING_CLIENT) { + remove_local(client); + } + } } void routing_manager_impl::offer_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) { - std::shared_ptr<serviceinfo> its_info; + std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); + { - std::lock_guard<std::mutex> its_lock(local_mutex_); - local_services_[_service][_instance] = _client; + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + local_services_[_service][_instance] = std::make_tuple(_major, _minor, _client); + } - // Remote route (incoming only) - its_info = find_service(_service, _instance); - if (its_info) { - if (its_info->get_major() == _major - && its_info->get_minor() == _minor) { - its_info->set_ttl(DEFAULT_TTL); - } else { - host_->on_error(error_code_e::SERVICE_PROPERTY_MISMATCH); + routing_manager_base::offer_service(_client, _service, _instance, _major, _minor); + init_service_info(_service, _instance, true); + + { + std::lock_guard<std::mutex> its_lock(events_mutex_); + // Set major version for all registered events of this service and instance + auto find_service = events_.find(_service); + if (find_service != events_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + for (auto j : find_instance->second) { + j.second->set_version(_major); + } } - } else { - its_info = create_service_info(_service, _instance, _major, _minor, - DEFAULT_TTL, true); } } - if (discovery_ && its_info) { + if (discovery_) { discovery_->on_offer_change(); } - stub_->on_offer_service(_client, _service, _instance); - host_->on_availability(_service, _instance, true); + stub_->on_offer_service(_client, _service, _instance, _major, _minor); + host_->on_availability(_service, _instance, true, _major, _minor); } void routing_manager_impl::stop_offer_service(client_t _client, - service_t _service, instance_t _instance) { - on_stop_offer_service(_service, _instance); - stub_->on_stop_offer_service(_client, _service, _instance); + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + routing_manager_base::stop_offer_service(_client, _service, _instance, _major, _minor); + on_stop_offer_service(_service, _instance, _major, _minor); + stub_->on_stop_offer_service(_client, _service, _instance, _major, _minor); } void routing_manager_impl::request_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, bool _use_exclusive_proxy) { - std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); - if (its_info) { + routing_manager_base::request_service(_client, _service, _instance, _major, + _minor, _use_exclusive_proxy); + + auto its_info = find_service(_service, _instance); + if (!its_info) { + { + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); + requested_services_[_client][_service][_instance].insert({ _major, _minor }); + } + // Unknown service instance ~> tell SD to find it! + if (discovery_) { + discovery_->request_service(_service, _instance, _major, _minor, + DEFAULT_TTL); + } + } else { if ((_major == its_info->get_major() || DEFAULT_MAJOR == its_info->get_major()) && (_minor <= its_info->get_minor() - || DEFAULT_MINOR == its_info->get_minor())) { - its_info->add_client(_client); - } else { - host_->on_error(error_code_e::SERVICE_PROPERTY_MISMATCH); + || DEFAULT_MINOR == its_info->get_minor() + || _minor == ANY_MINOR)) { + if(!its_info->is_local()) { + find_or_create_remote_client(_service, _instance, true, VSOMEIP_ROUTING_CLIENT); + if (_use_exclusive_proxy) { + std::shared_ptr<endpoint> its_endpoint = its_info->get_endpoint(true); + if(its_endpoint) { + find_or_create_remote_client(_service, _instance, true, _client); + } + } + } } - } else { - if (discovery_) - discovery_->request_service(_service, _instance, _major, _minor, - DEFAULT_TTL); } - // TODO: Mutex?! if (_use_exclusive_proxy) { - specific_endpoint_clients.insert(_client); + std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); + specific_endpoint_clients_[_service][_instance].insert(_client); } } void routing_manager_impl::release_service(client_t _client, service_t _service, instance_t _instance) { + routing_manager_base::release_service(_client, _service, _instance); std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); - if (its_info) { - its_info->remove_client(_client); + if(its_info) { + if(!its_info->get_requesters_size()) { + if(discovery_) { + discovery_->release_service(_service, _instance); + } + } } else { - if (discovery_) + if(discovery_) { discovery_->release_service(_service, _instance); + } } } void routing_manager_impl::subscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, subscription_type_e _subscription_type) { - if (discovery_) { + if (get_client() == find_local_client(_service, _instance)) { if (!host_->on_subscription(_service, _instance, _eventgroup, _client, true)) { - VSOMEIP_INFO << "Subscription request for eventgroup " << _eventgroup - << " rejected from application handler"; + on_subscribe_nack(_client, _service, _instance, _eventgroup); + VSOMEIP_INFO << "Subscription request from client: 0x" << std::hex + << _client << std::dec << " for eventgroup: 0x" << _eventgroup + << " rejected from application handler."; return; + } else { + on_subscribe_ack(_client, _service, _instance, _eventgroup); } - - if (insert_subscription(_service, _instance, _eventgroup, _client)) { - if (0 == find_local_client(_service, _instance)) { - client_t subscriber = VSOMEIP_ROUTING_CLIENT; - // subscriber != VSOMEIP_ROUTING_CLIENT implies to use its own endpoint - auto its_selective = specific_endpoint_clients.find(_client); - if (its_selective != specific_endpoint_clients.end()) { - subscriber = _client; - } - discovery_->subscribe(_service, _instance, _eventgroup, - _major, DEFAULT_TTL, subscriber, _subscription_type); - } else { - send_subscribe(_client, _service, _instance, _eventgroup, _major); - - std::shared_ptr<eventgroupinfo> its_eventgroup - = find_eventgroup(_service, _instance, _eventgroup); - if (its_eventgroup) { - std::set<std::shared_ptr<event> > its_events - = its_eventgroup->get_events(); - for (auto e : its_events) { - if (e->is_field()) - e->notify_one(_client); + routing_manager_base::subscribe(_client, _service, _instance, _eventgroup, _major, _subscription_type); + } else { + if (discovery_) { + bool inserted = insert_subscription(_service, _instance, _eventgroup, _client); + if (inserted) { + if (0 == find_local_client(_service, _instance)) { + client_t subscriber = VSOMEIP_ROUTING_CLIENT; + // subscriber != VSOMEIP_ROUTING_CLIENT implies to use its own endpoint + { + std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); + auto found_service = specific_endpoint_clients_.find(_service); + if (found_service != specific_endpoint_clients_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_client = found_instance->second.find(_client); + if(found_client != found_instance->second.end()) { + subscriber = _client; + if (supports_selective(_service, _instance)) { + identify_for_subscribe(_client, _service, _instance, _major); + } else { + VSOMEIP_INFO << "Subcribe to legacy selective service: " << std::hex + << _service << ":" << _instance << "."; + } + } + } + } } + discovery_->subscribe(_service, _instance, _eventgroup, + _major, DEFAULT_TTL, subscriber, _subscription_type); + } else { + stub_->send_subscribe(routing_manager_base::find_local(_service, _instance), + _client, _service, _instance, _eventgroup, _major, false); } } + } else { + VSOMEIP_ERROR<< "SOME/IP eventgroups require SD to be enabled!"; } - } else { - VSOMEIP_ERROR<< "SOME/IP eventgroups require SD to be enabled!"; } } void routing_manager_impl::unsubscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup) { if (discovery_) { - auto found_service = eventgroup_clients_.find(_service); - if (found_service != eventgroup_clients_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto found_eventgroup = found_instance->second.find( - _eventgroup); - if (found_eventgroup != found_instance->second.end()) { - found_eventgroup->second.erase(_client); - if (0 == found_eventgroup->second.size()) { - eventgroup_clients_.erase(_eventgroup); + { + std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_); + auto found_service = eventgroup_clients_.find(_service); + if (found_service != eventgroup_clients_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find( + _eventgroup); + if (found_eventgroup != found_instance->second.end()) { + found_eventgroup->second.erase(_client); + if (0 == found_eventgroup->second.size()) { + eventgroup_clients_.erase(_eventgroup); + } } } } @@ -235,13 +282,23 @@ void routing_manager_impl::unsubscribe(client_t _client, service_t _service, if (0 == find_local_client(_service, _instance)) { client_t subscriber = VSOMEIP_ROUTING_CLIENT; // subscriber != VSOMEIP_ROUTING_CLIENT implies to use its own endpoint - auto its_selective = specific_endpoint_clients.find(_client); - if (its_selective != specific_endpoint_clients.end()) { - subscriber = _client; + { + std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); + auto found_service = specific_endpoint_clients_.find(_service); + if (found_service != specific_endpoint_clients_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_client = found_instance->second.find(_client); + if(found_client != found_instance->second.end()) { + subscriber = _client; + } + } + } } discovery_->unsubscribe(_service, _instance, _eventgroup, subscriber); } else { - send_unsubscribe(_client, _service, _instance, _eventgroup); + stub_->send_unsubscribe(routing_manager_base::find_local(_service, _instance), + _client, _service, _instance, _eventgroup); } clear_multicast_endpoints(_service, _instance); } else { @@ -249,30 +306,14 @@ void routing_manager_impl::unsubscribe(client_t _client, service_t _service, } } -bool routing_manager_impl::send(client_t its_client, +bool routing_manager_impl::send(client_t _client, std::shared_ptr<message> _message, bool _flush) { - bool is_sent(false); - - if (utility::is_request(_message->get_message_type())) { - _message->set_client(its_client); - } - - std::lock_guard<std::mutex> its_lock(serialize_mutex_); - if (serializer_->serialize(_message.get())) { - is_sent = send(its_client, serializer_->get_data(), - serializer_->get_size(), _message->get_instance(), - _flush, _message->is_reliable()); - serializer_->reset(); - } else { - VSOMEIP_ERROR << "Failed to serialize message. Check message size!"; - } - - return (is_sent); + return routing_manager_base::send(_client, _message, _flush); } bool routing_manager_impl::send(client_t _client, const byte_t *_data, length_t _size, instance_t _instance, - bool _flush, bool _reliable) { + bool _flush, bool _reliable, bool _initial) { bool is_sent(false); std::shared_ptr<endpoint> its_target; @@ -291,16 +332,20 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, if (_size > VSOMEIP_MESSAGE_TYPE_POS) { if (is_request) { - its_target = find_local(its_service, _instance); + its_target = routing_manager_base::find_local(its_service, _instance); } else if (!is_notification) { its_target = find_local(its_client); } else if (is_notification && _client) { // Selective notifications! + if (_client == get_client()) { + deliver_message(_data, _size, _instance, _reliable); + return true; + } its_target = find_local(_client); } if (its_target) { - is_sent = send_local(its_target, _client, _data, _size, _instance, _flush, _reliable); + is_sent = send_local(its_target, _client, _data, _size, _instance, _flush, _reliable, VSOMEIP_SEND, false, _initial); } else { // Check whether hosting application should get the message // If not, check routes to external @@ -312,19 +357,39 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, } else { if (is_request) { client_t client = VSOMEIP_ROUTING_CLIENT; - if (specific_endpoint_clients.find(its_client) != specific_endpoint_clients.end()) { - client = its_client; + { + std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); + auto found_service = specific_endpoint_clients_.find(its_service); + if (found_service != specific_endpoint_clients_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_client = found_instance->second.find(its_client); + if (found_client != found_instance->second.end()) { + client = its_client; + } + } + } } its_target = find_or_create_remote_client(its_service, _instance, _reliable, client); if (its_target) { +#ifdef USE_DLT + uint16_t its_data_size + = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); + + tc::trace_header its_header; + if (its_header.prepare(its_target, true)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, its_data_size); +#endif is_sent = its_target->send(_data, _size, _flush); } else { VSOMEIP_ERROR<< "Routing error. Client from remote service could not be found!"; } } else { std::shared_ptr<serviceinfo> its_info(find_service(its_service, _instance)); - if (its_info) { + if (its_info || is_service_discovery) { if (is_notification && !is_service_discovery) { + send_local_notification(get_client(), _data, _size, _instance, _flush, _reliable); method_t its_method = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN], _data[VSOMEIP_METHOD_POS_MAX]); std::shared_ptr<event> its_event = find_event(its_service, _instance, its_method); @@ -332,21 +397,6 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, std::vector< byte_t > its_data; for (auto its_group : its_event->get_eventgroups()) { - // local - auto its_local_clients = find_local_clients(its_service, _instance, its_group); - for (auto its_local_client : its_local_clients) { - // If we also want to receive the message, send it to the routing manager - // We cannot call deliver_message in this case as this would end in receiving - // an answer before the call to send has finished. - if (its_local_client == host_->get_client()) { - its_local_client = VSOMEIP_ROUTING_CLIENT; - } - - std::shared_ptr<endpoint> its_local_target = find_local(its_local_client); - if (its_local_target) { - send_local(its_local_target, _client, _data, _size, _instance, _flush, _reliable); - } - } // we need both endpoints as clients can subscribe to events via TCP and UDP std::shared_ptr<endpoint> its_unreliable_target = its_info->get_endpoint(false); std::shared_ptr<endpoint> its_reliable_target = its_info->get_endpoint(true); @@ -354,11 +404,37 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, // remote auto its_eventgroup = find_eventgroup(its_service, _instance, its_group); if (its_eventgroup) { + //Unicast targets for (auto its_remote : its_eventgroup->get_targets()) { - if(its_remote->is_reliable() && its_reliable_target) { - its_reliable_target->send_to(its_remote, _data, _size); - } else if(its_unreliable_target) { - its_unreliable_target->send_to(its_remote, _data, _size); + if(its_remote.endpoint_->is_reliable() && its_reliable_target) { +#ifdef USE_DLT + uint16_t its_data_size + = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); + + tc::trace_header its_header; + if (its_header.prepare(its_reliable_target, true)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, its_data_size); +#endif + its_reliable_target->send_to(its_remote.endpoint_, _data, _size); + } else if(its_unreliable_target && !its_eventgroup->is_multicast()) { +#ifdef USE_DLT + uint16_t its_data_size + = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); + + tc::trace_header its_header; + if (its_header.prepare(its_reliable_target, true)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, its_data_size); +#endif + its_unreliable_target->send_to(its_remote.endpoint_, _data, _size); + } + } + //send to multicast targets if subscribers are still interested + if(its_eventgroup->is_multicast() + && its_eventgroup->get_unreliable_target_count() > 0 ) { + for (auto its_multicast_target : its_eventgroup->get_multicast_targets()) { + its_unreliable_target->send_to(its_multicast_target.endpoint_, _data, _size); } } } @@ -366,8 +442,17 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, } } } else { - its_target = its_info->get_endpoint(_reliable); + its_target = is_service_discovery ? sd_info_->get_endpoint(false) : its_info->get_endpoint(_reliable); if (its_target) { +#ifdef USE_DLT + uint16_t its_data_size + = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); + + tc::trace_header its_header; + if (its_header.prepare(its_target, true)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, its_data_size); +#endif is_sent = its_target->send(_data, _size, _flush); } else { VSOMEIP_ERROR << "Routing error. Endpoint for service [" @@ -390,34 +475,6 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data, return (is_sent); } -bool routing_manager_impl::send_local( - std::shared_ptr<endpoint>& _target, client_t _client, - const byte_t *_data, uint32_t _size, - instance_t _instance, - bool _flush, bool _reliable) const { - - std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); - - std::vector<byte_t> its_command( - VSOMEIP_COMMAND_HEADER_SIZE + _size + sizeof(instance_t) - + sizeof(bool) + sizeof(bool)); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SEND; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, - sizeof(client_t)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &_size, - sizeof(_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], _data, - _size); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size], - &_instance, sizeof(instance_t)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size - + sizeof(instance_t)], &_flush, sizeof(bool)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size - + sizeof(instance_t) + sizeof(bool)], &_reliable, sizeof(bool)); - - return _target->send(&its_command[0], uint32_t(its_command.size()), _flush); -} - bool routing_manager_impl::send_to( const std::shared_ptr<endpoint_definition> &_target, std::shared_ptr<message> _message) { @@ -439,95 +496,56 @@ bool routing_manager_impl::send_to( std::shared_ptr<endpoint> its_endpoint = find_server_endpoint( _target->get_remote_port(), _target->is_reliable()); - return (its_endpoint && its_endpoint->send_to(_target, _data, _size)); -} - -void routing_manager_impl::register_event(client_t _client, - service_t _service, instance_t _instance, - event_t _event, const std::set<eventgroup_t> &_eventgroups, - bool _is_field, bool _is_provided) { - (void)_client; - std::shared_ptr<event> its_event = find_event(_service, _instance, _event); - if (its_event) { - if (its_event->is_field() == _is_field) { - if (_is_provided) { - its_event->set_provided(true); - } - for (auto eg : _eventgroups) { - its_event->add_eventgroup(eg); - } - } else { - VSOMEIP_ERROR << "Event registration update failed. " - "Specified arguments do not match existing registration."; - } - } else { - its_event = std::make_shared<event>(this); - its_event->set_service(_service); - its_event->set_instance(_instance); - its_event->set_event(_event); - its_event->set_field(_is_field); - its_event->set_provided(_is_provided); - std::shared_ptr<serviceinfo> its_service = find_service(_service, _instance); - if (its_service) { - its_event->set_version(its_service->get_major()); - } - - if (_eventgroups.size() == 0) { // No eventgroup specified - std::set<eventgroup_t> its_eventgroups; - its_eventgroups.insert(_event); - its_event->set_eventgroups(its_eventgroups); - } else { - its_event->set_eventgroups(_eventgroups); - } + if (its_endpoint) { +#ifdef USE_DLT + uint16_t its_data_size + = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); + + tc::trace_header its_header; + if (its_header.prepare(its_endpoint, true)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, its_data_size); +#endif + return its_endpoint->send_to(_target, _data, _size); } + return false; +} - its_event->add_ref(); +bool routing_manager_impl::send_to(const std::shared_ptr<endpoint_definition> &_target, + const byte_t *_data, uint32_t _size, uint16_t _sd_port) { + std::shared_ptr<endpoint> its_endpoint = find_server_endpoint( + _sd_port, _target->is_reliable()); - for (auto eg : _eventgroups) { - std::shared_ptr<eventgroupinfo> its_eventgroup_info - = find_eventgroup(_service, _instance, eg); - if (!its_eventgroup_info) { - its_eventgroup_info = std::make_shared<eventgroupinfo>(); - eventgroups_[_service][_instance][eg] = its_eventgroup_info; - } - its_eventgroup_info->add_event(its_event); + if (its_endpoint) { +#ifdef USE_DLT + uint16_t its_data_size + = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); + + tc::trace_header its_header; + if (its_header.prepare(its_endpoint, true)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, its_data_size); +#endif + return its_endpoint->send_to(_target, _data, _size); } - events_[_service][_instance][_event] = its_event; + return false; } -void routing_manager_impl::unregister_event(client_t _client, +void routing_manager_impl::register_shadow_event(client_t _client, service_t _service, instance_t _instance, - event_t _event, bool _is_provided) { - (void)_client; + event_t _event, const std::set<eventgroup_t> &_eventgroups, + bool _is_field, bool _is_provided) { + routing_manager_base::register_event(_client, _service, _instance, + _event, _eventgroups, _is_field, _is_provided, true); +} - auto found_service = events_.find(_service); - if (found_service != events_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto found_event = found_instance->second.find(_event); - if (found_event != found_instance->second.end()) { - auto its_event = found_event->second; - if (!its_event->remove_ref()) { - auto its_eventgroups = its_event->get_eventgroups(); - for (auto eg : its_eventgroups) { - std::shared_ptr<eventgroupinfo> its_eventgroup_info - = find_eventgroup(_service, _instance, eg); - if (its_eventgroup_info) { - its_eventgroup_info->remove_event(its_event); - if (0 == its_eventgroup_info->get_events().size()) { - remove_eventgroup_info(_service, _instance, eg); - } - } - } - found_instance->second.erase(_event); - } else if (_is_provided) { - its_event->set_provided(false); - } - } - } - } +void routing_manager_impl::unregister_shadow_event(client_t _client, + service_t _service, instance_t _instance, + event_t _event, bool _is_provided) { + routing_manager_base::unregister_event(_client, _service, _instance, + _event, _is_provided); } void routing_manager_impl::notify( @@ -545,25 +563,46 @@ void routing_manager_impl::notify( void routing_manager_impl::notify_one(service_t _service, instance_t _instance, event_t _event, std::shared_ptr<payload> _payload, client_t _client) { - - std::shared_ptr<event> its_event = find_event(_service, _instance, _event); - if (its_event) { - for (auto its_group : its_event->get_eventgroups()) { - auto its_eventgroup = find_eventgroup(_service, _instance, its_group); - if (its_eventgroup) { - auto its_subscriber = remote_subscriber_map_.find(_client); - if (its_subscriber != remote_subscriber_map_.end()) { - its_event->set_payload(_payload, its_subscriber->second); - } else { - its_event->set_payload(_payload, _client); - } - } - } - } else { - VSOMEIP_WARNING << "Attempt to update the undefined event/field [" - << std::hex << _service << "." << _instance << "." << _event - << "]"; - } + if (find_local(_client)) { + routing_manager_base::notify_one(_service, _instance, _event, _payload, + _client); + } else { + std::shared_ptr<event> its_event = find_event(_service, _instance, _event); + if (its_event) { + // Event is valid for service/instance + bool found_eventgroup(false); + // Iterate over all groups of the event to ensure at least + // one valid eventgroup for service/instance exists. + for (auto its_group : its_event->get_eventgroups()) { + auto its_eventgroup = find_eventgroup(_service, _instance, its_group); + if (its_eventgroup) { + // Eventgroup is valid for service/instance + found_eventgroup = true; + break; + } + } + if (found_eventgroup) { + // Now set event's payload! + // Either with endpoint_definition (remote) or with client (local). + auto its_service = remote_subscribers_.find(_service); + if (its_service != remote_subscribers_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + auto its_subscriber = its_instance->second.find(_client); + if (its_subscriber != its_instance->second.end()) { + for (auto its_target : its_subscriber->second) { + its_event->set_payload(_payload, its_target); + } + } + } + } + } + } else { + VSOMEIP_WARNING << "Attempt to update the undefined event/field [" + << std::hex << _service << "." << _instance << "." << _event + << "]"; + } + } } void routing_manager_impl::on_error(const byte_t *_data, length_t _length, endpoint *_receiver) { @@ -577,8 +616,12 @@ void routing_manager_impl::on_error(const byte_t *_data, length_t _length, endpo its_instance, _receiver->is_reliable(), _receiver); } +void routing_manager_impl::release_port(uint16_t _port, bool _reliable) { + used_client_ports_[_reliable].erase(_port); +} + void routing_manager_impl::on_message(const byte_t *_data, length_t _size, - endpoint *_receiver) { + endpoint *_receiver, const boost::asio::ip::address &_destination) { #if 0 std::stringstream msg; msg << "rmi::on_message: "; @@ -587,36 +630,62 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size, VSOMEIP_DEBUG << msg.str(); #endif service_t its_service; + method_t its_method; if (_size >= VSOMEIP_SOMEIP_HEADER_SIZE) { its_service = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_SERVICE_POS_MIN], _data[VSOMEIP_SERVICE_POS_MAX]); if (its_service == VSOMEIP_SD_SERVICE) { - if (discovery_) { - boost::asio::ip::address its_address; - if (_receiver->get_remote_address(its_address)) { - discovery_->on_message(_data, _size, its_address); + its_method = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN], + _data[VSOMEIP_METHOD_POS_MAX]); + if (discovery_ && its_method == sd::method) { + if (configuration_->get_sd_port() == _receiver->get_remote_port()) { + boost::asio::ip::address its_address; + if (_receiver->get_remote_address(its_address)) { + discovery_->on_message(_data, _size, its_address, _destination); + } else { + VSOMEIP_ERROR << "Ignored SD message from unknown address."; + } } else { - VSOMEIP_ERROR << "Ignored SD message from unknown address."; + VSOMEIP_ERROR << "Ignored SD message from unknown port (" + << _receiver->get_remote_port() << ")"; } } } else { instance_t its_instance = find_instance(its_service, _receiver); return_code_e return_code = check_error(_data, _size, its_instance); - if (return_code != return_code_e::E_OK) { - if (return_code != return_code_e::E_NOT_OK) { + if(!(_size >= VSOMEIP_MESSAGE_TYPE_POS && utility::is_request_no_return(_data[VSOMEIP_MESSAGE_TYPE_POS]))) { + if (return_code != return_code_e::E_OK && return_code != return_code_e::E_NOT_OK) { send_error(return_code, _data, _size, its_instance, _receiver->is_reliable(), _receiver); + return; } + } else if(return_code != return_code_e::E_OK && return_code != return_code_e::E_NOT_OK) { + //Ignore request no response message if an error occured return; } if (!deliver_specific_endpoint_message( its_service, its_instance, _data, _size, _receiver)) { + // set client ID to zero for all messages + if( utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + byte_t *its_data = const_cast<byte_t *>(_data); + its_data[VSOMEIP_CLIENT_POS_MIN] = 0x0; + its_data[VSOMEIP_CLIENT_POS_MAX] = 0x0; + } // Common way of message handling on_message(its_service, its_instance, _data, _size, _receiver->is_reliable()); } } } +#ifdef USE_DLT + uint16_t its_data_size + = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); + + tc::trace_header its_header; + if (its_header.prepare(_receiver, false)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, its_data_size); +#endif } void routing_manager_impl::on_message( @@ -632,88 +701,10 @@ void routing_manager_impl::on_message( msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; VSOMEIP_DEBUG << msg.str(); #endif - method_t its_method; client_t its_client; - session_t its_session; - - its_client = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_CLIENT_POS_MIN], - _data[VSOMEIP_CLIENT_POS_MAX]); - - its_method = VSOMEIP_BYTES_TO_WORD( - _data[VSOMEIP_METHOD_POS_MIN], - _data[VSOMEIP_METHOD_POS_MAX]); - - if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && its_client) { - // targeted notification - // reset client_id/subscriber/target field - const_cast<byte_t *>(_data)[VSOMEIP_CLIENT_POS_MIN] = 0; - const_cast<byte_t *>(_data)[VSOMEIP_CLIENT_POS_MAX] = 0; - - auto it_subscriber = remote_subscriber_map_.find(its_client); - if (it_subscriber != remote_subscriber_map_.end()) { - send_to(it_subscriber->second, _data, _size); - } else { - if (its_client == host_->get_client()) { - deliver_message(_data, _size, _instance, _reliable); - } else { - send(its_client, _data, _size, _instance, true, _reliable); - } - } - return; - } if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) { - std::shared_ptr<event> its_event - = find_event(_service, _instance, its_method); - if (its_event) { - uint32_t its_length = utility::get_payload_size(_data, _size); - std::shared_ptr<payload> its_payload = - runtime::get()->create_payload( - &_data[VSOMEIP_PAYLOAD_POS], - its_length); - its_event->set_payload(its_payload); - - if (!utility::is_request_no_return( - _data[VSOMEIP_MESSAGE_TYPE_POS])) { - std::shared_ptr<message> its_response = - runtime::get()->create_message(); - its_session = VSOMEIP_BYTES_TO_WORD( - _data[VSOMEIP_SESSION_POS_MIN], - _data[VSOMEIP_SESSION_POS_MAX]); - major_version_t its_version = _data[VSOMEIP_INTERFACE_VERSION_POS]; - - its_response->set_service(_service); - its_response->set_method(its_method); - its_response->set_client(its_client); - its_response->set_session(its_session); - its_response->set_interface_version(its_version); - - if (its_event->is_field()) { - its_response->set_message_type( - message_type_e::MT_RESPONSE); - its_response->set_payload(its_event->get_payload()); - } else { - its_response->set_message_type(message_type_e::MT_ERROR); - } - - std::lock_guard<std::mutex> its_lock(serialize_mutex_); - if (serializer_->serialize(its_response.get())) { - // always pass reliable = false, but this won't be used, as - // the event is sent out via TCP or UDP dependent on which - // L4Proto the subscriber passed in the endpoint option in - // its subscription to the eventgroup - send(its_client, - serializer_->get_data(), serializer_->get_size(), - _instance, true, false); - } else { - VSOMEIP_ERROR << "routing_manager_impl::on_message: serialization error."; - } - serializer_->reset(); - } - return; - } else { - its_client = find_local_client(_service, _instance); - } + its_client = find_local_client(_service, _instance); } else { its_client = VSOMEIP_BYTES_TO_WORD( _data[VSOMEIP_CLIENT_POS_MIN], @@ -732,7 +723,7 @@ void routing_manager_impl::on_message( void routing_manager_impl::on_notification(client_t _client, service_t _service, instance_t _instance, - const byte_t *_data, length_t _size) { + const byte_t *_data, length_t _size, bool _notify_one) { event_t its_event_id = VSOMEIP_BYTES_TO_WORD( _data[VSOMEIP_METHOD_POS_MIN], _data[VSOMEIP_METHOD_POS_MAX]); @@ -745,10 +736,12 @@ void routing_manager_impl::on_notification(client_t _client, &_data[VSOMEIP_PAYLOAD_POS], its_length); - if (_client == VSOMEIP_ROUTING_CLIENT) + if (!_notify_one) { its_event->set_payload(its_payload); - else - its_event->set_payload(its_payload, _client); + } else { + notify_one(_service, _instance, its_event->get_event(), its_payload, _client); + } + } } @@ -762,15 +755,28 @@ void routing_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) { auto found_endpoint = its_client.second.find(false); if (found_endpoint != its_client.second.end()) { if (found_endpoint->second.get() == _endpoint.get()) { + std::shared_ptr<serviceinfo> its_info(find_service(its_service.first, its_instance.first)); + if(!its_info) { + return; + } host_->on_availability(its_service.first, its_instance.first, - true); + true, its_info->get_major(), its_info->get_minor()); } } found_endpoint = its_client.second.find(true); if (found_endpoint != its_client.second.end()) { if (found_endpoint->second.get() == _endpoint.get()) { - host_->on_availability(its_service.first, - its_instance.first, true); + std::shared_ptr<serviceinfo> its_info(find_service(its_service.first, its_instance.first)); + if(!its_info){ + return; + } + host_->on_availability(its_service.first, its_instance.first, + true, its_info->get_major(), its_info->get_minor()); + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, + its_service.first, its_instance.first, its_info->get_major(), its_info->get_minor()); + if(discovery_) { + discovery_->on_reliable_endpoint_connected(its_service.first, its_instance.first, _endpoint); + } } } } @@ -789,15 +795,25 @@ void routing_manager_impl::on_disconnect(std::shared_ptr<endpoint> _endpoint) { auto found_endpoint = its_client.second.find(false); if (found_endpoint != its_client.second.end()) { if (found_endpoint->second.get() == _endpoint.get()) { + + std::shared_ptr<serviceinfo> its_info(find_service(its_service.first, its_instance.first)); + if(!its_info){ + return; + } host_->on_availability(its_service.first, its_instance.first, - false); + false, its_info->get_major(), its_info->get_minor()); } } found_endpoint = its_client.second.find(true); if (found_endpoint != its_client.second.end()) { if (found_endpoint->second.get() == _endpoint.get()) { - host_->on_availability(its_service.first, - its_instance.first, false); + + std::shared_ptr<serviceinfo> its_info(find_service(its_service.first, its_instance.first)); + if(!its_info){ + return; + } + host_->on_availability(its_service.first, its_instance.first, + false, its_info->get_major(), its_info->get_minor()); } } } @@ -807,12 +823,29 @@ void routing_manager_impl::on_disconnect(std::shared_ptr<endpoint> _endpoint) { } void routing_manager_impl::on_stop_offer_service(service_t _service, - instance_t _instance) { + instance_t _instance, major_version_t _major, minor_version_t _minor) { - for (auto &s : events_) - for (auto &i : s.second) - for (auto &e : i.second) - e.second->unset_payload(); + { + std::lock_guard<std::mutex> its_lock(events_mutex_); + auto its_events_service = events_.find(_service); + if (its_events_service != events_.end()) { + auto its_events_instance = its_events_service->second.find(_instance); + if (its_events_instance != its_events_service->second.end()) { + for (auto &e : its_events_instance->second) + e.second->unset_payload(); + } + } + } + { + std::lock_guard<std::mutex> its_lock(eventgroup_clients_mutex_); + auto its_service = eventgroup_clients_.find(_service); + if (its_service != eventgroup_clients_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + its_instance->second.clear(); + } + } + } /** * Hold reliable & unreliable server-endpoints from service info @@ -831,11 +864,10 @@ void routing_manager_impl::on_stop_offer_service(service_t _service, // Trigger "del_routing_info" either over SD or static if (discovery_) { - auto found_service = services_.find(_service); - if (found_service != services_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - found_instance->second->set_ttl(0); + auto its_info = find_service(_service, _instance); + if (its_info) { + if (its_info->get_major() == _major && its_info->get_minor() == _minor) { + its_info->set_ttl(0); discovery_->on_offer_change(); } } @@ -909,11 +941,8 @@ bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, host_->on_message(its_message); is_delivered = true; } else { - VSOMEIP_ERROR << "Deserialization of vSomeIP message failed"; - if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) { - send_error(return_code_e::E_MALFORMED_MESSAGE, _data, - _size, _instance, _reliable, nullptr); - } + VSOMEIP_ERROR << "Routing manager: deliver_message: " + << "SomeIP-Header deserialization failed!"; } return is_delivered; } @@ -930,18 +959,31 @@ bool routing_manager_impl::deliver_notification( std::shared_ptr<event> its_event = find_event(_service, _instance, its_method); if (its_event) { std::vector< byte_t > its_data; - + std::set<client_t> its_local_client_set; + if(its_event->is_field() && !its_event->is_shadow()) { + // store the current value of the remote field + const uint32_t its_length(utility::get_payload_size(_data, _length)); + std::shared_ptr<payload> its_payload = + runtime::get()->create_payload( + &_data[VSOMEIP_PAYLOAD_POS], + its_length); + its_event->set_payload_dont_notify(its_payload); + } for (auto its_group : its_event->get_eventgroups()) { - auto its_local_clients = find_local_clients(_service, _instance, its_group); - for (auto its_local_client : its_local_clients) { - if (its_local_client == host_->get_client()) { - deliver_message(_data, _length, _instance, _reliable); - } else { - std::shared_ptr<endpoint> its_local_target = find_local(its_local_client); - if (its_local_target) { - send_local(its_local_target, VSOMEIP_ROUTING_CLIENT, - _data, _length, _instance, true, _reliable); - } + auto its_local_clients + = find_local_clients(_service, _instance, its_group); + its_local_client_set.insert( + its_local_clients.begin(), its_local_clients.end()); + } + + for (auto its_local_client : its_local_client_set) { + if (its_local_client == host_->get_client()) { + deliver_message(_data, _length, _instance, _reliable); + } else { + std::shared_ptr<endpoint> its_local_target = find_local(its_local_client); + if (its_local_target) { + send_local(its_local_target, VSOMEIP_ROUTING_CLIENT, + _data, _length, _instance, true, _reliable, VSOMEIP_SEND); } } } @@ -953,57 +995,7 @@ bool routing_manager_impl::deliver_notification( std::shared_ptr<eventgroupinfo> routing_manager_impl::find_eventgroup( service_t _service, instance_t _instance, eventgroup_t _eventgroup) const { - std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); - - std::shared_ptr<eventgroupinfo> its_info(nullptr); - auto found_service = eventgroups_.find(_service); - if (found_service != eventgroups_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto found_eventgroup = found_instance->second.find(_eventgroup); - if (found_eventgroup != found_instance->second.end()) { - its_info = found_eventgroup->second; - std::shared_ptr<serviceinfo> its_service_info - = find_service(_service, _instance); - if (its_service_info) { - if (_eventgroup - == its_service_info->get_multicast_group()) { - try { - boost::asio::ip::address its_multicast_address = - boost::asio::ip::address::from_string( - its_service_info->get_multicast_address()); - uint16_t its_multicast_port = - its_service_info->get_multicast_port(); - its_info->set_multicast(its_multicast_address, - its_multicast_port); - } - catch (...) { - VSOMEIP_ERROR << "Eventgroup [" - << std::hex << std::setw(4) << std::setfill('0') - << _service << "." << _instance << "." << _eventgroup - << "] is configured as multicast, but no valid " - "multicast address is configured!"; - } - } - its_info->set_major(its_service_info->get_major()); - its_info->set_ttl(its_service_info->get_ttl()); - } - } - } - } - return (its_info); -} - -void routing_manager_impl::remove_eventgroup_info(service_t _service, - instance_t _instance, eventgroup_t _eventgroup) { - std::lock_guard<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()) { - found_instance->second.erase(_eventgroup); - } - } + return routing_manager_base::find_eventgroup(_service, _instance, _eventgroup); } std::shared_ptr<configuration> routing_manager_impl::get_configuration() const { @@ -1018,16 +1010,11 @@ std::shared_ptr<endpoint> routing_manager_impl::create_service_discovery_endpoin its_service_endpoint = create_server_endpoint(_port, _reliable, true); if (its_service_endpoint) { - std::shared_ptr<serviceinfo> its_info( - std::make_shared<serviceinfo>(ANY_MAJOR, ANY_MINOR, DEFAULT_TTL, - false)); // false, because we do _not_ want to announce it... - its_info->set_endpoint(its_service_endpoint, _reliable); - - // routing info - services_[VSOMEIP_SD_SERVICE][VSOMEIP_SD_INSTANCE] = its_info; - - its_service_endpoint->add_multicast(VSOMEIP_SD_SERVICE, - VSOMEIP_SD_METHOD, _address, _port); + sd_info_ = std::make_shared<serviceinfo>(ANY_MAJOR, ANY_MINOR, DEFAULT_TTL, + false); // false, because we do _not_ want to announce it... + sd_info_->set_endpoint(its_service_endpoint, _reliable); + its_service_endpoint->add_default_target(VSOMEIP_SD_SERVICE, + _address, _port); its_service_endpoint->join(_address); } else { VSOMEIP_ERROR << "Service Discovery endpoint could not be created. " @@ -1038,16 +1025,15 @@ std::shared_ptr<endpoint> routing_manager_impl::create_service_discovery_endpoin } services_t routing_manager_impl::get_offered_services() const { - services_t its_offers; - std::lock_guard<std::mutex> its_lock(services_mutex_); - for (auto s : services_) { + services_t its_services; + for (auto s : get_services()) { for (auto i : s.second) { if (i.second->is_local()) { - its_offers[s.first][i.first] = i.second; + its_services[s.first][i.first] = i.second; } } } - return (its_offers); + return its_services; } std::shared_ptr<endpoint> routing_manager_impl::find_or_create_remote_client( @@ -1064,26 +1050,12 @@ std::shared_ptr<endpoint> routing_manager_impl::find_or_create_remote_client( /////////////////////////////////////////////////////////////////////////////// // PRIVATE /////////////////////////////////////////////////////////////////////////////// -std::shared_ptr<serviceinfo> routing_manager_impl::find_service( - service_t _service, instance_t _instance) const { - std::shared_ptr<serviceinfo> its_info; - 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()) { - its_info = found_instance->second; - } - } - return (its_info); -} - -std::shared_ptr<serviceinfo> routing_manager_impl::create_service_info( - service_t _service, instance_t _instance, major_version_t _major, - minor_version_t _minor, ttl_t _ttl, bool _is_local_service) { - std::shared_ptr<serviceinfo> its_info; +void routing_manager_impl::init_service_info( + service_t _service, instance_t _instance, bool _is_local_service) { + std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); if (configuration_) { - its_info = std::make_shared<serviceinfo>(_major, _minor, _ttl, _is_local_service); + std::shared_ptr<endpoint> its_reliable_endpoint; + std::shared_ptr<endpoint> its_unreliable_endpoint; uint16_t its_reliable_port = configuration_->get_reliable_port(_service, _instance); @@ -1092,16 +1064,6 @@ std::shared_ptr<serviceinfo> routing_manager_impl::create_service_info( bool is_someip = configuration_->is_someip(_service, _instance); - its_info->set_multicast_address( - configuration_->get_multicast_address(_service, _instance)); - its_info->set_multicast_port( - configuration_->get_multicast_port(_service, _instance)); - its_info->set_multicast_group( - configuration_->get_multicast_group(_service, _instance)); - - std::shared_ptr<endpoint> its_reliable_endpoint; - std::shared_ptr<endpoint> its_unreliable_endpoint; - // Create server endpoints for local services only if (_is_local_service) { if (ILLEGAL_PORT != its_reliable_port) { @@ -1133,20 +1095,14 @@ std::shared_ptr<serviceinfo> routing_manager_impl::create_service_info( << "]. Service is internal."; } } - - { - std::lock_guard<std::mutex> its_lock(services_mutex_); - services_[_service][_instance] = its_info; - } } else { host_->on_error(error_code_e::CONFIGURATION_MISSING); } - - return (its_info); } std::shared_ptr<endpoint> routing_manager_impl::create_client_endpoint( - const boost::asio::ip::address &_address, uint16_t _port, + const boost::asio::ip::address &_address, + uint16_t _local_port, uint16_t _remote_port, bool _reliable, client_t _client, bool _start) { (void)_client; @@ -1155,18 +1111,30 @@ std::shared_ptr<endpoint> routing_manager_impl::create_client_endpoint( if (_reliable) { its_endpoint = std::make_shared<tcp_client_endpoint_impl>( shared_from_this(), - boost::asio::ip::tcp::endpoint(_address, _port), io_, + boost::asio::ip::tcp::endpoint( + (_address.is_v4() ? + boost::asio::ip::tcp::v4() : + boost::asio::ip::tcp::v6()), + _local_port), + boost::asio::ip::tcp::endpoint(_address, _remote_port), + io_, configuration_->get_message_size_reliable( - _address.to_string(), _port)); + _address.to_string(), _remote_port)); if (configuration_->has_enabled_magic_cookies(_address.to_string(), - _port)) { + _remote_port)) { its_endpoint->enable_magic_cookies(); } } else { its_endpoint = std::make_shared<udp_client_endpoint_impl>( shared_from_this(), - boost::asio::ip::udp::endpoint(_address, _port), io_); + boost::asio::ip::udp::endpoint( + (_address.is_v4() ? + boost::asio::ip::udp::v4() : + boost::asio::ip::udp::v6()), + _local_port), + boost::asio::ip::udp::endpoint(_address, _remote_port), + io_); } if (_start) its_endpoint->start(); @@ -1226,7 +1194,7 @@ std::shared_ptr<endpoint> routing_manager_impl::create_server_endpoint( } std::shared_ptr<endpoint> routing_manager_impl::find_server_endpoint( - uint16_t _port, bool _reliable) { + uint16_t _port, bool _reliable) const { std::shared_ptr<endpoint> its_endpoint; std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); auto found_port = server_endpoints_.find(_port); @@ -1236,6 +1204,7 @@ std::shared_ptr<endpoint> routing_manager_impl::find_server_endpoint( its_endpoint = found_endpoint->second; } } + return (its_endpoint); } @@ -1243,118 +1212,23 @@ std::shared_ptr<endpoint> routing_manager_impl::find_or_create_server_endpoint( uint16_t _port, bool _reliable, bool _start) { std::shared_ptr<endpoint> its_endpoint = find_server_endpoint(_port, _reliable); - if (0 == its_endpoint) { + if (!its_endpoint) { its_endpoint = create_server_endpoint(_port, _reliable, _start); } return (its_endpoint); } std::shared_ptr<endpoint> routing_manager_impl::find_local(client_t _client) { - std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); - std::shared_ptr<endpoint> its_endpoint; - auto found_endpoint = local_clients_.find(_client); - if (found_endpoint != local_clients_.end()) { - its_endpoint = found_endpoint->second; - } - return (its_endpoint); -} - -std::shared_ptr<endpoint> routing_manager_impl::create_local(client_t _client) { - std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); - - std::stringstream its_path; - its_path << VSOMEIP_BASE_PATH << std::hex << _client; - -#ifdef WIN32 - boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); - int port = VSOMEIP_INTERNAL_BASE_PORT + _client; -#endif - - std::shared_ptr<endpoint> its_endpoint = std::make_shared< - local_client_endpoint_impl>(shared_from_this(), -#ifdef WIN32 - boost::asio::ip::tcp::endpoint(address, port) -#else - boost::asio::local::stream_protocol::endpoint(its_path.str()) -#endif - , io_, configuration_->get_max_message_size_local()); - local_clients_[_client] = its_endpoint; - its_endpoint->start(); - return (its_endpoint); + return routing_manager_base::find_local(_client); } std::shared_ptr<endpoint> routing_manager_impl::find_or_create_local( client_t _client) { - std::shared_ptr<endpoint> its_endpoint(find_local(_client)); - if (!its_endpoint) { - its_endpoint = create_local(_client); - } - return (its_endpoint); + return routing_manager_base::find_or_create_local(_client); } void routing_manager_impl::remove_local(client_t _client) { - { - std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); - std::shared_ptr<endpoint> its_endpoint = find_local(_client); - its_endpoint->stop(); - local_clients_.erase(_client); - } - { - std::lock_guard<std::mutex> its_lock(local_mutex_); - // Finally remove all services that are implemented by the client. - std::set<std::pair<service_t, instance_t>> its_services; - for (auto& s : local_services_) { - for (auto& i : s.second) { - if (i.second == _client) - its_services.insert({ s.first, i.first }); - } - } - - for (auto& si : its_services) { - local_services_[si.first].erase(si.second); - if (local_services_[si.first].size() == 0) - local_services_.erase(si.first); - } - } -} - -std::shared_ptr<endpoint> routing_manager_impl::find_local(service_t _service, - instance_t _instance) { - client_t client = find_local_client(_service, _instance); - if (client) { - return find_local(client); - } - return nullptr; -} - -client_t routing_manager_impl::find_local_client(service_t _service, - instance_t _instance) { - std::lock_guard<std::mutex> its_lock(local_mutex_); - client_t its_client(0); - auto found_service = local_services_.find(_service); - if (found_service != local_services_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - its_client = found_instance->second; - } - } - return (its_client); -} - -std::set<client_t> routing_manager_impl::find_local_clients(service_t _service, - instance_t _instance, eventgroup_t _eventgroup) { - std::set<client_t> its_clients; - auto found_service = eventgroup_clients_.find(_service); - if (found_service != eventgroup_clients_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto found_eventgroup = found_instance->second.find(_eventgroup); - if (found_eventgroup != found_instance->second.end()) { - its_clients = found_eventgroup->second; - } - } - } - return (its_clients); + routing_manager_base::remove_local(_client); } instance_t routing_manager_impl::find_instance(service_t _service, @@ -1374,34 +1248,42 @@ std::shared_ptr<endpoint> routing_manager_impl::create_remote_client( service_t _service, instance_t _instance, bool _reliable, client_t _client) { std::shared_ptr<endpoint> its_endpoint; std::shared_ptr<endpoint_definition> its_endpoint_def; - auto found_service = remote_service_info_.find(_service); - if (found_service != remote_service_info_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto found_reliability = found_instance->second.find(_reliable); - if (found_reliability != found_instance->second.end()) { - its_endpoint_def = found_reliability->second; - its_endpoint = create_client_endpoint( - its_endpoint_def->get_address(), - its_endpoint_def->get_port(), _reliable, _client, - configuration_->is_someip(_service, _instance) - ); - } - } - } - if (its_endpoint) { - service_instances_[_service][its_endpoint.get()] = _instance; - remote_services_[_service][_instance][_client][_reliable] = its_endpoint; - if (_client == VSOMEIP_ROUTING_CLIENT) { - client_endpoints_by_ip_[its_endpoint_def->get_address()] - [its_endpoint_def->get_port()] - [_reliable] = its_endpoint; - // Set the basic route to the service in the service info - auto found_service_info = find_service(_service, _instance); - if (found_service_info) { - found_service_info->set_endpoint(its_endpoint, _reliable); - } - } + + uint16_t its_local_port; + if (configuration_->get_client_port(_service, _instance, _reliable, + used_client_ports_, its_local_port)) { + auto found_service = remote_service_info_.find(_service); + if (found_service != remote_service_info_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_reliability = found_instance->second.find(_reliable); + if (found_reliability != found_instance->second.end()) { + its_endpoint_def = found_reliability->second; + its_endpoint = create_client_endpoint( + its_endpoint_def->get_address(), + its_local_port, + its_endpoint_def->get_port(), + _reliable, _client, + configuration_->is_someip(_service, _instance) + ); + } + } + } + if (its_endpoint) { + used_client_ports_[_reliable].insert(its_local_port); + service_instances_[_service][its_endpoint.get()] = _instance; + remote_services_[_service][_instance][_client][_reliable] = its_endpoint; + if (_client == VSOMEIP_ROUTING_CLIENT) { + client_endpoints_by_ip_[its_endpoint_def->get_address()] + [its_endpoint_def->get_port()] + [_reliable] = its_endpoint; + // Set the basic route to the service in the service info + auto found_service_info = find_service(_service, _instance); + if (found_service_info) { + found_service_info->set_endpoint(its_endpoint, _reliable); + } + } + } } return its_endpoint; } @@ -1423,7 +1305,7 @@ std::shared_ptr<endpoint> routing_manager_impl::find_remote_client( } } } - if(its_endpoint || _client != VSOMEIP_ROUTING_CLIENT) { + if (its_endpoint || _client != VSOMEIP_ROUTING_CLIENT) { return its_endpoint; } @@ -1461,41 +1343,34 @@ std::shared_ptr<endpoint> routing_manager_impl::find_remote_client( return its_endpoint; } -std::shared_ptr<event> routing_manager_impl::find_event(service_t _service, - instance_t _instance, event_t _event) const { - std::shared_ptr<event> its_event; - auto find_service = events_.find(_service); - if (find_service != events_.end()) { - auto find_instance = find_service->second.find(_instance); - if (find_instance != find_service->second.end()) { - auto find_event = find_instance->second.find(_event); - if (find_event != find_instance->second.end()) { - its_event = find_event->second; - } - } - } - return (its_event); -} - -std::set<std::shared_ptr<event> > routing_manager_impl::find_events( - service_t _service, instance_t _instance, eventgroup_t _eventgroup) { - std::set<std::shared_ptr<event> > its_events; - auto found_service = eventgroups_.find(_service); - if (found_service != eventgroups_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto found_eventgroup = found_instance->second.find(_eventgroup); - if (found_eventgroup != found_instance->second.end()) { - return (found_eventgroup->second->get_events()); - } - } - } - return (its_events); +client_t routing_manager_impl::find_client( + service_t _service, instance_t _instance, + const std::shared_ptr<eventgroupinfo> &_eventgroup, + const std::shared_ptr<endpoint_definition> &_target) const { + client_t its_client = VSOMEIP_ROUTING_CLIENT; + if (!_eventgroup->is_multicast()) { + if (!_target->is_reliable()) { + uint16_t unreliable_port = configuration_->get_unreliable_port(_service, _instance); + auto endpoint = find_server_endpoint(unreliable_port, false); + if (endpoint) { + its_client = std::dynamic_pointer_cast<udp_server_endpoint_impl>(endpoint)-> + get_client(_target); + } + } else { + uint16_t reliable_port = configuration_->get_reliable_port(_service, _instance); + auto endpoint = find_server_endpoint(reliable_port, true); + if (endpoint) { + its_client = std::dynamic_pointer_cast<tcp_server_endpoint_impl>(endpoint)-> + get_client(_target); + } + } + } + return its_client; } - bool routing_manager_impl::is_field(service_t _service, instance_t _instance, event_t _event) const { + std::lock_guard<std::mutex> its_lock(events_mutex_); auto find_service = events_.find(_service); if (find_service != events_.end()) { auto find_instance = find_service->second.find(_instance); @@ -1530,10 +1405,7 @@ void routing_manager_impl::add_routing_info( is_local = true; its_info = create_service_info(_service, _instance, _major, _minor, _ttl, is_local); - { - std::lock_guard<std::mutex> its_lock(services_mutex_); - services_[_service][_instance] = its_info; - } + init_service_info(_service, _instance, is_local); } else { its_info->set_ttl(_ttl); } @@ -1554,9 +1426,9 @@ void routing_manager_impl::add_routing_info( if (its_definition->get_address() == _reliable_address && its_definition->get_port() == _reliable_port) { is_reliable_known = true; + } else { + VSOMEIP_WARNING << "Reliable service endpoint has changed!"; } - } else { - VSOMEIP_WARNING << "Reliable service endpoint has changed!"; } } if (_unreliable_port != ILLEGAL_PORT) { @@ -1581,6 +1453,48 @@ void routing_manager_impl::add_routing_info( = endpoint_definition::get(_reliable_address, _reliable_port, true); remote_service_info_[_service][_instance][true] = endpoint_def; is_added = !is_unreliable_known; + + // check if service was requested and establish TCP connection if necessary + { + bool connected(false); + std::lock_guard<std::mutex> its_lock(requested_services_mutex_); + for(const auto &client_id : requested_services_) { + auto found_service = client_id.second.find(_service); + if (found_service != client_id.second.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto &major_minor_pair : found_instance->second) { + if ((major_minor_pair.first == _major + || _major == DEFAULT_MAJOR) + && (major_minor_pair.second <= _minor + || _minor == DEFAULT_MINOR + || major_minor_pair.second == ANY_MINOR)) { + // SWS_SD_00376 establish TCP connection to service + // service is marked as available later in on_connect() + if(!connected) { + find_or_create_remote_client(_service, _instance, + true, VSOMEIP_ROUTING_CLIENT); + connected = true; + } + its_info->add_client(client_id.first); + break; + } + } + } + } + } + } + + std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); + auto found_service2 = specific_endpoint_clients_.find(_service); + if (found_service2 != specific_endpoint_clients_.end()) { + auto found_instance = found_service2->second.find(_instance); + if (found_instance != found_service2->second.end()) { + for (const client_t& c : found_instance->second) { + find_or_create_remote_client(_service, _instance, true, c); + } + } + } } if (_unreliable_port != ILLEGAL_PORT && !is_unreliable_known) { @@ -1588,27 +1502,51 @@ void routing_manager_impl::add_routing_info( = endpoint_definition::get(_unreliable_address, _unreliable_port, false); remote_service_info_[_service][_instance][false] = endpoint_def; is_added = !is_reliable_known; + if (is_added) { + host_->on_availability(_service, _instance, true, _major, _minor); + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, _major, _minor); + } } - if (is_added) { - host_->on_availability(_service, _instance, true); - stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance); - } } void routing_manager_impl::del_routing_info(service_t _service, instance_t _instance, bool _has_reliable, bool _has_unreliable) { - host_->on_availability(_service, _instance, false); - stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance); + std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); + if(!its_info) + return; + + host_->on_availability(_service, _instance, false, its_info->get_major(), its_info->get_minor()); + stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, its_info->get_major(), its_info->get_minor()); // Implicit unsubscribe - auto found_service = eventgroups_.find(_service); - if (found_service != eventgroups_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - for (auto &its_eventgroup : found_instance->second) { - its_eventgroup.second->clear_targets(); + { + std::lock_guard<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(); + } + } + } + } + { + std::lock_guard<std::mutex> its_lock(identified_clients_mutex_); + auto its_service = identified_clients_.find(_service); + if (its_service != identified_clients_.end()) { + auto found_instance = its_service->second.find(_instance); + if (found_instance != its_service->second.end()) { + auto found_reliable = found_instance->second.find(true); + if (found_reliable != found_instance->second.end()) { + found_reliable->second.clear(); + } + auto found_unreliable = found_instance->second.find(false); + if (found_unreliable != found_instance->second.end()) { + found_unreliable->second.clear(); + } } } } @@ -1626,17 +1564,23 @@ void routing_manager_impl::del_routing_info(service_t _service, instance_t _inst clear_service_info(_service, _instance, false); } -ttl_t routing_manager_impl::update_routing_info(ttl_t _elapsed) { - ttl_t its_smallest_ttl(DEFAULT_TTL); +std::chrono::milliseconds routing_manager_impl::update_routing_info(std::chrono::milliseconds _elapsed) { + std::chrono::seconds default_ttl(DEFAULT_TTL); + std::chrono::milliseconds its_smallest_ttl = + std::chrono::duration_cast<std::chrono::milliseconds>(default_ttl); std::map<service_t, std::map<instance_t, std::pair<bool, bool> > > its_expired_offers; - for (auto &s : services_) { + for (auto &s : get_services()) { for (auto &i : s.second) { + if (routing_manager_base::find_local(s.first, i.first)) { + continue; //don't expire local services + } ttl_t its_ttl = i.second->get_ttl(); + std::chrono::milliseconds precise_ttl = i.second->get_precise_ttl(); if (its_ttl < DEFAULT_TTL) { // do not touch "forever" - if (its_ttl < _elapsed || its_ttl == 0) { + if (precise_ttl.count() < _elapsed.count() || precise_ttl.count() == 0) { i.second->set_ttl(0); if (discovery_) discovery_->unsubscribe_all(s.first, i.first); @@ -1645,8 +1589,8 @@ ttl_t routing_manager_impl::update_routing_info(ttl_t _elapsed) { i.second->get_endpoint(false) != nullptr }; } else { - ttl_t its_new_ttl(its_ttl - _elapsed); - i.second->set_ttl(its_new_ttl); + std::chrono::milliseconds its_new_ttl(precise_ttl - _elapsed); + i.second->set_precise_ttl(its_new_ttl); if (its_smallest_ttl > its_new_ttl) its_smallest_ttl = its_new_ttl; } @@ -1668,8 +1612,11 @@ void routing_manager_impl::expire_services(const boost::asio::ip::address &_addr std::map<instance_t, std::pair<bool, bool> > > its_expired_offers; - for (auto &s : services_) { + for (auto &s : get_services()) { for (auto &i : s.second) { + if (routing_manager_base::find_local(s.first, i.first)) { + continue; //don't expire local services + } bool is_gone(false); boost::asio::ip::address its_address; std::shared_ptr<endpoint> its_endpoint = i.second->get_endpoint(true); @@ -1705,17 +1652,23 @@ void routing_manager_impl::expire_services(const boost::asio::ip::address &_addr } void routing_manager_impl::expire_subscriptions(const boost::asio::ip::address &_address) { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); for (auto &its_service : eventgroups_) { for (auto &its_instance : its_service.second) { for (auto &its_eventgroup : its_instance.second) { - std::set<std::shared_ptr<endpoint_definition>> its_invalid_targets; + std::set<std::shared_ptr<endpoint_definition>> its_invalid_endpoints; for (auto &its_target : its_eventgroup.second->get_targets()) { - if (its_target->get_address() == _address) - its_invalid_targets.insert(its_target); + if (its_target.endpoint_->get_address() == _address) + its_invalid_endpoints.insert(its_target.endpoint_); } - for (auto &its_target : its_invalid_targets) { - its_eventgroup.second->remove_target(its_target); + for (auto &its_endpoint : its_invalid_endpoints) { + its_eventgroup.second->remove_target(its_endpoint); + } + if(its_eventgroup.second->is_multicast() && + 0 == its_eventgroup.second->get_unreliable_target_count() ) { + //clear multicast targets if no subscriber is left for multicast eventgroup + its_eventgroup.second->clear_multicast_targets(); } } } @@ -1751,16 +1704,15 @@ void routing_manager_impl::init_routing_info() { } } -void routing_manager_impl::on_subscribe( - service_t _service, instance_t _instance, eventgroup_t _eventgroup, - std::shared_ptr<endpoint_definition> _subscriber, - std::shared_ptr<endpoint_definition> _target) { +bool routing_manager_impl::on_subscribe_accepted(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, const std::shared_ptr<endpoint_definition> _target, + const std::chrono::high_resolution_clock::time_point &_expiration) { std::shared_ptr<eventgroupinfo> its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); if (its_eventgroup) { - client_t client = 0; - if (!its_eventgroup->is_multicast()) { - if (!_target->is_reliable()) { + client_t client = VSOMEIP_ROUTING_CLIENT; + if (!_target->is_reliable()) { + if (!its_eventgroup->is_multicast()) { uint16_t unreliable_port = configuration_->get_unreliable_port(_service, _instance); _target->set_remote_port(unreliable_port); auto endpoint = find_server_endpoint(unreliable_port, false); @@ -1769,40 +1721,89 @@ void routing_manager_impl::on_subscribe( get_client(_target); } } - else { - uint16_t reliable_port = configuration_->get_reliable_port(_service, _instance); - auto endpoint = find_server_endpoint(reliable_port, true); - _target->set_remote_port(reliable_port); - if (endpoint) { - client = std::dynamic_pointer_cast<tcp_server_endpoint_impl>(endpoint)-> - get_client(_target); - } + } + else { + uint16_t reliable_port = configuration_->get_reliable_port(_service, _instance); + _target->set_remote_port(reliable_port); + auto endpoint = find_server_endpoint(reliable_port, true); + if (endpoint) { + client = std::dynamic_pointer_cast<tcp_server_endpoint_impl>(endpoint)-> + get_client(_target); } } - if(!host_->on_subscription(_service, _instance, _eventgroup, client, true)) { - VSOMEIP_INFO << "Subscription request for eventgroup " << _eventgroup - << " rejected from application handler"; - return; + if (its_eventgroup->update_target(_target, _expiration)) { + return true; } - VSOMEIP_DEBUG << "on_subscribe: target=" << _target->get_address().to_string() - << ":" << std::dec <<_target->get_port() << ":Client=" << std::hex - << client << (_target->is_reliable() ? " reliable" : " unreliable"); + if (!host_->on_subscription(_service, _instance, _eventgroup, client, true)) { + VSOMEIP_INFO << "Subscription request from client: 0x" << std::hex + << client << " for eventgroup: 0x" << _eventgroup << std::dec + << " rejected from application handler."; + return false; + } - send_subscribe(client, _service, _instance, _eventgroup, its_eventgroup->get_major()); + if (client != VSOMEIP_ROUTING_CLIENT) { + VSOMEIP_DEBUG << "Subscription accepted: eventgroup=" << _eventgroup + << " : target: " << _target->get_address().to_string() + << ":" << std::dec <<_target->get_port() + << (_target->is_reliable() ? " reliable" : " unreliable") + << " from client: 0x" << std::hex << client << "."; + } else { + VSOMEIP_DEBUG << "Subscription accepted: eventgroup: " << _eventgroup + << " : target: " << _target->get_address().to_string() + << ":" << std::dec <<_target->get_port() + << (_target->is_reliable() ? " reliable" : " unreliable") + << " from unknown client."; + } - remote_subscriber_map_[client] = _target; + stub_->send_subscribe(routing_manager_base::find_local(_service, _instance), + client, _service, _instance, _eventgroup, its_eventgroup->get_major(), true); - if (its_eventgroup->add_target(_target)) { // unicast or multicast + remote_subscribers_[_service][_instance][client].insert(_target); + } else { + VSOMEIP_ERROR<< "subscribe: attempt to subscribe to unknown eventgroup!"; + return false; + } + return true; +} + +void routing_manager_impl::on_subscribe( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + std::shared_ptr<endpoint_definition> _subscriber, + std::shared_ptr<endpoint_definition> _target, + const std::chrono::high_resolution_clock::time_point &_expiration) { + + std::shared_ptr<eventgroupinfo> its_eventgroup + = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + // IP address of target is a multicast address if the event is in a multicast eventgroup + bool target_added(false); + if( its_eventgroup->is_multicast() && !_subscriber->is_reliable()) { + // Event is in multicast eventgroup and subscribe for UDP + target_added = its_eventgroup->add_target({ _target, _expiration }, {_subscriber, _expiration}); + + // If the target is multicast, we need to set the remote port + // of the unicast(!) here, as its only done in on_subscribe_accepted + // for unicast subscribes and it needs to be done before calling + // notify_one on the events. + uint16_t unreliable_port = + configuration_->get_unreliable_port(_service, _instance); + _subscriber->set_remote_port(unreliable_port); + } + else { + // subscribe for TCP or UDP + target_added = its_eventgroup->add_target({ _target, _expiration }); + } + + if (target_added) { // unicast or multicast + // send initial events for (auto its_event : its_eventgroup->get_events()) { if (its_event->is_field()) { its_event->notify_one(_subscriber); // unicast } } } - } else { - VSOMEIP_ERROR<< "subscribe: attempt to subscribe to unknown eventgroup!"; } } @@ -1812,35 +1813,26 @@ void routing_manager_impl::on_unsubscribe(service_t _service, std::shared_ptr<eventgroupinfo> its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); if (its_eventgroup) { - client_t client = 0; - if (!its_eventgroup->is_multicast()) { - if (!_target->is_reliable()) { - uint16_t unreliable_port = configuration_->get_unreliable_port(_service, _instance); - auto endpoint = find_server_endpoint(unreliable_port, false); - if (endpoint) { - client = std::dynamic_pointer_cast<udp_server_endpoint_impl>(endpoint)-> - get_client(_target); - } - } else { - uint16_t reliable_port = configuration_->get_reliable_port(_service, _instance); - auto endpoint = find_server_endpoint(reliable_port, true); - if (endpoint) { - client = std::dynamic_pointer_cast<tcp_server_endpoint_impl>(endpoint)-> - get_client(_target); - } - } - } + client_t its_client = find_client(_service, _instance, its_eventgroup, _target); - VSOMEIP_DEBUG << "on_unsubscribe: target=" << _target->get_address().to_string() - << ":" << std::dec <<_target->get_port() << ":Client=" << std::hex - << client << (_target->is_reliable() ? " reliable" : " unreliable");; + if (its_client != VSOMEIP_ROUTING_CLIENT) { + VSOMEIP_DEBUG << "on_unsubscribe: target: " << _target->get_address().to_string() + << ":" << std::dec <<_target->get_port() + << (_target->is_reliable() ? " reliable" : " unreliable") + << " from client: 0x" << std::hex << its_client; + } else { + VSOMEIP_DEBUG << "on_unsubscribe: target: " << _target->get_address().to_string() + << ":" << std::dec <<_target->get_port() + << (_target->is_reliable() ? " reliable" : " unreliable"); + } its_eventgroup->remove_target(_target); + clear_remote_subscriber(_service, _instance, its_client, _target); - if (remote_subscriber_map_.find(client) != remote_subscriber_map_.end()) { - remote_subscriber_map_.erase(client); - } - host_->on_subscription(_service, _instance, _eventgroup, client, false); + stub_->send_unsubscribe(routing_manager_base::find_local(_service, _instance), + its_client, _service, _instance, _eventgroup); + + host_->on_subscription(_service, _instance, _eventgroup, its_client, false); } else { VSOMEIP_ERROR<<"unsubscribe: attempt to subscribe to unknown eventgroup!"; @@ -1883,79 +1875,51 @@ void routing_manager_impl::on_subscribe_ack(service_t _service, } } -void routing_manager_impl::send_subscribe(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major) { - - byte_t its_command[VSOMEIP_SUBSCRIBE_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_SUBSCRIBE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, - sizeof(_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] = _major; - - std::shared_ptr<vsomeip::endpoint> target = find_local(_service, _instance); - if (target) { - target->send(its_command, sizeof(its_command)); - } -} - -void routing_manager_impl::send_unsubscribe(client_t _client, service_t _service, - instance_t _instance, eventgroup_t _eventgroup) { - - byte_t its_command[VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE]; - uint32_t its_size = VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE - - VSOMEIP_COMMAND_HEADER_SIZE; - - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNSUBSCRIBE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, - sizeof(_client)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, - sizeof(_service)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, - sizeof(_instance)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, - sizeof(_eventgroup)); - - std::shared_ptr<vsomeip::endpoint> target = find_local(_service, _instance); - if (target) { - target->send(its_command, sizeof(its_command)); - } -} - -bool routing_manager_impl::insert_subscription( - service_t _service, instance_t _instance, eventgroup_t _eventgroup, - client_t _client) { - - auto found_service = eventgroup_clients_.find(_service); - if (found_service != eventgroup_clients_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto found_eventgroup = found_instance->second.find(_eventgroup); - if (found_eventgroup != found_instance->second.end()) { - if (found_eventgroup->second.find(_client) - != found_eventgroup->second.end()) - return false; +void routing_manager_impl::on_subscribe_ack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + { + std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); + auto found_service = specific_endpoint_clients_.find(_service); + if(found_service != specific_endpoint_clients_.end()){ + auto found_instance = found_service->second.find(_instance); + if(found_instance != found_service->second.end()) { + auto found_client = found_instance->second.find(_client); + if(found_client == found_instance->second.end()) { + // Ack is only interesting for proxies using its own endpoint! + return; + } } } } - - eventgroup_clients_[_service][_instance][_eventgroup].insert(_client); - return true; + if (_client == get_client()) { + host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/); + } else { + stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup); + } } +void routing_manager_impl::on_subscribe_nack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + { + std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); + auto found_service = specific_endpoint_clients_.find(_service); + if(found_service != specific_endpoint_clients_.end()){ + auto found_instance = found_service->second.find(_instance); + if(found_instance != found_service->second.end()) { + auto found_client = found_instance->second.find(_client); + if(found_client == found_instance->second.end()) { + // Nack is only interesting for proxies using its own endpoint! + return; + } + } + } + } + if (_client == get_client()) { + host_->on_subscription_error(_service, _instance, _eventgroup, 0x7 /*Rejected*/); + } else { + stub_->send_subscribe_nack(_client, _service, _instance, _eventgroup); + } +} bool routing_manager_impl::deliver_specific_endpoint_message(service_t _service, instance_t _instance, const byte_t *_data, length_t _size, endpoint *_receiver) { @@ -1973,9 +1937,12 @@ bool routing_manager_impl::deliver_specific_endpoint_message(service_t _service, if (found_reliability != client_entry.second.end()) { auto found_enpoint = found_reliability->second; if (found_enpoint.get() == _receiver) { - auto local_endpoint = find_local(client); if (client != get_client()) { - send_local(local_endpoint, client, _data, _size, _instance, true, _receiver->is_reliable()); + auto local_endpoint = find_local(client); + if (local_endpoint) { + send_local(local_endpoint, client, _data, _size, _instance, true, + _receiver->is_reliable(), VSOMEIP_SEND); + } } else { deliver_message(_data, _size, _instance, _receiver->is_reliable()); } @@ -2009,18 +1976,27 @@ void routing_manager_impl::clear_client_endpoints(service_t _service, instance_t } } } - for (client_t client : specific_endpoint_clients) { - if (remote_services_.find(_service) != remote_services_.end()) { - if (remote_services_[_service].find(_instance) != remote_services_[_service].end()) { - auto endpoint = remote_services_[_service][_instance][client][_reliable]; - if (endpoint) { - service_instances_[_service].erase(endpoint.get()); - endpoint->stop(); - } - remote_services_[_service][_instance][client].erase(_reliable); - auto found_endpoint = remote_services_[_service][_instance][client].find(!_reliable); - if (found_endpoint == remote_services_[_service][_instance][client].end()) { - remote_services_[_service][_instance].erase(client); + { + std::lock_guard<std::mutex> its_lock(specific_endpoint_clients_mutex_); + auto found_service = specific_endpoint_clients_.find(_service); + if(found_service != specific_endpoint_clients_.end()){ + auto found_instance = found_service->second.find(_instance); + if(found_instance != found_service->second.end()) { + for (const client_t& client : found_instance->second) { + if (remote_services_.find(_service) != remote_services_.end()) { + if (remote_services_[_service].find(_instance) != remote_services_[_service].end()) { + auto endpoint = remote_services_[_service][_instance][client][_reliable]; + if (endpoint) { + service_instances_[_service].erase(endpoint.get()); + endpoint->stop(); + } + remote_services_[_service][_instance][client].erase(_reliable); + auto found_endpoint = remote_services_[_service][_instance][client].find(!_reliable); + if (found_endpoint == remote_services_[_service][_instance][client].end()) { + remote_services_[_service][_instance].erase(client); + } + } + } } } } @@ -2137,33 +2113,15 @@ void routing_manager_impl::clear_multicast_endpoints(service_t _service, instanc } } -void routing_manager_impl::clear_service_info(service_t _service, instance_t _instance, - bool _reliable) { - std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); - if (!its_info) { - return; - } - // Clear service_info and service_group - std::shared_ptr<endpoint> its_empty_endpoint; - if (!its_info->get_endpoint(!_reliable)) { - if (1 >= services_[_service].size()) { - services_.erase(_service); - } else { - services_[_service].erase(_instance); - } - } else { - its_info->set_endpoint(its_empty_endpoint, _reliable); - } -} - return_code_e routing_manager_impl::check_error(const byte_t *_data, length_t _size, instance_t _instance) { service_t its_service = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_SERVICE_POS_MIN], _data[VSOMEIP_SERVICE_POS_MAX]); - if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) { - if (_size >= VSOMEIP_PAYLOAD_POS) { + if (_size >= VSOMEIP_PAYLOAD_POS) { + if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS]) + || utility::is_request_no_return(_data[VSOMEIP_MESSAGE_TYPE_POS]) ) { if (_data[VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) { VSOMEIP_WARNING << "Received a message with unsupported protocol version for service 0x" << std::hex << its_service; @@ -2175,25 +2133,26 @@ return_code_e routing_manager_impl::check_error(const byte_t *_data, length_t _s return return_code_e::E_UNKNOWN_SERVICE; } // Check interface version of service/instance - auto found_service = services_.find(its_service); - if (found_service != services_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - auto its_info = found_instance->second; - major_version_t its_version = _data[VSOMEIP_INTERFACE_VERSION_POS]; - if (its_version != its_info->get_major()) { - return return_code_e::E_WRONG_INTERFACE_VERSION; - } + auto its_info = find_service(its_service, _instance); + if (its_info) { + major_version_t its_version = _data[VSOMEIP_INTERFACE_VERSION_POS]; + if (its_version != its_info->get_major()) { + VSOMEIP_WARNING << "Received a message with unsupported interface version for service 0x" + << std::hex << its_service; + return return_code_e::E_WRONG_INTERFACE_VERSION; } } if (_data[VSOMEIP_RETURN_CODE_POS] != static_cast<byte_t> (return_code_e::E_OK)) { // Request calls must to have return code E_OK set! + VSOMEIP_WARNING << "Received a message with unsupported return code set for service 0x" + << std::hex << its_service; return return_code_e::E_NOT_OK; } - } else { - // Message shorter than vSomeIP message header - return return_code_e::E_MALFORMED_MESSAGE; } + } else { + // Message shorter than vSomeIP message header + VSOMEIP_WARNING << "Received a message message which is shorter than vSomeIP message header!"; + return return_code_e::E_MALFORMED_MESSAGE; } return return_code_e::E_OK; } @@ -2207,6 +2166,7 @@ void routing_manager_impl::send_error(return_code_e _return_code, service_t its_service = 0; method_t its_method = 0; session_t its_session = 0; + major_version_t its_version = 0; if (_size >= VSOMEIP_CLIENT_POS_MAX) { its_client = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_CLIENT_POS_MIN], @@ -2224,11 +2184,14 @@ void routing_manager_impl::send_error(return_code_e _return_code, its_session = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_SESSION_POS_MIN], _data[VSOMEIP_SESSION_POS_MAX]); } + if( _size >= VSOMEIP_INTERFACE_VERSION_POS) { + its_version = _data[VSOMEIP_INTERFACE_VERSION_POS]; + } auto error_message = runtime::get()->create_message(_reliable); error_message->set_client(its_client); error_message->set_instance(_instance); - error_message->set_interface_version(0); + error_message->set_interface_version(its_version); error_message->set_message_type(message_type_e::MT_ERROR); error_message->set_method(its_method); error_message->set_return_code(_return_code); @@ -2241,11 +2204,19 @@ void routing_manager_impl::send_error(return_code_e _return_code, boost::asio::ip::address adr; uint16_t port; if (_receiver->is_reliable()) { - auto remote = static_cast<tcp_server_endpoint_impl*>(_receiver)->get_remote(); + auto endpoint = dynamic_cast<tcp_server_endpoint_impl*>(_receiver); + if(!endpoint) { + return; + } + auto remote = endpoint->get_remote(); adr = remote.address(); port = remote.port(); } else { - auto remote = static_cast<udp_server_endpoint_impl*>(_receiver)->get_remote(); + auto endpoint = dynamic_cast<udp_server_endpoint_impl*>(_receiver); + if (!endpoint) { + return; + } + auto remote = endpoint->get_remote(); adr = remote.address(); port = remote.port(); } @@ -2253,9 +2224,6 @@ void routing_manager_impl::send_error(return_code_e _return_code, std::make_shared<endpoint_definition>(adr, port, _receiver->is_reliable()); its_endpoint_def->set_remote_port(_receiver->get_local_port()); send_to(its_endpoint_def, serializer_->get_data(), serializer_->get_size()); - } else { - send(get_client(), serializer_->get_data(), serializer_->get_size(), - _instance, true, _reliable); } serializer_->reset(); } else { @@ -2263,5 +2231,163 @@ void routing_manager_impl::send_error(return_code_e _return_code, } } +void routing_manager_impl::on_identify_response(client_t _client, service_t _service, + instance_t _instance, bool _reliable) { + std::lock_guard<std::mutex> its_lock(identified_clients_mutex_); + identified_clients_[_service][_instance][_reliable].insert(_client); + discovery_->send_subscriptions(_service, _instance, _client, _reliable); +} + +void routing_manager_impl::identify_for_subscribe(client_t _client, + service_t _service, instance_t _instance, major_version_t _major) { + if (!has_identified(_client, _service, _instance, false)) { + auto unreliable_endpoint = find_or_create_remote_client(_service, _instance, false, _client); + if (unreliable_endpoint) { + auto message = runtime::get()->create_message(false); + message->set_service(_service); + message->set_instance(_instance); + message->set_client(_client); + message->set_method(ANY_METHOD - 1); + message->set_interface_version(_major); + message->set_message_type(message_type_e::MT_REQUEST); + std::lock_guard<std::mutex> its_lock(serialize_mutex_); + if (serializer_->serialize(message.get())) { + unreliable_endpoint->send(serializer_->get_data(), + serializer_->get_size()); + serializer_->reset(); + } + } + } + if (!has_identified(_client, _service, _instance, true)) { + auto reliable_endpoint = find_or_create_remote_client(_service, _instance, true, _client); + if (reliable_endpoint) { + auto message = runtime::get()->create_message(true); + message->set_service(_service); + message->set_instance(_instance); + message->set_client(_client); + message->set_method(ANY_METHOD - 1); + message->set_interface_version(_major); + message->set_message_type(message_type_e::MT_REQUEST); + std::lock_guard<std::mutex> its_lock(serialize_mutex_); + if (serializer_->serialize(message.get())) { + reliable_endpoint->send(serializer_->get_data(), + serializer_->get_size()); + serializer_->reset(); + } + } + } +} + +bool routing_manager_impl::supports_selective(service_t _service, instance_t _instance) { + bool supports_selective(false); + auto its_service = remote_service_info_.find(_service); + if (its_service != remote_service_info_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + for (auto its_reliable : its_instance->second) { + supports_selective |= configuration_-> + supports_selective_broadcasts( + its_reliable.second->get_address()); + } + } + } + return supports_selective; } - // namespace vsomeip + +bool routing_manager_impl::has_identified(client_t _client, service_t _service, + instance_t _instance, bool _reliable) { + if (!supports_selective(_service, _instance)) { + // For legacy selective services clients can't be identified! + return true; + } + bool has_identified(false); + std::lock_guard<std::mutex> its_lock(identified_clients_mutex_); + auto its_service = identified_clients_.find(_service); + if (its_service != identified_clients_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + auto its_reliable = its_instance->second.find(_reliable); + if (its_reliable != its_instance->second.end()) { + auto its_client = its_reliable->second.find(_client); + if (its_client != its_reliable->second.end()) { + has_identified = true; + } + } + } + } + return has_identified; +} + +void routing_manager_impl::clear_remote_subscriber( + service_t _service, instance_t _instance, client_t _client, + const std::shared_ptr<endpoint_definition> &_target) { + auto its_service = remote_subscribers_.find(_service); + if (its_service != remote_subscribers_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + auto its_client = its_instance->second.find(_client); + if (its_client != its_instance->second.end()) { + if (its_client->second.size() <= 1) { + its_instance->second.erase(_client); + } else { + its_client->second.erase(_target); + } + } + } + } +} + +std::chrono::high_resolution_clock::time_point +routing_manager_impl::expire_subscriptions() { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + std::chrono::high_resolution_clock::time_point now + = std::chrono::high_resolution_clock::now(); + std::chrono::high_resolution_clock::time_point next_expiration + = std::chrono::high_resolution_clock::now() + std::chrono::hours(24); + + for (auto &its_service : eventgroups_) { + for (auto &its_instance : its_service.second) { + for (auto &its_eventgroup : its_instance.second) { + std::set<std::shared_ptr<endpoint_definition>> its_expired_endpoints; + for (auto &its_target : its_eventgroup.second->get_targets()) { + if (its_target.expiration_ < now) { + its_expired_endpoints.insert(its_target.endpoint_); + } else if (its_target.expiration_ < next_expiration) { + next_expiration = its_target.expiration_; + } + } + + for (auto its_endpoint : its_expired_endpoints) { + its_eventgroup.second->remove_target(its_endpoint); + + client_t its_client + = find_client(its_service.first, its_instance.first, + its_eventgroup.second, its_endpoint); + clear_remote_subscriber(its_service.first, its_instance.first, + its_client, its_endpoint); + + VSOMEIP_DEBUG << "Expired subscription (" + << std::hex << its_service.first << "." + << its_instance .first << "." + << its_eventgroup.first << " from " + << its_endpoint->get_address() << ":" + << std::dec << its_endpoint->get_port() + << "(" << std::hex << its_client << ")"; + } + if(its_eventgroup.second->is_multicast() && + 0 == its_eventgroup.second->get_unreliable_target_count() ) { + //clear multicast targets if no unreliable subscriber is left for multicast eventgroup + its_eventgroup.second->clear_multicast_targets(); + } + } + } + } + + return next_expiration; +} + +bool routing_manager_impl::queue_message(const byte_t *_data, uint32_t _size) const { + return stub_->queue_message(_data, _size); +} + +} // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_proxy.cpp b/implementation/routing/src/routing_manager_proxy.cpp index 45346bf..0a3f7b5 100644 --- a/implementation/routing/src/routing_manager_proxy.cpp +++ b/implementation/routing/src/routing_manager_proxy.cpp @@ -1,10 +1,19 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include <climits> #include <iomanip> #include <mutex> +#include <unordered_set> +#include <future> + +#ifndef WIN32 +// for umask +#include <sys/types.h> +#include <sys/stat.h> +#endif #include <vsomeip/constants.hpp> #include <vsomeip/runtime.hpp> @@ -26,32 +35,20 @@ namespace vsomeip { routing_manager_proxy::routing_manager_proxy(routing_manager_host *_host) : - io_(_host->get_io()), + routing_manager_base(_host), is_connected_(false), is_started_(false), state_(state_type_e::ST_DEREGISTERED), - host_(_host), - client_(_host->get_client()), - configuration_(host_->get_configuration()), - serializer_(std::make_shared<serializer>()), - deserializer_(std::make_shared<deserializer>()), sender_(0), - receiver_(0) { + receiver_(0) +{ } routing_manager_proxy::~routing_manager_proxy() { } -boost::asio::io_service & routing_manager_proxy::get_io() { - return (io_); -} - -client_t routing_manager_proxy::get_client() const { - return client_; -} - void routing_manager_proxy::init() { - serializer_->create_data(configuration_->get_max_message_size_local()); + routing_manager_base::init(); std::stringstream its_sender_path; sender_ = create_local(VSOMEIP_ROUTING_CLIENT); @@ -63,6 +60,7 @@ void routing_manager_proxy::init() { int port = VSOMEIP_INTERNAL_BASE_PORT + client_; #else ::unlink(its_client.str().c_str()); + const mode_t previous_mask(::umask(static_cast<mode_t>(configuration_->get_umask()))); #endif receiver_ = std::make_shared<local_server_endpoint_impl>(shared_from_this(), #ifdef WIN32 @@ -75,30 +73,45 @@ void routing_manager_proxy::init() { #ifdef WIN32 VSOMEIP_DEBUG << "Listening at " << port; #else + ::umask(previous_mask); VSOMEIP_DEBUG<< "Listening at " << its_client.str(); #endif } void routing_manager_proxy::start() { - if (sender_) + is_started_ = true; + + if (!sender_) { + // application has been stopped and started again + sender_ = create_local(VSOMEIP_ROUTING_CLIENT); + } + if (sender_) { sender_->start(); + } if (receiver_) receiver_->start(); - - if (is_connected_) { - register_application(); - } - - is_started_ = true; } void routing_manager_proxy::stop() { deregister_application(); - if (receiver_) + if (receiver_) { receiver_->stop(); + } + if (sender_) { + sender_->stop(); + } + + for (auto client: get_connected_clients()) { + if (client != VSOMEIP_ROUTING_CLIENT) { + remove_local(client); + } + } + + // delete the sender + sender_ = nullptr; std::stringstream its_client; its_client << VSOMEIP_BASE_PATH << std::hex << client_; #ifdef WIN32 @@ -113,14 +126,14 @@ void routing_manager_proxy::stop() { void routing_manager_proxy::offer_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) { - service_versions_[_service][_instance] = _major; + routing_manager_base::offer_service(_client, _service, _instance, _major, _minor); + if (is_connected_) { send_offer_service(_client, _service, _instance, _major, _minor); - } else { - service_data_t offer = { _service, _instance, _major, _minor, false }; - std::lock_guard<std::mutex> its_lock(pending_mutex_); - pending_offers_.insert(offer); } + service_data_t offer = { _service, _instance, _major, _minor, false }; + std::lock_guard<std::mutex> its_lock(pending_mutex_); + pending_offers_.insert(offer); } void routing_manager_proxy::send_offer_service(client_t _client, @@ -149,16 +162,15 @@ void routing_manager_proxy::send_offer_service(client_t _client, } void routing_manager_proxy::stop_offer_service(client_t _client, - service_t _service, instance_t _instance) { + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { (void)_client; - auto its_service = service_versions_.find(_service); - if (its_service != service_versions_.end()) { - auto its_instance = its_service->second.find(_instance); - if (its_instance != its_service->second.end()) { - its_service->second.clear(); - } - } + routing_manager_base::stop_offer_service(_client, _service, _instance, _major, _minor); + + // Reliable/Unreliable unimportant as routing_proxy does not + // create server endpoints which needs to be freed + clear_service_info(_service, _instance, false); if (is_connected_) { byte_t its_command[VSOMEIP_STOP_OFFER_SERVICE_COMMAND_SIZE]; @@ -174,45 +186,49 @@ void routing_manager_proxy::stop_offer_service(client_t _client, sizeof(_service)); std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, sizeof(_instance)); + its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4] = _major; + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5], &_minor, + sizeof(_minor)); sender_->send(its_command, sizeof(its_command)); - } else { - std::lock_guard<std::mutex> its_lock(pending_mutex_); - auto it = pending_offers_.begin(); - while (it != pending_offers_.end()) { - if (it->service_ == _service - && it->instance_ == _instance) { - break; - } - it++; + } + std::lock_guard<std::mutex> its_lock(pending_mutex_); + auto it = pending_offers_.begin(); + while (it != pending_offers_.end()) { + if (it->service_ == _service + && it->instance_ == _instance) { + break; } - - if (it != pending_offers_.end()) pending_offers_.erase(it); + it++; } + if (it != pending_offers_.end()) pending_offers_.erase(it); } void routing_manager_proxy::request_service(client_t _client, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, bool _use_exclusive_proxy) { + routing_manager_base::request_service(_client, _service, _instance, _major, + _minor, _use_exclusive_proxy); send_request_service(_client, _service, _instance, _major, _minor, _use_exclusive_proxy); } void routing_manager_proxy::release_service(client_t _client, service_t _service, instance_t _instance) { - (void)_client; - (void)_service; - (void)_instance; + routing_manager_base::release_service(_client, _service, _instance); + send_release_service(_client, _service, _instance); } void routing_manager_proxy::register_event(client_t _client, service_t _service, instance_t _instance, event_t _event, const std::set<eventgroup_t> &_eventgroups, - bool _is_field, bool _is_provided) { - (void)_client; + bool _is_field, bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) { + + (void)_is_shadow; + (void)_is_cache_placeholder; - if (_is_field) - fields_[_service][_instance].insert(_event); + routing_manager_base::register_event(_client, _service, _instance, + _event,_eventgroups, _is_field, _is_provided); send_register_event(client_, _service, _instance, _event, _eventgroups, _is_field, _is_provided); @@ -221,18 +237,9 @@ void routing_manager_proxy::register_event(client_t _client, void routing_manager_proxy::unregister_event(client_t _client, service_t _service, instance_t _instance, event_t _event, bool _is_provided) { - (void)_client; - auto find_service = fields_.find(_service); - if (find_service != fields_.end()) { - auto find_instance = find_service->second.find(_instance); - if (find_instance != find_service->second.end()) { - find_instance->second.erase(_event); - if (find_instance->second.size() == 0) - find_service->second.erase(find_instance); - } - if (find_service->second.size() == 0) - fields_.erase(find_service); - } + + routing_manager_base::unregister_event(_client, _service, _instance, + _event, _is_provided); if (is_connected_) { byte_t its_command[VSOMEIP_UNREGISTER_EVENT_COMMAND_SIZE]; @@ -250,33 +257,30 @@ void routing_manager_proxy::unregister_event(client_t _client, sizeof(_instance)); std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_event, sizeof(_event)); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 5] + its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] = static_cast<byte_t>(_is_provided); sender_->send(its_command, sizeof(its_command)); - } else { - std::lock_guard<std::mutex> its_lock(pending_mutex_); - auto it = pending_event_registrations_.begin(); - while (it != pending_event_registrations_.end()) { - if (it->service_ == _service - && it->instance_ == _instance - && it->event_ == _event) { - break; - } - it++; + } + std::lock_guard<std::mutex> its_lock(pending_mutex_); + auto it = pending_event_registrations_.begin(); + while (it != pending_event_registrations_.end()) { + if (it->service_ == _service + && it->instance_ == _instance + && it->event_ == _event) { + break; } - - if (it != pending_event_registrations_.end()) - pending_event_registrations_.erase(it); + it++; } + if (it != pending_event_registrations_.end()) + pending_event_registrations_.erase(it); } + bool routing_manager_proxy::is_field(service_t _service, instance_t _instance, event_t _event) const { - auto find_service = fields_.find(_service); - if (find_service != fields_.end()) { - auto find_instance = find_service->second.find(_instance); - if (find_instance != find_service->second.end()) - return (find_instance->second.find(_event) != find_instance->second.end()); + auto event = find_event(_service, _instance, _event); + if (event && event->is_field()) { + return true; } return false; } @@ -284,15 +288,15 @@ bool routing_manager_proxy::is_field(service_t _service, instance_t _instance, void routing_manager_proxy::subscribe(client_t _client, service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, subscription_type_e _subscription_type) { - if (is_connected_) { + + if (is_connected_ && is_available(_service, _instance, _major)) { send_subscribe(_client, _service, _instance, _eventgroup, _major, _subscription_type); - } else { - eventgroup_data_t subscription = { _service, _instance, _eventgroup, _major, - _subscription_type}; - std::lock_guard<std::mutex> its_lock(pending_mutex_); - pending_subscriptions_.insert(subscription); } + eventgroup_data_t subscription = { _service, _instance, _eventgroup, _major, + _subscription_type}; + std::lock_guard<std::mutex> its_lock(pending_mutex_); + pending_subscriptions_.insert(subscription); } void routing_manager_proxy::send_subscribe(client_t _client, service_t _service, @@ -305,8 +309,8 @@ void routing_manager_proxy::send_subscribe(client_t _client, service_t _service, - VSOMEIP_COMMAND_HEADER_SIZE; its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, - sizeof(client_)); + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, + sizeof(_client)); std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, sizeof(its_size)); std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, @@ -316,10 +320,71 @@ void routing_manager_proxy::send_subscribe(client_t _client, service_t _service, std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, sizeof(_eventgroup)); its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] = _major; - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7], &_subscription_type, + its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7] = 0; // local subscriber + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 8], &_subscription_type, sizeof(_subscription_type)); - sender_->send(its_command, sizeof(its_command)); + client_t target_client = find_local_client(_service, _instance); + if (target_client != VSOMEIP_ROUTING_CLIENT) { + auto its_target = find_or_create_local(target_client); + its_target->send(its_command, sizeof(its_command)); + } else { + sender_->send(its_command, sizeof(its_command)); + } +} + +void routing_manager_proxy::send_subscribe_nack(client_t _subscriber, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + byte_t its_command[VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE]; + uint32_t its_size = VSOMEIP_SUBSCRIBE_NACK_COMMAND_SIZE + - VSOMEIP_COMMAND_HEADER_SIZE; + + client_t its_client = get_client(); + its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_NACK; + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &its_client, + sizeof(its_client)); + std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, + sizeof(its_size)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, + sizeof(_service)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, + sizeof(_instance)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, + sizeof(_eventgroup)); + + auto its_target = find_local(_subscriber); + if (its_target) { + its_target->send(its_command, sizeof(its_command)); + } else { + sender_->send(its_command, sizeof(its_command)); + } +} + +void routing_manager_proxy::send_subscribe_ack(client_t _subscriber, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + byte_t its_command[VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE]; + uint32_t its_size = VSOMEIP_SUBSCRIBE_ACK_COMMAND_SIZE + - VSOMEIP_COMMAND_HEADER_SIZE; + + client_t its_client = get_client(); + its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_ACK; + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &its_client, + sizeof(its_client)); + std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, + sizeof(its_size)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, + sizeof(_service)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, + sizeof(_instance)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, + sizeof(_eventgroup)); + + auto its_target = find_local(_subscriber); + if (its_target) { + its_target->send(its_command, sizeof(its_command)); + } else { + sender_->send(its_command, sizeof(its_command)); + } } void routing_manager_proxy::unsubscribe(client_t _client, service_t _service, @@ -332,8 +397,8 @@ void routing_manager_proxy::unsubscribe(client_t _client, service_t _service, - VSOMEIP_COMMAND_HEADER_SIZE; its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNSUBSCRIBE; - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, - sizeof(client_)); + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, + sizeof(_client)); std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, sizeof(its_size)); std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, @@ -343,84 +408,92 @@ void routing_manager_proxy::unsubscribe(client_t _client, service_t _service, std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, sizeof(_eventgroup)); - sender_->send(its_command, sizeof(its_command)); - } else { - std::lock_guard<std::mutex> its_lock(pending_mutex_); - auto it = pending_subscriptions_.begin(); - while (it != pending_subscriptions_.end()) { - if (it->service_ == _service - && it->instance_ == _instance) { - break; - } - it++; + auto its_target = find_local(_service, _instance); + if (its_target) { + its_target->send(its_command, sizeof(its_command)); + } else { + sender_->send(its_command, sizeof(its_command)); } - - if (it != pending_subscriptions_.end()) pending_subscriptions_.erase(it); } -} - -bool routing_manager_proxy::send(client_t its_client, - std::shared_ptr<message> _message, - bool _flush) { - bool is_sent(false); - - std::lock_guard<std::mutex> its_lock(serialize_mutex_); - if (serializer_->serialize(_message.get())) { - is_sent = send(its_client, serializer_->get_data(), - serializer_->get_size(), _message->get_instance(), - _flush, _message->is_reliable()); - serializer_->reset(); - } else { - VSOMEIP_ERROR << "Failed to serialize message. Check message size!"; + std::lock_guard<std::mutex> its_lock(pending_mutex_); + auto it = pending_subscriptions_.begin(); + while (it != pending_subscriptions_.end()) { + if (it->service_ == _service + && it->instance_ == _instance) { + break; + } + it++; } - return (is_sent); + if (it != pending_subscriptions_.end()) pending_subscriptions_.erase(it); } bool routing_manager_proxy::send(client_t _client, const byte_t *_data, length_t _size, instance_t _instance, bool _flush, - bool _reliable) { - bool is_sent(false); - - std::shared_ptr<endpoint> its_target; + bool _reliable, + bool _initial) { + bool is_sent(false); if (_size > VSOMEIP_MESSAGE_TYPE_POS) { + std::shared_ptr<endpoint> its_target; if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + // Request service_t its_service = VSOMEIP_BYTES_TO_WORD( _data[VSOMEIP_SERVICE_POS_MIN], _data[VSOMEIP_SERVICE_POS_MAX]); std::lock_guard<std::mutex> its_lock(send_mutex_); - its_target = find_local(its_service, _instance); - } else { + client_t its_client = find_local_client(its_service, _instance); + if (its_client != VSOMEIP_ROUTING_CLIENT) { + if (known_clients_.find(its_client) != known_clients_.end()) { + its_target = find_or_create_local(its_client); + } + } + } else if (!utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + // Response client_t its_client = VSOMEIP_BYTES_TO_WORD( _data[VSOMEIP_CLIENT_POS_MIN], _data[VSOMEIP_CLIENT_POS_MAX]); std::lock_guard<std::mutex> its_lock(send_mutex_); - its_target = find_local(its_client); + if (its_client != VSOMEIP_ROUTING_CLIENT) { + if (known_clients_.find(its_client) != known_clients_.end()) { + its_target = find_or_create_local(its_client); + } + } + } else if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && + _client == VSOMEIP_ROUTING_CLIENT) { + // notify + send_local_notification(get_client(), _data, _size, + _instance, _flush, _reliable, _initial); + } else if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && + _client != VSOMEIP_ROUTING_CLIENT) { + // notify_one + its_target = find_local(_client); + if (its_target) { + return send_local(its_target, get_client(), _data, _size, + _instance, _flush, _reliable, VSOMEIP_SEND, false, _initial); + } } - - // If no direct endpoint could be found, route to stub - if (!its_target) + // If no direct endpoint could be found/is connected + // or for notifications ~> route to routing_manager_stub + if (!its_target || !its_target->is_connected()) { its_target = sender_; - - std::vector<byte_t> its_command( - VSOMEIP_COMMAND_HEADER_SIZE + _size + sizeof(instance_t) - + sizeof(bool) + sizeof(bool)); - its_command[VSOMEIP_COMMAND_TYPE_POS] - = utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) ? - VSOMEIP_NOTIFY : VSOMEIP_SEND; - - std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, - sizeof(client_t)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &_size, - sizeof(_size)); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], _data, _size); - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size], - &_instance, sizeof(instance_t)); - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size + sizeof(instance_t)] = - _flush; - its_command[VSOMEIP_COMMAND_PAYLOAD_POS + _size + sizeof(instance_t) - + sizeof(bool)] = _reliable; - is_sent = its_target->send(&its_command[0], uint32_t(its_command.size())); + } +#ifdef USE_DLT + else { + uint16_t its_data_size + = uint16_t(_size > USHRT_MAX ? USHRT_MAX : _size); + + tc::trace_header its_header; + if (its_header.prepare(its_target, true)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, its_data_size); + } +#endif + uint8_t command = utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) ? + VSOMEIP_NOTIFY : VSOMEIP_SEND; + if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && _client) { + command = VSOMEIP_NOTIFY_ONE; + } + is_sent = send_local(its_target, _client, _data, _size, _instance, _flush, _reliable, command, false, _initial); } return (is_sent); } @@ -451,44 +524,26 @@ void routing_manager_proxy::notify( its_notification->set_instance(_instance); its_notification->set_method(_event); its_notification->set_payload(_payload); - auto its_service = service_versions_.find(_service); - if (its_service != service_versions_.end()) { - auto its_instance = its_service->second.find(_instance); - if (its_instance != its_service->second.end()) { - its_notification->set_interface_version(its_instance->second); - } + auto service_info = find_service(_service, _instance); + if (service_info) { + its_notification->set_interface_version(service_info->get_major()); } if (is_connected_) { - send(VSOMEIP_ROUTING_CLIENT, its_notification, true); - } else if (is_field(_service, _instance, _event)) { + routing_manager_base::notify(_service, _instance, _event, _payload); + } else if (is_field(_service, _instance, _event)){ std::lock_guard<std::mutex> its_lock(pending_mutex_); pending_notifications_[_service][_instance][_event] = its_notification; } } -void routing_manager_proxy::notify_one(service_t _service, instance_t _instance, - event_t _event, std::shared_ptr<payload> _payload, client_t _client) { - - 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); - its_notification->set_client(_client); - auto its_service = service_versions_.find(_service); - if (its_service != service_versions_.end()) { - auto its_instance = its_service->second.find(_instance); - if (its_instance != its_service->second.end()) { - its_notification->set_interface_version(its_instance->second); - } - } - send(VSOMEIP_ROUTING_CLIENT, its_notification, true); -} - void routing_manager_proxy::on_connect(std::shared_ptr<endpoint> _endpoint) { - is_connected_ = is_connected_ || (_endpoint == sender_); + if (_endpoint != sender_) { + return; + } + is_connected_ = true; if (is_connected_ && is_started_) { + VSOMEIP_DEBUG << std::hex << "Client " << client_ + << " successfully connected to routing ~> registering.."; register_application(); } } @@ -510,10 +565,16 @@ void routing_manager_proxy::on_error(const byte_t *_data, length_t _length, (void)(_receiver); } +void routing_manager_proxy::release_port(uint16_t _port, bool _reliable) { + (void)_port; + (void)_reliable; + // intentionally empty +} void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, - endpoint *_receiver) { + endpoint *_receiver, const boost::asio::ip::address &_destination) { (void)_receiver; + (void)_destination; #if 0 std::stringstream msg; msg << "rmp::on_message: "; @@ -528,7 +589,7 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, instance_t its_instance; eventgroup_t its_eventgroup; major_version_t its_major; - ttl_t its_ttl; + bool subscription_accepted; if (_size > VSOMEIP_COMMAND_SIZE_POS_MAX) { its_command = _data[VSOMEIP_COMMAND_TYPE_POS]; @@ -542,9 +603,9 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, instance_t its_instance; std::memcpy(&its_instance, &_data[_size - sizeof(instance_t) - sizeof(bool) - - sizeof(bool)], sizeof(instance_t)); + - sizeof(bool) - sizeof(bool)], sizeof(instance_t)); bool its_reliable; - std::memcpy(&its_reliable, &_data[_size - sizeof(bool)], + std::memcpy(&its_reliable, &_data[_size - sizeof(bool) - sizeof(bool)], sizeof(its_reliable)); deserializer_->set_data(&_data[VSOMEIP_COMMAND_PAYLOAD_POS], its_length); @@ -553,9 +614,16 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, if (its_message) { its_message->set_instance(its_instance); its_message->set_reliable(its_reliable); + if(its_message->get_message_type() == message_type_e::MT_NOTIFICATION) { + bool its_initial(false); + std::memcpy(&its_initial, &_data[_size - sizeof(bool)], sizeof(its_initial)); + its_message->set_initial(its_initial); + cache_event_payload(its_message); + } host_->on_message(its_message); } else { - VSOMEIP_ERROR << "Deserialization of vSomeIP message failed"; + VSOMEIP_ERROR << "Routing proxy: on_message: " + << "SomeIP-Header deserialization failed!"; } deserializer_->reset(); } @@ -567,6 +635,8 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, case VSOMEIP_PING: send_pong(); + VSOMEIP_TRACE << "PING(" + << std::hex << std::setw(4) << std::setfill('0') << client_ << ")"; break; case VSOMEIP_SUBSCRIBE: @@ -578,10 +648,36 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, sizeof(its_eventgroup)); std::memcpy(&its_major, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], sizeof(its_major)); - std::memcpy(&its_ttl, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7], - sizeof(its_ttl)); + bool is_remote_subscriber; + std::memcpy(&is_remote_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7], + sizeof(is_remote_subscriber)); - host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, true); + if (is_remote_subscriber || known_clients_.find(its_client) != known_clients_.end()) { + subscription_accepted = host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, true); + if (!is_remote_subscriber) { + (void) find_or_create_local(its_client); + if (!subscription_accepted) { + send_subscribe_nack(its_client, its_service, its_instance, its_eventgroup); + } else { + routing_manager_base::subscribe(its_client, its_service, its_instance, its_eventgroup, + its_major, subscription_type_e::SU_RELIABLE_AND_UNRELIABLE); + send_subscribe_ack(its_client, its_service, its_instance, its_eventgroup); + } + } + } else { + if (!is_remote_subscriber) { + eventgroup_data_t subscription = { its_service, its_instance, + its_eventgroup, its_major, + subscription_type_e::SU_RELIABLE_AND_UNRELIABLE}; + pending_ingoing_subscripitons_[its_client].insert(subscription); + } + } + VSOMEIP_DEBUG << "SUBSCRIBE(" + << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << ":" + << std::dec << (uint16_t)its_major << "]"; break; case VSOMEIP_UNSUBSCRIBE: @@ -592,6 +688,44 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size, std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], sizeof(its_eventgroup)); host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, false); + routing_manager_base::unsubscribe(its_client, its_service, its_instance, its_eventgroup); + VSOMEIP_DEBUG << "UNSUBSCRIBE(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "]"; + break; + + case VSOMEIP_SUBSCRIBE_NACK: + std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], + sizeof(its_service)); + std::memcpy(&its_instance, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2], + sizeof(its_instance)); + std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], + sizeof(its_eventgroup)); + + on_subscribe_nack(its_client, its_service, its_instance, its_eventgroup); + VSOMEIP_DEBUG << "SUBSCRIBE NACK(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "]"; + break; + + case VSOMEIP_SUBSCRIBE_ACK: + std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], + sizeof(its_service)); + std::memcpy(&its_instance, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2], + sizeof(its_instance)); + std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], + sizeof(its_eventgroup)); + + on_subscribe_ack(its_client, its_service, its_instance, its_eventgroup); + VSOMEIP_DEBUG << "SUBSCRIBE ACK(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "]"; break; default: @@ -605,16 +739,19 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, #if 0 std::stringstream msg; msg << "rmp::on_routing_info(" << std::hex << client_ << "): "; - for (int i = 0; i < _size; ++i) + for (uint32_t i = 0; i < _size; ++i) msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; VSOMEIP_DEBUG << msg.str(); #endif state_type_e its_state(state_type_e::ST_DEREGISTERED); - std::map<service_t, std::map<instance_t, client_t> > old_local_services; + bool restart_sender(_size == 0); + std::map<service_t, std::map<instance_t, std::tuple< major_version_t, minor_version_t, client_t> > > old_local_services; + std::unordered_set<client_t> clients_to_delete; { std::lock_guard<std::mutex> its_lock(local_services_mutex_); old_local_services = local_services_; local_services_.clear(); + std::unordered_set<client_t> known_clients; uint32_t i = 0; while (i + sizeof(uint32_t) <= _size) { @@ -627,11 +764,10 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, std::memcpy(&its_client, &_data[i], sizeof(client_t)); i += uint32_t(sizeof(client_t)); - if (its_client != client_) { - (void) find_or_create_local(its_client); - } else { + if (its_client == client_) { its_state = state_type_e::ST_REGISTERED; } + known_clients.insert(its_client); uint32_t j = 0; while (j + sizeof(uint32_t) <= its_client_size) { @@ -639,22 +775,29 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, std::memcpy(&its_services_size, &_data[i + j], sizeof(uint32_t)); j += uint32_t(sizeof(uint32_t)); - if (its_services_size >= sizeof(service_t) + sizeof(instance_t)) { + if (its_services_size >= sizeof(service_t) + sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t)) { its_services_size -= uint32_t(sizeof(service_t)); service_t its_service; std::memcpy(&its_service, &_data[i + j], sizeof(service_t)); j += uint32_t(sizeof(service_t)); - while (its_services_size >= sizeof(instance_t)) { + while (its_services_size >= sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t)) { instance_t its_instance; std::memcpy(&its_instance, &_data[i + j], sizeof(instance_t)); j += uint32_t(sizeof(instance_t)); - if (its_client != client_) - local_services_[its_service][its_instance] = its_client; + major_version_t its_major; + std::memcpy(&its_major, &_data[i + j], sizeof(major_version_t)); + j += uint32_t(sizeof(major_version_t)); - its_services_size -= uint32_t(sizeof(instance_t)); + minor_version_t its_minor; + std::memcpy(&its_minor, &_data[i + j], sizeof(minor_version_t)); + j += uint32_t(sizeof(minor_version_t)); + + local_services_[its_service][its_instance] = std::make_tuple(its_major, its_minor, its_client); + + its_services_size -= uint32_t(sizeof(instance_t) + sizeof(major_version_t) + sizeof(minor_version_t) ); } } } @@ -662,10 +805,24 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, i += j; } } + // Which clients are no longer needed?! + for (auto client : get_connected_clients()) { + if (known_clients.find(client) == known_clients.end()) { + clients_to_delete.insert(client); + } + } + known_clients_ = known_clients; } // inform host about its own registration state changes if (state_ != its_state) { + if (its_state == state_type_e::ST_REGISTERED) { + VSOMEIP_INFO << std::hex << "Application/Client " << get_client() + << " is registered."; + } else { + VSOMEIP_INFO << std::hex << "Application/Client " << get_client() + << " is deregistered."; + } host_->on_state(its_state); state_ = its_state; } @@ -677,12 +834,15 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, for (auto j : i.second) { auto found_instance = found_service->second.find(j.first); if (found_instance == found_service->second.end()) { - host_->on_availability(i.first, j.first, false); + auto version_info = j.second; + on_stop_offer_service(i.first, j.first, std::get<0>(version_info), std::get<1>(version_info)); + host_->on_availability(i.first, j.first, false, std::get<0>(version_info), std::get<1>(version_info)); } } } else { for (auto j : i.second) { - host_->on_availability(i.first, j.first, false); + on_stop_offer_service(i.first, j.first, std::get<0>(j.second), std::get<1>(j.second)); + host_->on_availability(i.first, j.first, false, std::get<0>(j.second), std::get<1>(j.second)); } } } @@ -694,15 +854,50 @@ void routing_manager_proxy::on_routing_info(const byte_t *_data, for (auto j : i.second) { auto found_instance = found_service->second.find(j.first); if (found_instance == found_service->second.end()) { - host_->on_availability(i.first, j.first, true); + send_pending_subscriptions(i.first, j.first, std::get<0>(j.second)); + host_->on_availability(i.first, j.first, true, std::get<0>(j.second), std::get<1>(j.second)); } } } else { for (auto j : i.second) { - host_->on_availability(i.first, j.first, true); + send_pending_subscriptions(i.first, j.first, std::get<0>(j.second)); + host_->on_availability(i.first, j.first, true, std::get<0>(j.second), std::get<1>(j.second)); } } } + + for (client_t client : known_clients_) { + auto its_client = pending_ingoing_subscripitons_.find(client); + if (its_client != pending_ingoing_subscripitons_.end()) { + for (auto subscription : its_client->second) { + bool subscription_accepted = host_->on_subscription(subscription.service_, subscription.instance_, subscription.eventgroup_, client, true); + (void) find_or_create_local(client); + if (!subscription_accepted) { + send_subscribe_nack(client, subscription.service_, subscription.instance_, subscription.eventgroup_); + } else { + routing_manager_base::subscribe(client, subscription.service_, subscription.instance_, subscription.eventgroup_, + subscription.major_, subscription_type_e::SU_RELIABLE_AND_UNRELIABLE); + send_subscribe_ack(client, subscription.service_, subscription.instance_, subscription.eventgroup_); + } + } + } + pending_ingoing_subscripitons_.erase(client); + } + + if (clients_to_delete.size() || restart_sender) { + std::async(std::launch::async, [this, clients_to_delete, restart_sender] () { + for (auto client : clients_to_delete) { + if (client != VSOMEIP_ROUTING_CLIENT) { + remove_local(client); + } + } + if (restart_sender && is_started_ && sender_) { + VSOMEIP_INFO << std::hex << "Application/Client " << get_client() + <<": Reconnecting to routing manager."; + sender_->start(); + } + }); + } } void routing_manager_proxy::register_application() { @@ -721,6 +916,7 @@ void routing_manager_proxy::register_application() { send_offer_service(client_, po.service_, po.instance_, po.major_, po.minor_); + std::lock_guard<std::mutex> its_lock(pending_mutex_); for (auto &per : pending_event_registrations_) send_register_event(client_, per.service_, per.instance_, per.event_, per.eventgroups_, @@ -729,7 +925,8 @@ void routing_manager_proxy::register_application() { for (auto &s : pending_notifications_) { for (auto &i : s.second) { for (auto &pn : i.second) { - send(VSOMEIP_ROUTING_CLIENT, pn.second, true); + routing_manager_base::notify(s.first, i.first, + pn.first, pn.second->get_payload()); } } } @@ -738,16 +935,6 @@ void routing_manager_proxy::register_application() { send_request_service(client_, po.service_, po.instance_, po.major_, po.minor_, po.use_exclusive_proxy_); } - - std::lock_guard<std::mutex> its_lock(pending_mutex_); - for (auto &ps : pending_subscriptions_) - send_subscribe(client_, ps.service_, ps.instance_, - ps.eventgroup_, ps.major_, ps.subscription_type_); - - pending_offers_.clear(); - pending_requests_.clear(); - pending_notifications_.clear(); - pending_subscriptions_.clear(); } } @@ -764,75 +951,6 @@ void routing_manager_proxy::deregister_application() { (void)sender_->send(&its_command[0], uint32_t(its_command.size())); } -std::shared_ptr<endpoint> routing_manager_proxy::find_local(client_t _client) { - std::shared_ptr<endpoint> its_endpoint; - auto found_endpoint = local_endpoints_.find(_client); - if (found_endpoint != local_endpoints_.end()) { - its_endpoint = found_endpoint->second; - } - return (its_endpoint); -} - -std::shared_ptr<endpoint> routing_manager_proxy::create_local( - client_t _client) { - std::stringstream its_path; - its_path << VSOMEIP_BASE_PATH << std::hex << _client; - -#ifdef WIN32 - boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1"); - int port = VSOMEIP_INTERNAL_BASE_PORT + _client; - VSOMEIP_DEBUG<< "Connecting to [" - << std::hex << _client << "] at " << port; -#else - VSOMEIP_DEBUG<< "Connecting to [" - << std::hex << _client << "] at " << its_path.str(); -#endif - - std::shared_ptr<endpoint> its_endpoint = std::make_shared< - local_client_endpoint_impl>(shared_from_this(), -#ifdef WIN32 - boost::asio::ip::tcp::endpoint(address, port), -#else - boost::asio::local::stream_protocol::endpoint(its_path.str()), -#endif - io_, configuration_->get_max_message_size_local()); - - local_endpoints_[_client] = its_endpoint; - - return (its_endpoint); -} - -std::shared_ptr<endpoint> routing_manager_proxy::find_or_create_local( - client_t _client) { - std::shared_ptr<endpoint> its_endpoint(find_local(_client)); - if (0 == its_endpoint) { - its_endpoint = create_local(_client); - its_endpoint->start(); - } - return (its_endpoint); -} - -void routing_manager_proxy::remove_local(client_t _client) { - std::shared_ptr<endpoint> its_endpoint(find_local(_client)); - if (its_endpoint) - its_endpoint->stop(); - local_endpoints_.erase(_client); -} - -std::shared_ptr<endpoint> routing_manager_proxy::find_local(service_t _service, - instance_t _instance) { - client_t its_client(0); - std::lock_guard<std::mutex> its_lock(local_services_mutex_); - auto found_service = local_services_.find(_service); - if (found_service != local_services_.end()) { - auto found_instance = found_service->second.find(_instance); - if (found_instance != found_service->second.end()) { - its_client = found_instance->second; - } - } - return (find_local(its_client)); -} - void routing_manager_proxy::send_pong() const { byte_t its_pong[] = { VSOMEIP_PONG, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; @@ -877,6 +995,28 @@ void routing_manager_proxy::send_request_service(client_t _client, service_t _se } } +void routing_manager_proxy::send_release_service(client_t _client, service_t _service, + instance_t _instance) { + (void)_client; + byte_t its_command[VSOMEIP_RELEASE_SERVICE_COMMAND_SIZE]; + uint32_t its_size = VSOMEIP_RELEASE_SERVICE_COMMAND_SIZE + - VSOMEIP_COMMAND_HEADER_SIZE; + + if (is_connected_) { + its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_RELEASE_SERVICE; + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &client_, + sizeof(client_)); + std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, + sizeof(its_size)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, + sizeof(_service)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, + sizeof(_instance)); + + sender_->send(its_command, sizeof(its_command)); + } +} + void routing_manager_proxy::send_register_event(client_t _client, service_t _service, instance_t _instance, event_t _event, const std::set<eventgroup_t> &_eventgroups, @@ -930,4 +1070,97 @@ void routing_manager_proxy::send_register_event(client_t _client, } } +void routing_manager_proxy::on_subscribe_ack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + (void)_client; + host_->on_subscription_error(_service, _instance, _eventgroup, 0x0 /*OK*/); +} + +void routing_manager_proxy::on_subscribe_nack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + (void)_client; + host_->on_subscription_error(_service, _instance, _eventgroup, 0x7 /*Rejected*/); +} + +void routing_manager_proxy::on_identify_response(client_t _client, service_t _service, + instance_t _instance, bool _reliable) { + static const uint32_t size = uint32_t(VSOMEIP_COMMAND_HEADER_SIZE + sizeof(service_t) + sizeof(instance_t) + + sizeof(bool)); + byte_t its_command[size]; + uint32_t its_size = size - VSOMEIP_COMMAND_HEADER_SIZE; + its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_ID_RESPONSE; + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, + sizeof(_client)); + std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, + sizeof(its_size)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, + sizeof(_service)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, + sizeof(_instance)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_reliable, + sizeof(_reliable)); + sender_->send(its_command, size); +} + +bool routing_manager_proxy::queue_message(const byte_t *_data, uint32_t _size) const { + std::shared_ptr<local_server_endpoint_impl> its_server_endpoint + = std::dynamic_pointer_cast<local_server_endpoint_impl>(receiver_); + return its_server_endpoint->queue_message(_data, _size); +} + +void routing_manager_proxy::cache_event_payload( + const std::shared_ptr<message> &_message) { + const service_t its_service(_message->get_service()); + const instance_t its_instance(_message->get_instance()); + const method_t its_method(_message->get_method()); + std::shared_ptr<event> its_event = find_event(its_service, its_instance, its_method); + if (its_event) { + if (its_event->is_field()) { + its_event->set_payload_dont_notify(_message->get_payload()); + } + } else { + // we received a event which was not yet requested + std::set<eventgroup_t> its_eventgroups; + // create a placeholder field until someone requests this event with + // full information like eventgroup, field or not etc. + routing_manager_base::register_event(host_->get_client(), its_service, + its_instance, its_method, its_eventgroups, true, false, false, true); + std::shared_ptr<event> its_event = find_event(its_service, its_instance, its_method); + if (its_event) { + its_event->set_payload_dont_notify(_message->get_payload()); + } + } + +} + +void routing_manager_proxy::send_pending_subscriptions(service_t _service, + instance_t _instance, major_version_t _major) { + for (auto &ps : pending_subscriptions_) { + if (ps.service_ == _service && + ps.instance_ == _instance && ps.major_ == _major) { + send_subscribe(client_, ps.service_, ps.instance_, + ps.eventgroup_, ps.major_, ps.subscription_type_); + } + } +} + +void routing_manager_proxy::on_stop_offer_service(service_t _service, + instance_t _instance, + major_version_t _major, + minor_version_t _minor) { + (void) _major; + (void) _minor; + { + std::lock_guard<std::mutex> its_lock(events_mutex_); + auto its_events_service = events_.find(_service); + if (its_events_service != events_.end()) { + auto its_events_instance = its_events_service->second.find(_instance); + if (its_events_instance != its_events_service->second.end()) { + for (auto &e : its_events_instance->second) + e.second->unset_payload(); + } + } + } +} + } // namespace vsomeip diff --git a/implementation/routing/src/routing_manager_stub.cpp b/implementation/routing/src/routing_manager_stub.cpp index 7f8aad8..01ca85a 100644 --- a/implementation/routing/src/routing_manager_stub.cpp +++ b/implementation/routing/src/routing_manager_stub.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -6,7 +6,12 @@ #include <chrono> #include <functional> #include <iomanip> -#include <iostream> + +#ifndef WIN32 +// for umask +#include <sys/types.h> +#include <sys/stat.h> +#endif #include <boost/system/error_code.hpp> @@ -21,6 +26,7 @@ #include "../../endpoints/include/local_server_endpoint_impl.hpp" #include "../../logging/include/logger.hpp" #include "../../utility/include/byteorder.hpp" +#include "../../utility/include/utility.hpp" namespace vsomeip { @@ -30,7 +36,8 @@ routing_manager_stub::routing_manager_stub( host_(_host), io_(_host->get_io()), watchdog_timer_(_host->get_io()), - configuration_(_configuration) { + configuration_(_configuration), + routingCommandSize_(VSOMEIP_ROUTING_INFO_SIZE_INIT) { } routing_manager_stub::~routing_manager_stub() { @@ -40,13 +47,21 @@ void routing_manager_stub::init() { std::stringstream its_endpoint_path; its_endpoint_path << VSOMEIP_BASE_PATH << VSOMEIP_ROUTING_CLIENT; endpoint_path_ = its_endpoint_path.str(); + + std::stringstream its_local_receiver_path; + its_local_receiver_path << VSOMEIP_BASE_PATH << std::hex << host_->get_client(); + local_receiver_path_ = its_local_receiver_path.str(); #if WIN32 ::_unlink(endpoint_path_.c_str()); + ::_unlink(local_receiver_path_.c_str()); int port = VSOMEIP_INTERNAL_BASE_PORT; VSOMEIP_DEBUG << "Routing endpoint at " << port; #else ::unlink(endpoint_path_.c_str()); + ::unlink(local_receiver_path_.c_str()); VSOMEIP_DEBUG << "Routing endpoint at " << endpoint_path_; + + const mode_t previous_mask(::umask(static_cast<mode_t>(configuration_->get_umask()))); #endif endpoint_ = @@ -58,23 +73,62 @@ void routing_manager_stub::init() { boost::asio::local::stream_protocol::endpoint(endpoint_path_), #endif io_, configuration_->get_max_message_size_local()); + + local_receiver_ = + std::make_shared < local_server_endpoint_impl + > (shared_from_this(), + #ifdef WIN32 + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port + host_->get_client()), + #else + boost::asio::local::stream_protocol::endpoint(local_receiver_path_), + #endif + io_, configuration_->get_max_message_size_local()); + +#ifndef WIN32 + ::umask(previous_mask); +#endif } void routing_manager_stub::start() { endpoint_->start(); - - // Start watchdog (TODO: only if configured) - start_watchdog(); + local_receiver_->start(); + + client_registration_running_ = true; + client_registration_thread_ = std::make_shared<std::thread>( + std::bind(&routing_manager_stub::client_registration_func, this)); + + if (configuration_->is_watchdog_enabled()) { + VSOMEIP_INFO << "Watchdog is enabled : Timeout in ms = " + << configuration_->get_watchdog_timeout() + << " : Allowed missing pongs = " + << configuration_->get_allowed_missing_pongs() + << "."; + start_watchdog(); + } else { + VSOMEIP_INFO << "Watchdog is disabled!"; + } } void routing_manager_stub::stop() { + client_registration_running_ = false; + client_registration_condition_.notify_one(); + if (client_registration_thread_->joinable()) { + client_registration_thread_->join(); + } + watchdog_timer_.cancel(); endpoint_->stop(); + local_receiver_->stop(); + #ifdef WIN32 ::_unlink(endpoint_path_.c_str()); + ::_unlink(local_receiver_path_.c_str()); #else ::unlink(endpoint_path_.c_str()); + ::unlink(local_receiver_path_.c_str()); #endif + + broadcast_routing_info(true); } void routing_manager_stub::on_connect(std::shared_ptr<endpoint> _endpoint) { @@ -95,15 +149,22 @@ void routing_manager_stub::on_error(const byte_t *_data, length_t _length, (void)(_receiver); } +void routing_manager_stub::release_port(uint16_t _port, bool _reliable) { + (void)_port; + (void)_reliable; + // intentionally empty +} + void routing_manager_stub::on_message(const byte_t *_data, length_t _size, - endpoint *_receiver) { + endpoint *_receiver, const boost::asio::ip::address &_destination) { (void)_receiver; + (void)_destination; #if 0 std::stringstream msg; msg << "rms::on_message: "; for (length_t i = 0; i < _size; ++i) msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; - VSOMEIP_DEBUG << msg.str(); + VSOMEIP_INFO << msg.str(); #endif if (VSOMEIP_COMMAND_SIZE_POS_MAX < _size) { @@ -125,6 +186,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, bool its_reliable(false); bool use_exclusive_proxy(false); subscription_type_e its_subscription_type; + bool is_remote_subscriber(false); its_command = _data[VSOMEIP_COMMAND_TYPE_POS]; std::memcpy(&its_client, &_data[VSOMEIP_COMMAND_CLIENT_POS], @@ -136,21 +198,31 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, if (its_size <= _size - VSOMEIP_COMMAND_HEADER_SIZE) { switch (its_command) { case VSOMEIP_REGISTER_APPLICATION: - on_register_application(its_client); - VSOMEIP_DEBUG << "Application/Client " + { + std::lock_guard<std::mutex> its_lock(client_registration_mutex_); + VSOMEIP_INFO << "Application/Client " << std::hex << std::setw(4) << std::setfill('0') - << its_client << " got registered!"; + << its_client << " is registering."; + pending_client_registrations_[its_client].push_back(true); + client_registration_condition_.notify_one(); + } break; case VSOMEIP_DEREGISTER_APPLICATION: - on_deregister_application(its_client); - VSOMEIP_DEBUG << "Application/Client " - << std::hex << std::setw(4) << std::setfill('0') - << its_client << " got deregistered!"; + { + std::lock_guard<std::mutex> its_lock(client_registration_mutex_); + VSOMEIP_INFO << "Application/Client " + << std::hex << std::setw(4) << std::setfill('0') + << its_client << " is deregistering."; + pending_client_registrations_[its_client].push_back(false); + client_registration_condition_.notify_one(); + } break; case VSOMEIP_PONG: on_pong(its_client); + VSOMEIP_TRACE << "PONG(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << ")"; break; case VSOMEIP_OFFER_SERVICE: @@ -165,7 +237,11 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, sizeof(its_minor)); host_->offer_service(its_client, its_service, its_instance, its_major, its_minor); - on_offer_service(its_client, its_service, its_instance); + VSOMEIP_DEBUG << "OFFER(" + << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance + << ":" << std::dec << int(its_major) << "." << std::dec << its_minor << "]"; break; case VSOMEIP_STOP_OFFER_SERVICE: @@ -174,8 +250,18 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, std::memcpy(&its_instance, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2], sizeof(its_instance)); - host_->stop_offer_service(its_client, its_service, its_instance); - on_stop_offer_service(its_client, its_service, its_instance); + + std::memcpy(&its_major, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], + sizeof(its_major)); + std::memcpy(&its_minor, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 5], + sizeof(its_minor)); + + host_->stop_offer_service(its_client, its_service, its_instance, its_major, its_minor); + VSOMEIP_DEBUG << "STOP OFFER(" + << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance + << ":" << std::dec << int(its_major) << "." << its_minor << "]"; break; case VSOMEIP_SUBSCRIBE: @@ -187,10 +273,18 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, sizeof(its_eventgroup)); std::memcpy(&its_major, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], sizeof(its_major)); - std::memcpy(&its_subscription_type, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7], + std::memcpy(&is_remote_subscriber, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 7], + sizeof(is_remote_subscriber)); + std::memcpy(&its_subscription_type, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 8], sizeof(its_subscription_type)); host_->subscribe(its_client, its_service, its_instance, its_eventgroup, its_major, its_subscription_type); + VSOMEIP_DEBUG << "SUBSCRIBE(" + << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << ":" + << std::dec << (uint16_t)its_major << "]"; break; case VSOMEIP_UNSUBSCRIBE: @@ -202,6 +296,41 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, sizeof(its_eventgroup)); host_->unsubscribe(its_client, its_service, its_instance, its_eventgroup); + VSOMEIP_DEBUG << "UNSUBSCRIBE(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "]"; + break; + + case VSOMEIP_SUBSCRIBE_ACK: + std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], + sizeof(its_service)); + std::memcpy(&its_instance, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2], + sizeof(its_instance)); + std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], + sizeof(its_eventgroup)); + host_->on_subscribe_ack(its_client, its_service, its_instance, its_eventgroup); + VSOMEIP_DEBUG << "SUBSCRIBE ACK(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "]"; + break; + + case VSOMEIP_SUBSCRIBE_NACK: + std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], + sizeof(its_service)); + std::memcpy(&its_instance, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2], + sizeof(its_instance)); + std::memcpy(&its_eventgroup, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], + sizeof(its_eventgroup)); + host_->on_subscribe_nack(its_client, its_service, its_instance, its_eventgroup); + VSOMEIP_DEBUG << "SUBSCRIBE NACK(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup << "]"; break; case VSOMEIP_SEND: @@ -209,8 +338,11 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, its_service = VSOMEIP_BYTES_TO_WORD( its_data[VSOMEIP_SERVICE_POS_MIN], its_data[VSOMEIP_SERVICE_POS_MAX]); - std::memcpy(&its_instance, &_data[_size - 4], sizeof(its_instance)); - std::memcpy(&its_reliable, &_data[_size - 1], sizeof(its_reliable)); + std::memcpy(&its_instance, &_data[_size - sizeof(instance_t) + - sizeof(bool) - sizeof(bool) + - sizeof(bool)], sizeof(its_instance)); + std::memcpy(&its_reliable, &_data[_size - sizeof(bool) + - sizeof(bool)], sizeof(its_reliable)); host_->on_message(its_service, its_instance, its_data, its_size, its_reliable); break; @@ -219,9 +351,24 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, its_service = VSOMEIP_BYTES_TO_WORD( its_data[VSOMEIP_SERVICE_POS_MIN], its_data[VSOMEIP_SERVICE_POS_MAX]); - std::memcpy(&its_instance, &_data[_size - 4], sizeof(its_instance)); + its_client = VSOMEIP_BYTES_TO_WORD( + its_data[VSOMEIP_CLIENT_POS_MIN], + its_data[VSOMEIP_CLIENT_POS_MAX]); + std::memcpy(&its_instance, &_data[_size - sizeof(instance_t) + - sizeof(bool) - sizeof(bool) + - sizeof(bool)], sizeof(its_instance)); host_->on_notification(its_client, its_service, its_instance, its_data, its_size); break; + case VSOMEIP_NOTIFY_ONE: + its_data = &_data[VSOMEIP_COMMAND_PAYLOAD_POS]; + its_service = VSOMEIP_BYTES_TO_WORD( + its_data[VSOMEIP_SERVICE_POS_MIN], + its_data[VSOMEIP_SERVICE_POS_MAX]); + std::memcpy(&its_instance, &_data[_size - sizeof(instance_t) + - sizeof(bool) - sizeof(bool) + - sizeof(bool)], sizeof(its_instance)); + host_->on_notification(its_client, its_service, its_instance, its_data, its_size, true); + break; case VSOMEIP_REQUEST_SERVICE: std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], @@ -237,10 +384,24 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, sizeof(use_exclusive_proxy)); host_->request_service(its_client, its_service, its_instance, its_major, its_minor, use_exclusive_proxy); + VSOMEIP_DEBUG << "REQUEST(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << ":" + << std::dec << int(its_major) << "." << std::dec << its_minor << "]"; break; - case VSOMEIP_RELEASE_SERVICE: + std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], + sizeof(its_service)); + std::memcpy(&its_instance, + &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2], + sizeof(its_instance)); + host_->release_service(its_client, its_service, its_instance); + VSOMEIP_DEBUG << "RELEASE(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "]"; break; case VSOMEIP_REGISTER_EVENT: @@ -265,9 +426,15 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, sizeof(its_eventgroup)); its_eventgroups.insert(its_eventgroup); } - host_->register_event(its_client, its_service, + host_->register_shadow_event(its_client, its_service, its_instance, its_event, its_eventgroups, is_field, is_provided); + VSOMEIP_DEBUG << "REGISTER EVENT(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_event + << ":is_provider=" << is_provided << "]"; break; case VSOMEIP_UNREGISTER_EVENT: @@ -281,8 +448,31 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, std::memcpy(&is_provided, &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 6], sizeof(is_provided)); - host_->unregister_event(its_client, its_service, its_instance, + host_->unregister_shadow_event(its_client, its_service, its_instance, its_event, is_provided); + VSOMEIP_DEBUG << "UNREGISTER EVENT(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_event + << ":is_provider=" << is_provided << "]"; + break; + + case VSOMEIP_ID_RESPONSE: + std::memcpy(&its_service, &_data[VSOMEIP_COMMAND_PAYLOAD_POS], + sizeof(its_service)); + std::memcpy(&its_instance, + &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 2], + sizeof(its_instance)); + std::memcpy(&its_reliable, + &_data[VSOMEIP_COMMAND_PAYLOAD_POS + 4], + sizeof(its_reliable)); + host_->on_identify_response(its_client, its_service, its_instance, its_reliable); + VSOMEIP_TRACE << "ID RESPONSE(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << "): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance + << ":is_reliable=" << its_reliable << "]"; break; } } @@ -290,10 +480,15 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size, } void routing_manager_stub::on_register_application(client_t _client) { - std::lock_guard<std::mutex> its_guard(routing_info_mutex_); - (void)host_->find_or_create_local(_client); - routing_info_[_client].first = 0; - broadcast_routing_info(); + auto endpoint = host_->find_local(_client); + if (endpoint) { + VSOMEIP_ERROR << "Registering application: " << std::hex << _client + << " failed. It is already registered!"; + } else { + (void)host_->find_or_create_local(_client); + std::lock_guard<std::mutex> its_lock(routing_info_mutex_); + routing_info_[_client].first = 0; + } } void routing_manager_stub::on_deregister_application(client_t _client) { @@ -302,29 +497,59 @@ void routing_manager_stub::on_deregister_application(client_t _client) { if (its_info != routing_info_.end()) { for (auto &its_service : its_info->second.second) { for (auto &its_instance : its_service.second) { + auto its_version = its_instance.second; routing_info_mutex_.unlock(); - host_->on_stop_offer_service(its_service.first, its_instance); + host_->on_stop_offer_service(its_service.first, its_instance.first, its_version.first, its_version.second); routing_info_mutex_.lock(); } } } + routing_info_.erase(_client); routing_info_mutex_.unlock(); - - std::lock_guard<std::mutex> its_lock(routing_info_mutex_); host_->remove_local(_client); - routing_info_.erase(_client); - broadcast_routing_info(); } +void routing_manager_stub::client_registration_func(void) { + std::unique_lock<std::mutex> its_lock(client_registration_mutex_); + while (client_registration_running_) { + while (!pending_client_registrations_.size() && client_registration_running_) { + client_registration_condition_.wait(its_lock); + } + + std::map<client_t, std::vector<bool>> its_registrations( + pending_client_registrations_); + pending_client_registrations_.clear(); + its_lock.unlock(); + + for (auto r : its_registrations) { + for (auto b : r.second) { + if (b) { + on_register_application(r.first); + } else { + on_deregister_application(r.first); + } + } + } + + { + std::lock_guard<std::mutex> its_guard(routing_info_mutex_); + broadcast_routing_info(); + } + + its_lock.lock(); + } +} + + void routing_manager_stub::on_offer_service(client_t _client, - service_t _service, instance_t _instance) { + service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) { std::lock_guard<std::mutex> its_guard(routing_info_mutex_); - routing_info_[_client].second[_service].insert(_instance); + routing_info_[_client].second[_service][_instance] = std::make_pair(_major, _minor); broadcast_routing_info(); } void routing_manager_stub::on_stop_offer_service(client_t _client, - service_t _service, instance_t _instance) { + service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) { std::lock_guard<std::mutex> its_guard(routing_info_mutex_); auto found_client = routing_info_.find(_client); if (found_client != routing_info_.end()) { @@ -332,83 +557,138 @@ void routing_manager_stub::on_stop_offer_service(client_t _client, if (found_service != found_client->second.second.end()) { auto found_instance = found_service->second.find(_instance); if (found_instance != found_service->second.end()) { - found_service->second.erase(_instance); - if (0 == found_service->second.size()) { - found_client->second.second.erase(_service); + auto found_version = found_instance->second; + if( _major == found_version.first && _minor == found_version.second) { + found_service->second.erase(_instance); + if (0 == found_service->second.size()) { + found_client->second.second.erase(_service); + } + broadcast_routing_info(); + } else if( _major == DEFAULT_MAJOR && _minor == DEFAULT_MINOR) { + found_service->second.erase(_instance); + if (0 == found_service->second.size()) { + found_client->second.second.erase(_service); + } + broadcast_routing_info(); } - broadcast_routing_info(); } } } } -void routing_manager_stub::send_routing_info(client_t _client) { +void routing_manager_stub::send_routing_info(client_t _client, bool _empty) { std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); if (its_endpoint) { - uint32_t its_capacity = 4096; // TODO: dynamic resizing - std::vector<byte_t> its_command(its_capacity); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_ROUTING_INFO; - std::memset(&its_command[VSOMEIP_COMMAND_CLIENT_POS], 0, - sizeof(client_t)); - uint32_t its_size = VSOMEIP_COMMAND_PAYLOAD_POS; - - for (auto &info : routing_info_) { - uint32_t its_size_pos = its_size; - uint32_t its_entry_size = its_size; + // Create the command vector & reserve some bytes initially.. + // ..to avoid reallocation for smaller messages! + std::vector<byte_t> its_command; + its_command.reserve(routingCommandSize_); + + // Routing command + its_command.push_back(VSOMEIP_ROUTING_INFO); + + // Sender client + client_t client = 0x0; + for (uint32_t i = 0; i < sizeof(client_t); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&client)[i]); + } - its_size += uint32_t(sizeof(uint32_t)); // placeholder + // Overall size placeholder + byte_t size_placeholder = 0x0; + for (uint32_t i = 0; i < sizeof(uint32_t); ++i) { + its_command.push_back(size_placeholder); + } - if (info.first != host_->get_client()) { - std::memcpy(&its_command[its_size], &info.first, sizeof(client_t)); - } else { - std::memset(&its_command[its_size], 0x0, sizeof(client_t)); + // Routing info loop + for (auto &info : routing_info_) { + if (_empty) { + break; } - - its_size += uint32_t(sizeof(client_t)); - + std::size_t its_size_pos = its_command.size(); + std::size_t its_entry_size = its_command.size(); + // Client size placeholder + byte_t placeholder = 0x0; + for (uint32_t i = 0; i < sizeof(uint32_t); ++i) { + its_command.push_back(placeholder); + } + // Client + for (uint32_t i = 0; i < sizeof(client_t); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&info.first)[i]); + } + // Iterate over all services for (auto &service : info.second.second) { + // Service entry size uint32_t its_service_entry_size = uint32_t(sizeof(service_t) - + service.second.size() * sizeof(instance_t)); - - std::memcpy(&its_command[its_size], &its_service_entry_size, - sizeof(uint32_t)); - its_size += uint32_t(sizeof(uint32_t)); - - std::memcpy(&its_command[its_size], &service.first, - sizeof(service_t)); - its_size += uint32_t(sizeof(service_t)); - + + service.second.size() * (sizeof(instance_t) + + sizeof(major_version_t) + sizeof(minor_version_t))); + for (uint32_t i = 0; i < sizeof(its_service_entry_size); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&its_service_entry_size)[i]); + } + // Service + for (uint32_t i = 0; i < sizeof(service_t); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&service.first)[i]); + } + // Iterate over all instances for (auto &instance : service.second) { - std::memcpy(&its_command[its_size], &instance, - sizeof(instance_t)); - its_size += uint32_t(sizeof(instance_t)); + // Instance + for (uint32_t i = 0; i < sizeof(instance_t); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&instance)[i]); + } + // Major version + for (uint32_t i = 0; i < sizeof(major_version_t); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&instance.second.first)[i]); + } + // Minor version + for (uint32_t i = 0; i < sizeof(minor_version_t); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&instance.second.second)[i]); + } } } - - its_entry_size = its_size - its_entry_size - uint32_t(sizeof(uint32_t)); - std::memcpy(&its_command[its_size_pos], &its_entry_size, - sizeof(uint32_t)); + // File client size + its_entry_size = its_command.size() - its_entry_size - uint32_t(sizeof(uint32_t)); + std::memcpy(&its_command[its_size_pos], &its_entry_size, sizeof(uint32_t)); } - its_size -= VSOMEIP_COMMAND_PAYLOAD_POS; - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(its_size)); + // File overall size + std::size_t its_size = its_command.size() - VSOMEIP_COMMAND_PAYLOAD_POS; + std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, sizeof(uint32_t)); its_size += VSOMEIP_COMMAND_PAYLOAD_POS; + + // Double init size until it fits into the actual size for next run + size_t newInitSize; + for (newInitSize = VSOMEIP_ROUTING_INFO_SIZE_INIT; + newInitSize < its_size; newInitSize *= 2); + routingCommandSize_ = newInitSize; + #if 0 std::stringstream msg; msg << "rms::send_routing_info "; - for (int i = 0; i < its_size; ++i) + for (uint32_t i = 0; i < its_size; ++i) msg << std::hex << std::setw(2) << std::setfill('0') << (int)its_command[i] << " "; VSOMEIP_DEBUG << msg.str(); #endif - its_endpoint->send(&its_command[0], its_size, true); + + // Send routing info or error! + if(its_command.size() <= VSOMEIP_MAX_LOCAL_MESSAGE_SIZE) { + its_endpoint->send(&its_command[0], uint32_t(its_size), true); + } else { + VSOMEIP_ERROR << "Routing info exceeds maximum message size: Can't send!"; + } } } -void routing_manager_stub::broadcast_routing_info() { +void routing_manager_stub::broadcast_routing_info(bool _empty) { for (auto& info : routing_info_) { - if (info.first != VSOMEIP_ROUTING_CLIENT) - send_routing_info(info.first); + if (info.first != VSOMEIP_ROUTING_CLIENT) { + send_routing_info(info.first, _empty); + } } } @@ -425,6 +705,104 @@ void routing_manager_stub::broadcast(std::vector<byte_t> &_command) const { } } +void routing_manager_stub::send_subscribe(std::shared_ptr<vsomeip::endpoint> _target, + client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, bool _is_remote_subscriber) { + if (_target) { + byte_t its_command[VSOMEIP_SUBSCRIBE_COMMAND_SIZE]; + uint32_t its_size = VSOMEIP_SUBSCRIBE_COMMAND_SIZE + - VSOMEIP_COMMAND_HEADER_SIZE; + its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE; + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, + sizeof(_client)); + std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, + sizeof(its_size)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, + sizeof(_service)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, + sizeof(_instance)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, + sizeof(_eventgroup)); + its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 6] = _major; + its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 7] = _is_remote_subscriber; + + _target->send(its_command, sizeof(its_command)); + } +} + +void routing_manager_stub::send_unsubscribe(std::shared_ptr<vsomeip::endpoint> _target, + client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup) { + if (_target) { + byte_t its_command[VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE]; + uint32_t its_size = VSOMEIP_UNSUBSCRIBE_COMMAND_SIZE + - VSOMEIP_COMMAND_HEADER_SIZE; + its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_UNSUBSCRIBE; + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, + sizeof(_client)); + std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, + sizeof(its_size)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, + sizeof(_service)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, + sizeof(_instance)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, + sizeof(_eventgroup)); + + _target->send(its_command, sizeof(its_command)); + } +} + +void routing_manager_stub::send_subscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup) { + + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) { + byte_t its_command[VSOMEIP_SUBSCRIBE_COMMAND_SIZE]; + uint32_t its_size = VSOMEIP_SUBSCRIBE_COMMAND_SIZE + - VSOMEIP_COMMAND_HEADER_SIZE; + + its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_ACK; + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, + sizeof(_client)); + std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, + sizeof(its_size)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, + sizeof(_service)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, + sizeof(_instance)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, + sizeof(_eventgroup)); + + its_endpoint->send(&its_command[0], sizeof(its_command), true); + } +} + +void routing_manager_stub::send_subscribe_nack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup) { + + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) { + byte_t its_command[VSOMEIP_SUBSCRIBE_COMMAND_SIZE]; + uint32_t its_size = VSOMEIP_SUBSCRIBE_COMMAND_SIZE + - VSOMEIP_COMMAND_HEADER_SIZE; + + its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_SUBSCRIBE_NACK; + std::memcpy(&its_command[VSOMEIP_COMMAND_CLIENT_POS], &_client, + sizeof(_client)); + std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, + sizeof(its_size)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS], &_service, + sizeof(_service)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 2], &_instance, + sizeof(_instance)); + std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + 4], &_eventgroup, + sizeof(_eventgroup)); + + its_endpoint->send(&its_command[0], sizeof(its_command), true); + } +} + // Watchdog void routing_manager_stub::broadcast_ping() const { const byte_t its_ping[] = { @@ -445,8 +823,9 @@ void routing_manager_stub::on_pong(client_t _client) { } void routing_manager_stub::start_watchdog() { + // Divide / 2 as start and check sleep each watchdog_timer_.expires_from_now( - std::chrono::milliseconds(VSOMEIP_DEFAULT_WATCHDOG_CYCLE)); // TODO: use config variable + std::chrono::milliseconds(configuration_->get_watchdog_timeout() / 2)); std::function<void(boost::system::error_code const &)> its_callback = [this](boost::system::error_code const &_error) { @@ -467,7 +846,7 @@ void routing_manager_stub::check_watchdog() { broadcast_ping(); watchdog_timer_.expires_from_now( - std::chrono::milliseconds(VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT)); // TODO: use config variable + std::chrono::milliseconds(configuration_->get_watchdog_timeout() / 2)); std::function<void(boost::system::error_code const &)> its_callback = [this](boost::system::error_code const &_error) { @@ -477,42 +856,27 @@ void routing_manager_stub::check_watchdog() { std::lock_guard<std::mutex> its_lock(routing_info_mutex_); for (auto i : routing_info_) { if (i.first > 0 && i.first != host_->get_client()) { - if (i.second.first > VSOMEIP_DEFAULT_MAX_MISSING_PONGS) { // TODO: use config variable + if (i.second.first > configuration_->get_allowed_missing_pongs()) { VSOMEIP_WARNING << "Lost contact to application " << std::hex << (int)i.first; lost.push_back(i.first); } } } - - for (auto i : lost) { - routing_info_.erase(i); - } } - if (0 < lost.size()) - send_application_lost(lost); - + for (auto i : lost) { + utility::release_client_id(i); + on_deregister_application(i); + } start_watchdog(); }; watchdog_timer_.async_wait(its_callback); } -void routing_manager_stub::send_application_lost(std::list<client_t> &_lost) { - uint32_t its_size = uint32_t(_lost.size() * sizeof(client_t)); - std::vector<byte_t> its_command(VSOMEIP_COMMAND_HEADER_SIZE + its_size); - its_command[VSOMEIP_COMMAND_TYPE_POS] = VSOMEIP_APPLICATION_LOST; - std::memset(&its_command[VSOMEIP_COMMAND_CLIENT_POS], 0, sizeof(client_t)); - std::memcpy(&its_command[VSOMEIP_COMMAND_SIZE_POS_MIN], &its_size, - sizeof(uint32_t)); - - uint32_t its_offset = 0; - for (auto i : _lost) { - std::memcpy(&its_command[VSOMEIP_COMMAND_PAYLOAD_POS + its_offset], &i, - sizeof(client_t)); - its_offset += uint32_t(sizeof(client_t)); - } - - broadcast(its_command); +bool routing_manager_stub::queue_message(const byte_t *_data, uint32_t _size) { + std::shared_ptr<local_server_endpoint_impl> its_server_endpoint + = std::dynamic_pointer_cast<local_server_endpoint_impl>(endpoint_); + return its_server_endpoint->queue_message(_data, _size); } } // namespace vsomeip diff --git a/implementation/routing/src/serviceinfo.cpp b/implementation/routing/src/serviceinfo.cpp index 75d11dd..fcf535e 100644 --- a/implementation/routing/src/serviceinfo.cpp +++ b/implementation/routing/src/serviceinfo.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -12,11 +12,13 @@ serviceinfo::serviceinfo(major_version_t _major, minor_version_t _minor, : group_(0), major_(_major), minor_(_minor), - ttl_(_ttl), + ttl_(0), reliable_(nullptr), unreliable_(nullptr), - multicast_group_(0xFFFF), is_local_(_is_local) { + + std::chrono::seconds ttl = static_cast<std::chrono::seconds> (_ttl); + ttl_ = std::chrono::duration_cast<std::chrono::milliseconds>(ttl); } serviceinfo::~serviceinfo() { @@ -39,11 +41,21 @@ minor_version_t serviceinfo::get_minor() const { } ttl_t serviceinfo::get_ttl() const { - return ttl_; + ttl_t ttl = static_cast<ttl_t>(std::chrono::duration_cast<std::chrono::seconds>(ttl_).count()); + return ttl; } void serviceinfo::set_ttl(ttl_t _ttl) { - ttl_ = _ttl; + std::chrono::seconds ttl = static_cast<std::chrono::seconds>(_ttl); + ttl_ = std::chrono::duration_cast<std::chrono::milliseconds> (ttl); +} + +std::chrono::milliseconds serviceinfo::get_precise_ttl() const { + return ttl_; +} + +void serviceinfo::set_precise_ttl(std::chrono::milliseconds _precise_ttl) { + ttl_ = _precise_ttl; } std::shared_ptr<endpoint> serviceinfo::get_endpoint(bool _reliable) const { @@ -59,30 +71,6 @@ void serviceinfo::set_endpoint(std::shared_ptr<endpoint> _endpoint, } } -const std::string & serviceinfo::get_multicast_address() const { - return multicast_address_; -} - -void serviceinfo::set_multicast_address(const std::string &_multicast_address) { - multicast_address_ = _multicast_address; -} - -uint16_t serviceinfo::get_multicast_port() const { - return multicast_port_; -} - -void serviceinfo::set_multicast_port(uint16_t _multicast_port) { - multicast_port_ = _multicast_port; -} - -eventgroup_t serviceinfo::get_multicast_group() const { - return multicast_group_; -} - -void serviceinfo::set_multicast_group(eventgroup_t _multicast_group) { - multicast_group_ = _multicast_group; -} - void serviceinfo::add_client(client_t _client) { requesters_.insert(_client); } @@ -91,6 +79,10 @@ void serviceinfo::remove_client(client_t _client) { requesters_.erase(_client); } +uint32_t serviceinfo::get_requesters_size() { + return static_cast<std::uint32_t>(requesters_.size()); +} + bool serviceinfo::is_local() const { return is_local_; } diff --git a/implementation/runtime/include/application_impl.hpp b/implementation/runtime/include/application_impl.hpp index fea635e..06f60eb 100644 --- a/implementation/runtime/include/application_impl.hpp +++ b/implementation/runtime/include/application_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -17,6 +17,7 @@ #include <vector> #include <boost/asio/signal_set.hpp> +#include <boost/asio/system_timer.hpp> #include <vsomeip/export.hpp> #include <vsomeip/application.hpp> @@ -47,8 +48,8 @@ public: VSOMEIP_EXPORT void offer_service(service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor); - VSOMEIP_EXPORT void stop_offer_service(service_t _service, - instance_t _instance); + VSOMEIP_EXPORT void stop_offer_service(service_t _service, instance_t _instance, + major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR); VSOMEIP_EXPORT void offer_event(service_t _service, instance_t _instance, event_t _event, @@ -73,12 +74,13 @@ public: VSOMEIP_EXPORT void subscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, - subscription_type_e _subscription_type); + subscription_type_e _subscription_type, event_t _event); VSOMEIP_EXPORT void unsubscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup); - VSOMEIP_EXPORT bool is_available(service_t _service, instance_t _instance) const; + VSOMEIP_EXPORT bool is_available(service_t _service, instance_t _instance, + major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR) const; VSOMEIP_EXPORT void send(std::shared_ptr<message> _message, bool _flush); @@ -97,15 +99,25 @@ public: instance_t _instance, method_t _method); VSOMEIP_EXPORT void register_availability_handler(service_t _service, - instance_t _instance, availability_handler_t _handler); + instance_t _instance, availability_handler_t _handler, + major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR); VSOMEIP_EXPORT void unregister_availability_handler(service_t _service, - instance_t _instance); + instance_t _instance, + major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR); VSOMEIP_EXPORT void register_subscription_handler(service_t _service, instance_t _instance, eventgroup_t _eventgroup, subscription_handler_t _handler); VSOMEIP_EXPORT void unregister_subscription_handler(service_t _service, instance_t _instance, eventgroup_t _eventgroup); + VSOMEIP_EXPORT void register_subscription_error_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + error_handler_t _handler); + VSOMEIP_EXPORT void unregister_subscription_error_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + VSOMEIP_EXPORT bool is_routing() const; + // routing_manager_host VSOMEIP_EXPORT const std::string & get_name() const; VSOMEIP_EXPORT client_t get_client() const; @@ -114,16 +126,34 @@ public: VSOMEIP_EXPORT void on_state(state_type_e _state); VSOMEIP_EXPORT void on_availability(service_t _service, instance_t _instance, - bool _is_available) const; + bool _is_available, major_version_t _major, minor_version_t _minor); VSOMEIP_EXPORT void on_message(std::shared_ptr<message> _message); VSOMEIP_EXPORT void on_error(error_code_e _error); VSOMEIP_EXPORT bool on_subscription(service_t _service, instance_t _instance, eventgroup_t _eventgroup, client_t _client, bool _subscribed); + VSOMEIP_EXPORT void on_subscription_error(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, uint16_t _error); // service_discovery_host VSOMEIP_EXPORT routing_manager * get_routing_manager() const; private: + // + // Types + // + struct sync_handler { + + sync_handler(std::function<void()> _handler) : + handler_(_handler), + is_dispatching_(false) { } + + std::function<void()> handler_; + bool is_dispatching_; + }; + + // + // Methods + // void service(); inline void update_session() { session_++; @@ -132,10 +162,36 @@ private: } } + bool is_available_unlocked(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const; + + typedef std::map<service_t, std::map<instance_t, std::map<major_version_t, minor_version_t >>> available_t; + bool are_available(available_t &_available, + service_t _service = ANY_SERVICE, instance_t _instance = ANY_INSTANCE, + major_version_t _major = ANY_MAJOR, minor_version_t _minor = ANY_MINOR) const; + bool are_available_unlocked(available_t &_available, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const; + void do_register_availability_handler(service_t _service, + instance_t _instance, availability_handler_t _handler, + major_version_t _major, minor_version_t _minor); + + + void main_dispatch(); void dispatch(); + void invoke_handler(std::shared_ptr<sync_handler> &_handler); + bool is_active_dispatcher(std::thread::id &_id); + void remove_elapsed_dispatchers(); + + void clear_all_handler(); void wait_for_stop(); -private: + void send_back_cached_event(service_t _service, instance_t _instance, event_t _event); + void send_back_cached_eventgroup(service_t _service, instance_t _instance, eventgroup_t _eventgroup); + + // + // Attributes + // client_t client_; // unique application identifier session_t session_; std::mutex session_mutex_; @@ -153,6 +209,9 @@ private: // Proxy to or the Routing Manager itself std::shared_ptr<routing_manager> routing_; + // vsomeip state (registered / deregistered) + state_type_e state_; + // vsomeip state handler state_handler_t handler_; @@ -162,31 +221,43 @@ private: mutable std::mutex members_mutex_; // Availability handlers - std::map<service_t, std::map<instance_t, availability_handler_t> > availability_; + std::map<service_t, std::map<instance_t, std::tuple<major_version_t, minor_version_t, availability_handler_t, bool>>> availability_; mutable std::mutex availability_mutex_; // Availability - mutable std::map<service_t, std::set<instance_t>> available_; + mutable available_t available_; - // Subscriptopn handlers + // Subscription handlers std::map<service_t, std::map<instance_t, std::map<eventgroup_t, subscription_handler_t>>> subscription_; mutable std::mutex subscription_mutex_; + std::map<service_t, + std::map<instance_t, std::map<eventgroup_t, + std::map<client_t, error_handler_t > > > > eventgroup_error_handlers_; + mutable std::mutex subscription_error_mutex_; // Signals boost::asio::signal_set signals_; - // Thread pool for dispatch handlers - std::size_t num_dispatchers_; - std::vector<std::thread> dispatchers_; - std::atomic_bool is_dispatching_; - // Handlers - mutable std::deque<std::function<void()>> handlers_; - - // Condition to wake up - mutable std::mutex dispatch_mutex_; - mutable std::condition_variable dispatch_condition_; + mutable std::deque<std::shared_ptr<sync_handler>> handlers_; + mutable std::mutex handlers_mutex_; + + // Dispatching + bool is_dispatching_; + // Dispatcher threads + std::map<std::thread::id, std::shared_ptr<std::thread>> dispatchers_; + // Dispatcher threads that elapsed and can be removed + std::set<std::thread::id> elapsed_dispatchers_; + // Dispatcher threads that blocked + std::set<std::thread::id> blocked_dispatchers_; + // Mutex to protect access to dispatchers_ & elapsed_dispatchers_ + std::mutex dispatcher_mutex_; + // Condition to wakeup the dispatcher thread + mutable std::condition_variable dispatcher_condition_; + boost::asio::system_timer dispatcher_timer_; + std::size_t max_dispatchers_; + std::size_t max_dispatch_time_; // Workaround for destruction problem std::shared_ptr<logger> logger_; @@ -195,6 +266,16 @@ private: std::mutex start_stop_mutex_; bool stopped_; std::thread stop_thread_; + + bool catched_signal_; + + static uint32_t app_counter__; + + bool is_routing_manager_host_; + + // Event subscriptions + std::mutex event_subscriptions_mutex_; + std::map<service_t, std::map<instance_t, std::map<event_t, bool>>> event_subscriptions_; }; } // namespace vsomeip diff --git a/implementation/runtime/include/runtime_impl.hpp b/implementation/runtime/include/runtime_impl.hpp index 123272b..a81b00e 100644 --- a/implementation/runtime/include/runtime_impl.hpp +++ b/implementation/runtime/include/runtime_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -13,6 +13,10 @@ namespace vsomeip { class runtime_impl: public runtime { public: + + static std::string get_property(const std::string &_name); + static void set_property(const std::string &_name, const std::string &_value); + static std::shared_ptr<runtime> get(); virtual ~runtime_impl(); @@ -37,6 +41,7 @@ public: private: static std::shared_ptr<runtime> the_runtime_; + static std::map<std::string, std::string> properties_; std::map<std::string, std::shared_ptr<application>> applications_; }; diff --git a/implementation/runtime/src/application_impl.cpp b/implementation/runtime/src/application_impl.cpp index c9efed4..dc7bda5 100644 --- a/implementation/runtime/src/application_impl.cpp +++ b/implementation/runtime/src/application_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -10,8 +10,8 @@ #ifndef WIN32 #include <dlfcn.h> #endif -#include <iostream> #include <vsomeip/defines.hpp> +#include <vsomeip/runtime.hpp> #include "../include/application_impl.hpp" #include "../../configuration/include/configuration.hpp" @@ -22,24 +22,28 @@ #include "../../routing/include/routing_manager_proxy.hpp" #include "../../utility/include/utility.hpp" #include "../../configuration/include/configuration_impl.hpp" +#include "../../tracing/include/trace_connector.hpp" +#include "../../tracing/include/enumeration_types.hpp" namespace vsomeip { +uint32_t application_impl::app_counter__ = 0; + application_impl::application_impl(const std::string &_name) : is_initialized_(false), name_(_name), file_(VSOMEIP_DEFAULT_CONFIGURATION_FILE), folder_(VSOMEIP_DEFAULT_CONFIGURATION_FOLDER), routing_(0), + state_(state_type_e::ST_DEREGISTERED), signals_(io_, SIGINT, SIGTERM), - num_dispatchers_(0), logger_(logger::get()), - stopped_(false) { + dispatcher_timer_(io_), + logger_(logger::get()), + stopped_(false), + catched_signal_(false) { } application_impl::~application_impl() { -#ifdef WIN32 - exit(0); // TODO: clean solution... -#endif - stop_thread_.join(); + } void application_impl::set_configuration( @@ -49,6 +53,10 @@ void application_impl::set_configuration( } bool application_impl::init() { + if(is_initialized_) { + VSOMEIP_WARNING << "Trying to initialize an already initialized application."; + return true; + } // Application name if (name_ == "") { const char *its_name = getenv(VSOMEIP_ENV_APPLICATION_NAME); @@ -69,7 +77,7 @@ bool application_impl::init() { #ifdef WIN32 HMODULE config = LoadLibrary(config_module.c_str()); if (config != 0) { - VSOMEIP_INFO << "\"" << config_module << "\" was loaded"; + VSOMEIP_INFO << "\"" << config_module << "\" is loaded."; if (!configuration_) { VSOMEIP_ERROR << "Configuration not set."; return false; @@ -82,13 +90,13 @@ bool application_impl::init() { #else void *config = dlopen(config_module.c_str(), RTLD_LAZY | RTLD_GLOBAL); if(config != 0) { - VSOMEIP_INFO << "\"" << config_module << "\" was loaded"; + VSOMEIP_INFO << "\"" << config_module << "\" is loaded."; if(!configuration_) { VSOMEIP_ERROR << "Configuration not set."; return false; } } else { - VSOMEIP_ERROR << "\"" << config_module << "\" could not be loaded (" << dlerror() << ")"; + VSOMEIP_ERROR << "\"" << config_module << "\" could not be loaded (" << dlerror() << ")."; return false; } dlclose(config); @@ -120,58 +128,51 @@ bool application_impl::init() { std::shared_ptr<configuration> its_configuration = get_configuration(); if (its_configuration) { - VSOMEIP_INFO << "Initializing vsomeip application \"" << name_ << "\""; + VSOMEIP_INFO << "Initializing vsomeip application \"" << name_ << "\"."; if (utility::is_file(file_)) - VSOMEIP_INFO << "Using configuration file: \"" << file_ << "\""; + VSOMEIP_INFO << "Using configuration file: \"" << file_ << "\"."; if (utility::is_folder(folder_)) - VSOMEIP_INFO << "Using configuration folder: \"" << folder_ << "\""; + VSOMEIP_INFO << "Using configuration folder: \"" << folder_ << "\"."; - bool is_routing_manager_host(false); client_ = its_configuration->get_id(name_); - std::string its_routing_host = its_configuration->get_routing_host(); - if (client_ == 0 || its_routing_host == "") { -#ifndef WIN32 - if (!utility::auto_configuration_init()) { - VSOMEIP_ERROR << "Configuration incomplete and " - "Auto-configuration failed!"; - return false; - } -#else - return false; -#endif - } - // Client ID - if (client_ == 0) { -#ifndef WIN32 - client_ = utility::get_client_id(); - VSOMEIP_INFO << "No SOME/IP client identifier configured. " - << "Using auto-configured " - << std::hex << std::setfill('0') << std::setw(4) - << client_; -#else - return false; -#endif - } + // Max dispatchers is the configured maximum number of dispatchers and + // the main dispatcher + max_dispatchers_ = its_configuration->get_max_dispatchers(name_) + 1; + max_dispatch_time_ = its_configuration->get_max_dispatch_time(name_); - // Routing - if (its_routing_host == "") { -#ifndef WIN32 - is_routing_manager_host = utility::is_routing_manager_host(); - VSOMEIP_INFO << "No routing manager configured. " - << "Using auto-configuration (" - << (is_routing_manager_host ? - "Host" : "Proxy") << ")"; -#else - return false; -#endif + std::string its_routing_host = its_configuration->get_routing_host(); + if (!utility::auto_configuration_init(name_)) { + VSOMEIP_WARNING << "Could _not_ initialize auto-configuration:" + " Cannot guarantee unique application identifiers!"; } else { - is_routing_manager_host = (its_routing_host == name_); + // Client Identifier + client_t its_old_client = client_; + client_ = utility::request_client_id(client_); + VSOMEIP_INFO << "SOME/IP client identifier configured. " + << "Using " + << std::hex << std::setfill('0') << std::setw(4) + << client_ + << " (was: " + << std::hex << std::setfill('0') << std::setw(4) + << its_old_client + << ")"; + + // Routing + if (its_routing_host == "") { + is_routing_manager_host_ = utility::is_routing_manager_host(); + VSOMEIP_INFO << "No routing manager configured. " + << "Using auto-configuration (" + << (is_routing_manager_host_ ? + "Host" : "Proxy") << ")"; + } else { + is_routing_manager_host_ = (its_routing_host == name_); + } } - if (is_routing_manager_host) { + if (is_routing_manager_host_) { routing_ = std::make_shared<routing_manager_impl>(this); } else { routing_ = std::make_shared<routing_manager_proxy>(this); @@ -179,14 +180,41 @@ bool application_impl::init() { routing_->init(); - num_dispatchers_ = its_configuration->get_num_dispatchers(name_); - // Smallest allowed session identifier session_ = 0x0001; - VSOMEIP_DEBUG<< "Application(" << (name_ != "" ? name_ : "unnamed") - << ", " << std::hex << client_ << ") is initialized (uses " - << std::dec << num_dispatchers_ << " dispatcher threads)."; +#ifdef USE_DLT + // Tracing + std::shared_ptr<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; + + its_filter_rule[tc::filter_criteria_e::SERVICES] = its_filter_rule_cfg->services_; + its_filter_rule[tc::filter_criteria_e::METHODS] = its_filter_rule_cfg->methods_; + its_filter_rule[tc::filter_criteria_e::CLIENTS] = its_filter_rule_cfg->clients_; + + its_trace_connector->add_filter_rule(it->get()->channel_, its_filter_rule); + } + + bool enable_tracing = its_trace_cfg->is_enabled_; + if(enable_tracing) + its_trace_connector->init(); + its_trace_connector->set_enabled(enable_tracing); +#endif + + VSOMEIP_DEBUG << "Application(" << (name_ != "" ? name_ : "unnamed") + << ", " << std::hex << client_ << ") is initialized (" + << std::dec << max_dispatchers_ << ", " + << std::dec << max_dispatch_time_ << ")."; is_initialized_ = true; } @@ -202,11 +230,11 @@ bool application_impl::init() { switch (_signal) { case SIGTERM: case SIGINT: - stop(); - exit(0); - break; + catched_signal_ = true; + stop(); + break; default: - break; + break; } } }; @@ -219,7 +247,7 @@ bool application_impl::init() { void application_impl::start() { { std::lock_guard<std::mutex> its_lock(start_stop_mutex_); - if(io_.stopped()) { + if (io_.stopped()) { io_.reset(); } else if(stop_thread_.joinable()) { VSOMEIP_ERROR << "Trying to start an already started application."; @@ -228,11 +256,11 @@ void application_impl::start() { is_dispatching_ = true; - for (size_t i = 0; i < num_dispatchers_; i++) - dispatchers_.push_back( - std::thread(std::bind(&application_impl::dispatch, this))); + auto its_main_dispatcher = std::make_shared<std::thread>( + std::bind(&application_impl::main_dispatch, this)); + dispatchers_[its_main_dispatcher->get_id()] = its_main_dispatcher; - if(stop_thread_.joinable()) { + if (stop_thread_.joinable()) { stop_thread_.join(); } stop_thread_= std::thread(&application_impl::wait_for_stop, this); @@ -240,31 +268,42 @@ void application_impl::start() { if (routing_) routing_->start(); } - VSOMEIP_INFO << "Starting vsomeip application \"" << name_ << "\""; + + start_stop_mutex_.lock(); + app_counter__++; + start_stop_mutex_.unlock(); + + VSOMEIP_INFO << "Starting vsomeip application \"" << name_ << "\"."; io_.run(); + { + std::lock_guard<std::mutex> its_lock(start_stop_mutex_); + stopped_ = true; + stop_cv_.notify_one(); + } + + if (stop_thread_.joinable()) { + stop_thread_.join(); + } + + start_stop_mutex_.lock(); + app_counter__--; + + if (catched_signal_ && !app_counter__) { + start_stop_mutex_.unlock(); + VSOMEIP_INFO << "Exiting vsomeip application..."; + exit(0); + } + start_stop_mutex_.unlock(); } void application_impl::stop() { #ifndef WIN32 // Gives serious problems under Windows. - VSOMEIP_INFO << "Stopping vsomeip application \"" << name_ << "\""; + VSOMEIP_INFO << "Stopping vsomeip application \"" << name_ << "\"."; #endif - std::lock_guard<std::mutex> its_lock(start_stop_mutex_); - is_dispatching_ = false; - dispatch_condition_.notify_all(); - for (auto &t : dispatchers_) { - if(t.get_id() == std::this_thread::get_id()) { - continue; - } - if(t.joinable()) { - t.join(); - } - } - - if (routing_) - routing_->stop(); -#ifndef WIN32 + utility::release_client_id(client_); utility::auto_configuration_exit(); -#endif + + std::lock_guard<std::mutex> its_lock_start_stop(start_stop_mutex_); stopped_ = true; stop_cv_.notify_one(); } @@ -275,14 +314,22 @@ void application_impl::offer_service(service_t _service, instance_t _instance, routing_->offer_service(client_, _service, _instance, _major, _minor); } -void application_impl::stop_offer_service(service_t _service, - instance_t _instance) { +void application_impl::stop_offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { if (routing_) - routing_->stop_offer_service(client_, _service, _instance); + routing_->stop_offer_service(client_, _service, _instance, _major, _minor); } void application_impl::request_service(service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, bool _use_exclusive_proxy) { + if (_use_exclusive_proxy) { + message_handler_t handler([&](const std::shared_ptr<message>& response) { + routing_->on_identify_response(get_client(), response->get_service(), + response->get_instance(), response->is_reliable()); + }); + register_message_handler(_service, _instance, ANY_METHOD - 1, handler); + } + if (routing_) routing_->request_service(client_, _service, _instance, _major, _minor, _use_exclusive_proxy); @@ -290,16 +337,57 @@ void application_impl::request_service(service_t _service, instance_t _instance, void application_impl::release_service(service_t _service, instance_t _instance) { - if (routing_) + if (routing_) { routing_->release_service(client_, _service, _instance); + } } void application_impl::subscribe(service_t _service, instance_t _instance, - eventgroup_t _eventgroup, major_version_t _major, - subscription_type_e _subscription_type) { - if (routing_) + eventgroup_t _eventgroup, + major_version_t _major, + subscription_type_e _subscription_type, + event_t _event) { + if (routing_) { + bool send_back_cached(false); + bool send_back_cached_group(false); + { + std::lock_guard<std::mutex> its_lock(event_subscriptions_mutex_); + auto found_service = event_subscriptions_.find(_service); + if(found_service != event_subscriptions_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto its_event = found_instance->second.find(_event); + if (its_event == found_instance->second.end()) { + // first subscription to this event + event_subscriptions_[_service][_instance][_event] = false; + } else { + if(its_event->second) { + // initial values for this event have already been sent, + // send back cached value + if(_event == ANY_EVENT) { + send_back_cached_group = true; + } else { + send_back_cached = true; + } + } + } + } else { + // first subscription to this service instance + event_subscriptions_[_service][_instance][_event] = false; + } + } else { + // first subscription to this service + event_subscriptions_[_service][_instance][_event] = false; + } + } + if(send_back_cached) { + send_back_cached_event(_service, _instance, _event); + } else if(send_back_cached_group) { + send_back_cached_eventgroup(_service, _instance, _event); + } routing_->subscribe(client_, _service, _instance, _eventgroup, _major, _subscription_type); + } } void application_impl::unsubscribe(service_t _service, instance_t _instance, @@ -309,13 +397,160 @@ void application_impl::unsubscribe(service_t _service, instance_t _instance, } bool application_impl::is_available( - service_t _service, instance_t _instance) const { - auto found_available = available_.find(_service); - if (found_available == available_.end()) - return false; + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { + std::lock_guard<std::mutex> its_lock(availability_mutex_); + return is_available_unlocked(_service, _instance, _major, _minor); +} + +bool application_impl::is_available_unlocked( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { - return (found_available->second.find(_instance) - != found_available->second.end()); + bool is_available(false); + + auto found_available_service = available_.find(_service); + if (found_available_service != available_.end()) { + auto found_instance = found_available_service->second.find(_instance); + if( found_instance != found_available_service->second.end()) { + auto found_major = found_instance->second.find(_major); + if( found_major != found_instance->second.end() ){ + if( _minor <= found_major->second) { + is_available = true; + } + } else if(_major == DEFAULT_MAJOR && + _minor == DEFAULT_MINOR){ + is_available = true; + } + } + } + return is_available; +} + +bool application_impl::are_available( + available_t &_available, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { + std::lock_guard<std::mutex> its_lock(availability_mutex_); + return are_available_unlocked(_available, _service, _instance, _major, _minor); +} + +bool application_impl::are_available_unlocked(available_t &_available, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { + + //find available services + if(_service == ANY_SERVICE) { + //add all available services + for(auto its_available_services_it = available_.begin(); + its_available_services_it != available_.end(); + ++its_available_services_it) + _available[its_available_services_it->first]; + } else { + // check if specific service is available + if(available_.find(_service) != available_.end()) + _available[_service]; + } + + //find available instances + //iterate through found available services + for(auto its_available_services_it = _available.begin(); + its_available_services_it != _available.end(); + ++its_available_services_it) { + //get available service + auto found_available_service = available_.find(its_available_services_it->first); + if (found_available_service != available_.end()) { + if(_instance == ANY_INSTANCE) { + //add all available instances + for(auto its_available_instances_it = found_available_service->second.begin(); + its_available_instances_it != found_available_service->second.end(); + ++its_available_instances_it) + _available[its_available_services_it->first][its_available_instances_it->first]; + } else { + if(found_available_service->second.find(_instance) != found_available_service->second.end()) + _available[its_available_services_it->first][_instance]; + } + } + } + + //find major versions + //iterate through found available services + for(auto its_available_services_it = _available.begin(); + its_available_services_it != _available.end(); + ++its_available_services_it) { + //get available service + auto found_available_service = available_.find(its_available_services_it->first); + if (found_available_service != available_.end()) { + //iterate through found available instances + for(auto its_available_instances_it = found_available_service->second.begin(); + its_available_instances_it != found_available_service->second.end(); + ++its_available_instances_it) { + //get available instance + auto found_available_instance = found_available_service->second.find(its_available_instances_it->first); + if(found_available_instance != found_available_service->second.end()) { + if(_major == ANY_MAJOR || _major == DEFAULT_MAJOR) { + //add all major versions + for(auto its_available_major_it = found_available_instance->second.begin(); + its_available_major_it != found_available_instance->second.end(); + ++its_available_major_it) + _available[its_available_services_it->first][its_available_instances_it->first][its_available_major_it->first]; + } else { + if(found_available_instance->second.find(_major) != found_available_instance->second.end()) + _available[its_available_services_it->first][its_available_instances_it->first][_major]; + } + } + } + } + } + + //find minor + //iterate through found available services + auto its_available_services_it = _available.begin(); + while(its_available_services_it != _available.end()) { + bool found_minor(false); + //get available service + auto found_available_service = available_.find(its_available_services_it->first); + if (found_available_service != available_.end()) { + //iterate through found available instances + for(auto its_available_instances_it = found_available_service->second.begin(); + its_available_instances_it != found_available_service->second.end(); + ++its_available_instances_it) { + //get available instance + auto found_available_instance = found_available_service->second.find(its_available_instances_it->first); + if(found_available_instance != found_available_service->second.end()) { + //iterate through found available major version + for(auto its_available_major_it = found_available_instance->second.begin(); + its_available_major_it != found_available_instance->second.end(); + ++its_available_major_it) { + //get available major version + auto found_available_major = found_available_instance->second.find(its_available_major_it->first); + if(found_available_major != found_available_instance->second.end()) { + if(_minor == ANY_MINOR || _minor == DEFAULT_MINOR) { + //add minor version + _available[its_available_services_it->first][its_available_instances_it->first][its_available_major_it->first] = _minor; + found_minor = true; + } else { + if(_minor == found_available_major->second) { + _available[its_available_services_it->first][its_available_instances_it->first][_major] = _minor; + found_minor = true; + } + } + } + } + } + } + } + if(found_minor) + ++its_available_services_it; + else + its_available_services_it = _available.erase(its_available_services_it); + } + + if(_available.empty()) { + _available[_service][_instance][_major] = _minor ; + return false; + } + return true; } void application_impl::send(std::shared_ptr<message> _message, bool _flush) { @@ -360,24 +595,56 @@ void application_impl::unregister_state_handler() { } void application_impl::register_availability_handler(service_t _service, - instance_t _instance, availability_handler_t _handler) { + instance_t _instance, availability_handler_t _handler, + major_version_t _major, minor_version_t _minor) { + if (state_ == state_type_e::ST_REGISTERED) { + do_register_availability_handler(_service, _instance, + _handler, _major, _minor); + } else { + availability_[_service][_instance] + = std::make_tuple(_major, _minor, _handler, false); + } +} + +void application_impl::do_register_availability_handler(service_t _service, + instance_t _instance, availability_handler_t _handler, + major_version_t _major, minor_version_t _minor) { + { - std::unique_lock<std::mutex> its_lock(availability_mutex_); - availability_[_service][_instance] = _handler; + std::unique_lock<std::mutex> availability_lock(availability_mutex_); + available_t available; + bool are_available = are_available_unlocked(available, _service, _instance, _major, _minor); + availability_[_service][_instance] = std::make_tuple(_major, _minor, _handler, true); + + std::lock_guard<std::mutex> handlers_lock(handlers_mutex_); + + std::shared_ptr<sync_handler> its_sync_handler + = std::make_shared<sync_handler>([_handler, are_available, available]() { + for(auto available_services_it : available) + for(auto available_instances_it : available_services_it.second) + _handler(available_services_it.first, available_instances_it.first, are_available); + }); + handlers_.push_back(its_sync_handler); } - std::async(std::launch::async, [this, _service, _instance, _handler]() { - _handler(_service, _instance, is_available(_service, _instance)); - }); + + dispatcher_condition_.notify_one(); } void application_impl::unregister_availability_handler(service_t _service, - instance_t _instance) { - std::unique_lock<std::mutex> its_lock(availability_mutex_); + instance_t _instance, major_version_t _major, minor_version_t _minor) { + std::lock_guard<std::mutex> its_lock(availability_mutex_); auto found_service = availability_.find(_service); if (found_service != availability_.end()) { auto found_instance = found_service->second.find(_instance); if (found_instance != found_service->second.end()) { - found_service->second.erase(_instance); + auto found_version = found_instance->second; + auto found_major = std::get<0>(found_version); + auto found_minor = std::get<1>(found_version); + if(found_major == _major) { + if(found_minor == _minor) { + found_service->second.erase(_instance); + } + } } } } @@ -385,7 +652,7 @@ void application_impl::unregister_availability_handler(service_t _service, bool application_impl::on_subscription(service_t _service, instance_t _instance, eventgroup_t _eventgroup, client_t _client, bool _subscribed) { - std::unique_lock<std::mutex> its_lock(subscription_mutex_); + std::lock_guard<std::mutex> its_lock(subscription_mutex_); auto found_service = subscription_.find(_service); if (found_service != subscription_.end()) { auto found_instance = found_service->second.find(_instance); @@ -403,14 +670,18 @@ void application_impl::register_subscription_handler(service_t _service, instance_t _instance, eventgroup_t _eventgroup, subscription_handler_t _handler) { - std::unique_lock<std::mutex> its_lock(subscription_mutex_); + std::lock_guard<std::mutex> its_lock(subscription_mutex_); subscription_[_service][_instance][_eventgroup] = _handler; + + message_handler_t handler([&](const std::shared_ptr<message>& request) { + send(runtime::get()->create_response(request), true); + }); + register_message_handler(_service, _instance, ANY_METHOD - 1, handler); } void application_impl::unregister_subscription_handler(service_t _service, instance_t _instance, eventgroup_t _eventgroup) { - - std::unique_lock<std::mutex> its_lock(subscription_mutex_); + std::lock_guard<std::mutex> its_lock(subscription_mutex_); auto found_service = subscription_.find(_service); if (found_service != subscription_.end()) { auto found_instance = found_service->second.find(_instance); @@ -421,17 +692,71 @@ void application_impl::unregister_subscription_handler(service_t _service, } } } + unregister_message_handler(_service, _instance, ANY_METHOD - 1); +} + +void application_impl::on_subscription_error(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, uint16_t _error) { + error_handler_t handler = nullptr; + std::lock_guard<std::mutex> its_lock(subscription_error_mutex_); + auto found_service = eventgroup_error_handlers_.find(_service); + if (found_service != eventgroup_error_handlers_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto found_client = found_eventgroup->second.find(get_client()); + if (found_client != found_eventgroup->second.end()) { + handler = found_client->second; + + } + } + } + } + if (handler) { + { + std::unique_lock<std::mutex> handlers_lock(handlers_mutex_); + std::shared_ptr<sync_handler> its_sync_handler + = std::make_shared<sync_handler>([handler, _error]() { + handler(_error); + }); + handlers_.push_back(its_sync_handler); + } + dispatcher_condition_.notify_all(); + } +} + +void application_impl::register_subscription_error_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + error_handler_t _handler) { + std::lock_guard<std::mutex> its_lock(subscription_error_mutex_); + eventgroup_error_handlers_[_service][_instance][_eventgroup][get_client()] = _handler; +} + +void application_impl::unregister_subscription_error_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) { + std::lock_guard<std::mutex> its_lock(subscription_error_mutex_); + auto found_service = eventgroup_error_handlers_.find(_service); + if (found_service != eventgroup_error_handlers_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + found_eventgroup->second.erase(get_client()); + } + } + } } void application_impl::register_message_handler(service_t _service, instance_t _instance, method_t _method, message_handler_t _handler) { - std::unique_lock<std::mutex> its_lock(members_mutex_); + std::lock_guard<std::mutex> its_lock(members_mutex_); members_[_service][_instance][_method] = _handler; } void application_impl::unregister_message_handler(service_t _service, instance_t _instance, method_t _method) { - std::unique_lock<std::mutex> its_lock(members_mutex_); + std::lock_guard<std::mutex> its_lock(members_mutex_); auto found_service = members_.find(_service); if (found_service != members_.end()) { auto found_instance = found_service->second.find(_instance); @@ -462,7 +787,7 @@ void application_impl::request_event(service_t _service, instance_t _instance, if (routing_) routing_->register_event(client_, _service, _instance, _event, _eventgroups, _is_field, false); - } +} void application_impl::release_event(service_t _service, instance_t _instance, event_t _event) { @@ -501,81 +826,149 @@ boost::asio::io_service & application_impl::get_io() { } void application_impl::on_state(state_type_e _state) { + if (state_ != _state) { + state_ = _state; + if (state_ == state_type_e::ST_REGISTERED) { + for (auto &its_service : availability_) { + for (auto &its_instance : its_service.second) { + if (!std::get<3>(its_instance.second)) { + do_register_availability_handler( + its_service.first, its_instance.first, + std::get<2>(its_instance.second), + std::get<0>(its_instance.second), + std::get<1>(its_instance.second)); + } + } + } + } + } + if (handler_) { - if (num_dispatchers_ > 0) { - std::unique_lock<std::mutex> its_lock(dispatch_mutex_); - handlers_.push_back([this, _state]() { - handler_(_state); - }); - dispatch_condition_.notify_one(); - } else { - handler_(_state); + { + std::lock_guard<std::mutex> its_lock(handlers_mutex_); + + std::shared_ptr<sync_handler> its_sync_handler + = std::make_shared<sync_handler>([this, _state]() { + handler_(_state); + }); + + handlers_.push_back(its_sync_handler); } + dispatcher_condition_.notify_one(); } } void application_impl::on_availability(service_t _service, instance_t _instance, - bool _is_available) const { + bool _is_available, major_version_t _major, minor_version_t _minor) { - std::map<instance_t, availability_handler_t>::const_iterator found_instance; + std::map<minor_version_t, availability_handler_t>::const_iterator found_minor; availability_handler_t its_handler; - std::map<instance_t, availability_handler_t>::const_iterator found_wildcard_instance; + std::map<minor_version_t, availability_handler_t>::const_iterator found_wildcard_minor; availability_handler_t its_wildcard_handler; bool has_handler(false); bool has_wildcard_handler(false); { - std::unique_lock<std::mutex> its_lock(availability_mutex_); - - if (_is_available == is_available(_service, _instance)) + std::lock_guard<std::mutex> availability_lock(availability_mutex_); + if (_is_available == is_available_unlocked(_service, _instance, _major, _minor)) { return; + } if (_is_available) { - available_[_service].insert(_instance); + available_[_service][_instance][_major] = _minor; } else { auto found_available_service = available_.find(_service); - if (found_available_service != available_.end()) - found_available_service->second.erase(_instance); + if (found_available_service != available_.end()) { + auto found_instance = found_available_service->second.find(_instance); + if( found_instance != found_available_service->second.end()) { + auto found_major = found_instance->second.find(_major); + if( found_major != found_instance->second.end() ){ + if( _minor == found_major->second) + found_available_service->second.erase(_instance); + } + } + } } auto found_service = availability_.find(_service); if (found_service != availability_.end()) { - found_instance = found_service->second.find(_instance); - has_handler = (found_instance != found_service->second.end()); - if (has_handler) - its_handler = found_instance->second; - found_wildcard_instance = found_service->second.find(ANY_INSTANCE); - has_wildcard_handler = (found_wildcard_instance != found_service->second.end()); - if (has_wildcard_handler) - its_wildcard_handler = found_wildcard_instance->second; + //find specific instance + auto found_instance = found_service->second.find(_instance); + if( found_instance != found_service->second.end()) { + auto found_version = found_instance->second; + auto requested_major = std::get<0>(found_version); + auto requested_minor = std::get<1>(found_version); + if(requested_major == _major) { + if(requested_minor <= _minor ) { + has_handler = true; + its_handler = std::get<2>(found_version); + } + } else if (requested_major == DEFAULT_MAJOR && + requested_minor == DEFAULT_MINOR) { + has_handler = true; + its_handler = std::get<2>(found_version); + } + } + + //find wildcard instance major minor + found_instance = found_service->second.find(ANY_INSTANCE); + if( found_instance != found_service->second.end()) { + auto found_version = found_instance->second; + auto requested_major = std::get<0>(found_version); + auto requested_minor = std::get<1>(found_version); + if(requested_major == ANY_MAJOR) { + if(requested_minor == ANY_MINOR) { + has_wildcard_handler = true; + its_wildcard_handler = std::get<2>(found_version); + } + } else if (requested_major == DEFAULT_MAJOR && + requested_minor == DEFAULT_MINOR) { + has_handler = true; + its_handler = std::get<2>(found_version); + } + } } - } - if (num_dispatchers_ > 0) { + std::lock_guard<std::mutex> handlers_lock(handlers_mutex_); if (has_handler) { - std::unique_lock<std::mutex> its_lock(dispatch_mutex_); - handlers_.push_back( - [its_handler, _service, _instance, _is_available]() { - its_handler(_service, _instance, _is_available); - }); - dispatch_condition_.notify_one(); + + std::shared_ptr<sync_handler> its_sync_handler + = std::make_shared<sync_handler>( + [its_handler, _service, _instance, _is_available]() { + its_handler(_service, _instance, _is_available); + } + ); + + handlers_.push_back(its_sync_handler); } if (has_wildcard_handler) { - std::unique_lock < std::mutex > its_lock(dispatch_mutex_); - handlers_.push_back( - [its_wildcard_handler, _service, _instance, _is_available]() { - its_wildcard_handler(_service, _instance, _is_available); - }); - dispatch_condition_.notify_one(); - } - } else { - if(has_handler) { - its_handler(_service, _instance, _is_available); + + std::shared_ptr<sync_handler> its_sync_handler + = std::make_shared<sync_handler>( + [its_wildcard_handler, _service, _instance, _is_available]() { + its_wildcard_handler(_service, _instance, _is_available); + } + ); + + handlers_.push_back(its_sync_handler); } - if(has_wildcard_handler) { - its_wildcard_handler(_service, _instance, _is_available); + } + if (!_is_available) { + std::lock_guard<std::mutex> its_lock(event_subscriptions_mutex_); + auto found_service = event_subscriptions_.find(_service); + if (found_service != event_subscriptions_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (auto &e : found_instance->second) { + e.second = false; + } + } } } + + if (has_handler || has_wildcard_handler) { + dispatcher_condition_.notify_one(); + } } void application_impl::on_message(std::shared_ptr<message> _message) { @@ -587,8 +980,36 @@ void application_impl::on_message(std::shared_ptr<message> _message) { message_handler_t its_handler; bool has_handler(false); + if (_message->get_message_type() == message_type_e::MT_NOTIFICATION) { + std::lock_guard<std::mutex> its_lock(event_subscriptions_mutex_); + auto found_service = event_subscriptions_.find(its_service); + if(found_service != event_subscriptions_.end()) { + auto found_instance = found_service->second.find(its_instance); + if (found_instance != found_service->second.end()) { + auto its_event = found_instance->second.find(its_method); + if (its_event != found_instance->second.end()) { + its_event->second = true; + } else { + // received a event which nobody yet subscribed to + event_subscriptions_[its_service][its_instance][its_method] = true; + // check if someone subscribed to ANY_EVENT + auto its_any_event = found_instance->second.find(ANY_EVENT); + if(its_any_event == found_instance->second.end()) { + return; + } + } + } else { + // received a event from a service instance which nobody yet subscribed to + event_subscriptions_[its_service][its_instance][its_method] = true; + } + } else { + // received a event from a service which nobody yet subscribed to + event_subscriptions_[its_service][its_instance][its_method] = true; + } + } + { - std::unique_lock<std::mutex> its_lock(members_mutex_); + std::lock_guard<std::mutex> its_lock(members_mutex_); auto found_service = members_.find(its_service); if (found_service == members_.end()) { @@ -611,18 +1032,19 @@ void application_impl::on_message(std::shared_ptr<message> _message) { } } } - } - if (has_handler) { - if (num_dispatchers_ > 0) { - std::unique_lock<std::mutex> its_lock(dispatch_mutex_); - handlers_.push_back([its_handler, _message]() { - its_handler(_message); - }); - dispatch_condition_.notify_one(); - } else { - its_handler(_message); + if (has_handler) { + std::lock_guard<std::mutex> its_lock(handlers_mutex_); + std::shared_ptr<sync_handler> its_sync_handler + = std::make_shared<sync_handler>( + [its_handler, _message]() { + its_handler(_message); + } + ); + + handlers_.push_back(its_sync_handler); } + dispatcher_condition_.notify_one(); } } @@ -641,36 +1063,203 @@ void application_impl::service() { io_.run(); } -void application_impl::dispatch() { - std::function<void()> handler; +void application_impl::main_dispatch() { while (is_dispatching_) { - { - std::unique_lock<std::mutex> its_lock(dispatch_mutex_); - if (handlers_.empty()) { - dispatch_condition_.wait(its_lock); - continue; - } else { - handler = handlers_.front(); + std::unique_lock<std::mutex> its_lock(handlers_mutex_); + + if (handlers_.empty()) { + // Cancel other waiting dispatcher + dispatcher_condition_.notify_all(); + // Wait for new handlers to execute + dispatcher_condition_.wait(its_lock); + } else { + while (!handlers_.empty()) { + std::shared_ptr<sync_handler> its_handler = handlers_.front(); handlers_.pop_front(); + its_lock.unlock(); + invoke_handler(its_handler); + its_lock.lock(); + + remove_elapsed_dispatchers(); } } - handler(); } } -void application_impl::wait_for_stop() { - std::unique_lock<std::mutex> its_lock(start_stop_mutex_); - while(!stopped_) { - stop_cv_.wait(its_lock); +void application_impl::dispatch() { + std::thread::id its_id = std::this_thread::get_id(); + while (is_active_dispatcher(its_id)) { + std::unique_lock<std::mutex> its_lock(handlers_mutex_); + if (handlers_.empty()) { + dispatcher_condition_.wait(its_lock); + if (handlers_.empty()) { // Maybe woken up from main dispatcher + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + elapsed_dispatchers_.insert(its_id); + return; + } + } else { + while (!handlers_.empty() && is_active_dispatcher(its_id)) { + std::shared_ptr<sync_handler> its_handler = handlers_.front(); + handlers_.pop_front(); + its_lock.unlock(); + invoke_handler(its_handler); + its_lock.lock(); + + remove_elapsed_dispatchers(); + } + } + } + + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + elapsed_dispatchers_.insert(std::this_thread::get_id()); +} + +void application_impl::invoke_handler(std::shared_ptr<sync_handler> &_handler) { + std::thread::id its_id = std::this_thread::get_id(); + + dispatcher_timer_.expires_from_now(std::chrono::milliseconds(max_dispatch_time_)); + dispatcher_timer_.async_wait([this, its_id](const boost::system::error_code &_error) { + if (!_error) { + VSOMEIP_DEBUG << "Blocking call detected. Client=" << std::hex << get_client(); + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + blocked_dispatchers_.insert(its_id); + + // If possible, create a new dispatcher thread to unblock. + // If this is _not_ possible, dispatching is blocked until at least + // one of the active handler calls returns. + if (dispatchers_.size() < max_dispatchers_) { + auto its_dispatcher = std::make_shared<std::thread>( + std::bind(&application_impl::dispatch, this)); + dispatchers_[its_dispatcher->get_id()] = its_dispatcher; + } else { + VSOMEIP_DEBUG << "Maximum number of dispatchers exceeded."; + } + } + }); + + _handler->handler_(); + dispatcher_timer_.cancel(); + { + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + blocked_dispatchers_.erase(its_id); + } +} + +bool application_impl::is_active_dispatcher(std::thread::id &_id) { + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + for (auto d : dispatchers_) { + if (d.first != _id && + blocked_dispatchers_.find(d.first) == blocked_dispatchers_.end()) { + return false; + } + } + return true; +} + +void application_impl::remove_elapsed_dispatchers() { + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + for (auto id : elapsed_dispatchers_) { + auto its_dispatcher = dispatchers_.find(id); + if (its_dispatcher->second->joinable()) + its_dispatcher->second->join(); + dispatchers_.erase(id); + } + elapsed_dispatchers_.clear(); +} + +void application_impl::clear_all_handler() { + unregister_state_handler(); + + { + std::lock_guard<std::mutex> availability_lock(availability_mutex_); + availability_.clear(); } - stopped_ = false; - for (auto &t : dispatchers_) { - if(t.joinable()) { - t.join(); + { + std::lock_guard<std::mutex> its_lock(subscription_mutex_); + subscription_.clear(); + } + + { + std::lock_guard<std::mutex> its_lock(subscription_error_mutex_); + eventgroup_error_handlers_.clear(); + } + + { + std::lock_guard<std::mutex> its_lock(members_mutex_); + members_.clear(); + } +} + +void application_impl::wait_for_stop() { + + { + std::unique_lock<std::mutex> its_lock(start_stop_mutex_); + while(!stopped_) { + stop_cv_.wait(its_lock); } + stopped_ = false; + + // join dispatch threads + is_dispatching_ = false; + dispatcher_condition_.notify_all(); + } + + for (auto its_dispatcher : dispatchers_) { + if (its_dispatcher.second->joinable()) + its_dispatcher.second->join(); } + + if (routing_) + routing_->stop(); + io_.stop(); + + { + std::unique_lock<std::mutex> its_lock(start_stop_mutex_); + while(!stopped_) { + stop_cv_.wait(its_lock); + } + stopped_ = false; + } +} + +bool application_impl::is_routing() const { + return is_routing_manager_host_; +} + +void application_impl::send_back_cached_event(service_t _service, + instance_t _instance, + event_t _event) { + std::shared_ptr<event> its_event = routing_->get_event(_service, + _instance, _event); + if (its_event && its_event->is_field() && its_event->is_set()) { + std::shared_ptr<message> its_message = runtime::get()->create_notification(); + its_message->set_service(_service); + its_message->set_method(_event); + its_message->set_instance(_instance); + its_message->set_payload(its_event->get_payload()); + its_message->set_initial(true); + on_message(its_message); + } +} + +void application_impl::send_back_cached_eventgroup(service_t _service, + instance_t _instance, + eventgroup_t _eventgroup) { + std::set<std::shared_ptr<event>> its_events = routing_->find_events(_service, _instance, + _eventgroup); + for(const auto &its_event : its_events) { + if (its_event && its_event->is_field() && its_event->is_set()) { + std::shared_ptr<message> its_message = runtime::get()->create_notification(); + its_message->set_service(_service); + its_message->set_method(its_event->get_event()); + its_message->set_instance(_instance); + its_message->set_payload(its_event->get_payload()); + its_message->set_initial(true); + on_message(its_message); + } + } } } // namespace vsomeip diff --git a/implementation/runtime/src/error.cpp b/implementation/runtime/src/error.cpp index e921227..8bd1d36 100644 --- a/implementation/runtime/src/error.cpp +++ b/implementation/runtime/src/error.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2015-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/runtime/src/runtime.cpp b/implementation/runtime/src/runtime.cpp index 68f6154..0259b2a 100644 --- a/implementation/runtime/src/runtime.cpp +++ b/implementation/runtime/src/runtime.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -9,6 +9,14 @@ namespace vsomeip { +std::string runtime::get_property(const std::string &_name) { + return runtime_impl::get_property(_name); +} + +void runtime::set_property(const std::string &_name, const std::string &_value) { + runtime_impl::set_property(_name, _value); +} + std::shared_ptr<runtime> runtime::get() { return runtime_impl::get(); } diff --git a/implementation/runtime/src/runtime_impl.cpp b/implementation/runtime/src/runtime_impl.cpp index 2131da5..4943b6d 100644 --- a/implementation/runtime/src/runtime_impl.cpp +++ b/implementation/runtime/src/runtime_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -12,8 +12,20 @@ namespace vsomeip { +std::map<std::string, std::string> runtime_impl::properties_; std::shared_ptr<runtime> runtime_impl::the_runtime_ = std::make_shared<runtime_impl>(); +std::string runtime_impl::get_property(const std::string &_name) { + auto found_property = properties_.find(_name); + if (found_property != properties_.end()) + return found_property->second; + return ""; +} + +void runtime_impl::set_property(const std::string &_name, const std::string &_value) { + properties_[_name] = _value; +} + std::shared_ptr<runtime> runtime_impl::get() { return the_runtime_; } diff --git a/implementation/service_discovery/include/configuration_option_impl.hpp b/implementation/service_discovery/include/configuration_option_impl.hpp index de8a97f..d2351bc 100644 --- a/implementation/service_discovery/include/configuration_option_impl.hpp +++ b/implementation/service_discovery/include/configuration_option_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/include/constants.hpp b/implementation/service_discovery/include/constants.hpp index cc476a7..01c55cb 100644 --- a/implementation/service_discovery/include/constants.hpp +++ b/implementation/service_discovery/include/constants.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/service_discovery/include/defines.hpp b/implementation/service_discovery/include/defines.hpp index 2d23c3c..52c7216 100644 --- a/implementation/service_discovery/include/defines.hpp +++ b/implementation/service_discovery/include/defines.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -6,14 +6,24 @@ #ifndef VSOMEIP_SD_DEFINES_HPP #define VSOMEIP_SD_DEFINES_HPP +#include "../../configuration/include/internal.hpp" + +#define VSOMEIP_MAX_TCP_SD_PAYLOAD 4075 // Available for entries & options +#define VSOMEIP_MAX_UDP_SD_PAYLOAD 1380 + #define VSOMEIP_SOMEIP_SD_DATA_SIZE 12 #define VSOMEIP_SOMEIP_SD_ENTRY_SIZE 16 +#define VSOMEIP_SOMEIP_SD_IPV4_OPTION_SIZE 12 +#define VSOMEIP_SOMEIP_SD_IPV6_OPTION_SIZE 24 #define VSOMEIP_SOMEIP_SD_OPTION_HEADER_SIZE 3 +#define VSOMEIP_SD_IPV4_OPTION_LENGTH 0x0009 +#define VSOMEIP_SD_IPV6_OPTION_LENGTH 0x0015 + #define VSOMEIP_SD_SERVICE 0xFFFF #define VSOMEIP_SD_INSTANCE 0x0000 #define VSOMEIP_SD_METHOD 0x8100 -#define VSOMEIP_SD_CLIENT 0x0000 +#define VSOMEIP_SD_CLIENT (VSOMEIP_DIAGNOSIS_ADDRESS << 8) // SIP_SD_1139 #define VSOMEIP_SD_DEFAULT_ENABLED true @@ -25,7 +35,7 @@ #define VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MAX 3000 #define VSOMEIP_SD_DEFAULT_REPETITIONS_BASE_DELAY 10 #define VSOMEIP_SD_DEFAULT_REPETITIONS_MAX 3 -#define VSOMEIP_SD_DEFAULT_TTL 5 +#define VSOMEIP_SD_DEFAULT_TTL DEFAULT_TTL #define VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY 1000 #define VSOMEIP_SD_DEFAULT_REQUEST_RESPONSE_DELAY 2000 diff --git a/implementation/service_discovery/include/deserializer.hpp b/implementation/service_discovery/include/deserializer.hpp index 1625e80..085bc7c 100755 --- a/implementation/service_discovery/include/deserializer.hpp +++ b/implementation/service_discovery/include/deserializer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/include/entry_impl.hpp b/implementation/service_discovery/include/entry_impl.hpp index fde425c..25f08d2 100755 --- a/implementation/service_discovery/include/entry_impl.hpp +++ b/implementation/service_discovery/include/entry_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -46,8 +46,7 @@ public: void set_ttl(ttl_t _ttl);
const std::vector<uint8_t> & get_options(uint8_t _run) const;
- void assign_option(const std::shared_ptr<option_impl> &_option,
- uint8_t _run);
+ void assign_option(const std::shared_ptr<option_impl> &_option);
bool is_service_entry() const;
bool is_eventgroup_entry() const;
diff --git a/implementation/service_discovery/include/enumeration_types.hpp b/implementation/service_discovery/include/enumeration_types.hpp index 016fdae..6fb66f2 100644 --- a/implementation/service_discovery/include/enumeration_types.hpp +++ b/implementation/service_discovery/include/enumeration_types.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/service_discovery/include/eventgroupentry_impl.hpp b/implementation/service_discovery/include/eventgroupentry_impl.hpp index cde7497..0eb8893 100755 --- a/implementation/service_discovery/include/eventgroupentry_impl.hpp +++ b/implementation/service_discovery/include/eventgroupentry_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -20,11 +20,22 @@ public: eventgroup_t get_eventgroup() const;
void set_eventgroup(eventgroup_t _eventgroup);
+ uint16_t get_reserved() const;
+ void set_reserved(uint16_t _reserved);
+
+ uint8_t get_counter() const;
+ void set_counter(uint8_t _counter);
+
bool serialize(vsomeip::serializer *_to) const;
bool deserialize(vsomeip::deserializer *_from);
private:
eventgroup_t eventgroup_;
+ uint16_t reserved_;
+
+ // counter field to differentiate parallel subscriptions on same event group
+ // 4Bit only (max 16. parralel subscriptions)
+ uint8_t counter_;
};
} // namespace sd
diff --git a/implementation/service_discovery/include/fsm_base.hpp b/implementation/service_discovery/include/fsm_base.hpp index 13b7158..ede92d3 100644 --- a/implementation/service_discovery/include/fsm_base.hpp +++ b/implementation/service_discovery/include/fsm_base.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -19,15 +19,17 @@ public: fsm_base(boost::asio::io_service &_io); virtual ~fsm_base(); - void start_timer(uint32_t _ms); - void stop_timer(); + void start_timer(uint32_t _ms, bool _use_alt_timer = false); + void stop_timer(bool _use_alt_timer = false); - uint32_t expired_from_now(); + uint32_t expired_from_now(bool _use_alt_timer = false); - virtual void timer_expired(const boost::system::error_code &_error) = 0; + virtual void timer_expired(const boost::system::error_code &_error, + bool _use_alt_timer) = 0; private: boost::asio::system_timer timer_; + boost::asio::system_timer alt_timer_; }; } // namespace sd diff --git a/implementation/service_discovery/include/fsm_events.hpp b/implementation/service_discovery/include/fsm_events.hpp index 1624b00..75279e2 100644 --- a/implementation/service_discovery/include/fsm_events.hpp +++ b/implementation/service_discovery/include/fsm_events.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -9,6 +9,7 @@ #include <boost/statechart/event.hpp> #include <vsomeip/primitive_types.hpp> +#include "../../routing/include/serviceinfo.hpp" namespace sc = boost::statechart; @@ -21,6 +22,9 @@ struct ev_none: sc::event<ev_none> { struct ev_timeout: sc::event<ev_timeout> { }; +struct ev_alt_timeout: sc::event<ev_alt_timeout> { +}; + struct ev_status_change: sc::event<ev_status_change> { ev_status_change(bool _is_up) : is_up_(_is_up) { @@ -31,22 +35,25 @@ struct ev_status_change: sc::event<ev_status_change> { struct ev_find_service: sc::event<ev_find_service> { - ev_find_service(service_t _service, instance_t _instance, - major_version_t _major, minor_version_t _minor, ttl_t _ttl) - : service_(_service), instance_(_instance), major_(_major), minor_( - _minor), ttl_(_ttl) { + ev_find_service(const std::shared_ptr<const serviceinfo> &_info, service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, bool _unicast_flag) + : info_(_info), service_(_service), instance_(_instance), major_(_major), minor_( + _minor), unicast_flag_(_unicast_flag) { } - + const std::shared_ptr<const serviceinfo> &info_; service_t service_; instance_t instance_; major_version_t major_; minor_version_t minor_; - ttl_t ttl_; + bool unicast_flag_; }; struct ev_offer_change: sc::event<ev_offer_change> { }; +struct ev_request_service: sc::event<ev_request_service> { +}; + } // namespace sd } // namespace vsomeip diff --git a/implementation/service_discovery/include/ip_option_impl.hpp b/implementation/service_discovery/include/ip_option_impl.hpp index 8fd426b..e753b4e 100644 --- a/implementation/service_discovery/include/ip_option_impl.hpp +++ b/implementation/service_discovery/include/ip_option_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/service_discovery/include/ipv4_option_impl.hpp b/implementation/service_discovery/include/ipv4_option_impl.hpp index b8051cc..c233f0f 100644 --- a/implementation/service_discovery/include/ipv4_option_impl.hpp +++ b/implementation/service_discovery/include/ipv4_option_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/include/ipv6_option_impl.hpp b/implementation/service_discovery/include/ipv6_option_impl.hpp index 48938b0..c2b962f 100644 --- a/implementation/service_discovery/include/ipv6_option_impl.hpp +++ b/implementation/service_discovery/include/ipv6_option_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/include/load_balancing_option_impl.hpp b/implementation/service_discovery/include/load_balancing_option_impl.hpp index 0308a06..7504657 100755 --- a/implementation/service_discovery/include/load_balancing_option_impl.hpp +++ b/implementation/service_discovery/include/load_balancing_option_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/include/message_element_impl.hpp b/implementation/service_discovery/include/message_element_impl.hpp index 39ae3a1..c05b76e 100755 --- a/implementation/service_discovery/include/message_element_impl.hpp +++ b/implementation/service_discovery/include/message_element_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/include/message_impl.hpp b/implementation/service_discovery/include/message_impl.hpp index b0702df..a8573b8 100755 --- a/implementation/service_discovery/include/message_impl.hpp +++ b/implementation/service_discovery/include/message_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -14,6 +14,16 @@ #include "../include/primitive_types.hpp"
#include "../../message/include/message_base_impl.hpp"
+# if _MSC_VER >= 1300
+/*
+* Diamond inheritance is used for the vsomeip::message_base base class.
+* The Microsoft compiler put warning (C4250) using a desired c++ feature: "Delegating to a sister class"
+* A powerful technique that arises from using virtual inheritance is to delegate a method from a class in another class
+* by using a common abstract base class. This is also called cross delegation.
+*/
+# pragma warning( disable : 4250 )
+# endif
+
namespace vsomeip {
namespace sd {
diff --git a/implementation/service_discovery/include/option_impl.hpp b/implementation/service_discovery/include/option_impl.hpp index 90a6a48..21e8b9c 100644 --- a/implementation/service_discovery/include/option_impl.hpp +++ b/implementation/service_discovery/include/option_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/include/primitive_types.hpp b/implementation/service_discovery/include/primitive_types.hpp index fd12698..13f4478 100644 --- a/implementation/service_discovery/include/primitive_types.hpp +++ b/implementation/service_discovery/include/primitive_types.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/service_discovery/include/protection_option_impl.hpp b/implementation/service_discovery/include/protection_option_impl.hpp index 565b22b..e1f8d1e 100755 --- a/implementation/service_discovery/include/protection_option_impl.hpp +++ b/implementation/service_discovery/include/protection_option_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/include/request.hpp b/implementation/service_discovery/include/request.hpp index 9e62deb..99fe507 100644 --- a/implementation/service_discovery/include/request.hpp +++ b/implementation/service_discovery/include/request.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -29,10 +29,15 @@ public: ttl_t get_ttl() const; void set_ttl(ttl_t _ttl); + uint8_t get_sent_counter() const; + void set_sent_counter(uint8_t _sent_counter); + private: major_version_t major_; minor_version_t minor_; ttl_t ttl_; + + uint8_t sent_counter_; }; } // namespace sd diff --git a/implementation/service_discovery/include/runtime.hpp b/implementation/service_discovery/include/runtime.hpp index 47255a2..656e2d5 100644 --- a/implementation/service_discovery/include/runtime.hpp +++ b/implementation/service_discovery/include/runtime.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/include/runtime_impl.hpp b/implementation/service_discovery/include/runtime_impl.hpp index cc0e14e..111d56e 100644 --- a/implementation/service_discovery/include/runtime_impl.hpp +++ b/implementation/service_discovery/include/runtime_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/service_discovery/include/service_discovery.hpp b/implementation/service_discovery/include/service_discovery.hpp index 894de0c..ebc81fa 100644 --- a/implementation/service_discovery/include/service_discovery.hpp +++ b/implementation/service_discovery/include/service_discovery.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -11,6 +11,8 @@ #include <vsomeip/primitive_types.hpp> #include <vsomeip/enumeration_types.hpp> +#include "../../routing/include/serviceinfo.hpp" +#include "../../endpoints/include/endpoint.hpp" namespace vsomeip { @@ -41,12 +43,28 @@ public: eventgroup_t _eventgroup, client_t _client) = 0; virtual void unsubscribe_all(service_t _service, instance_t _instance) = 0; - virtual void send(bool _is_announcing) = 0; + virtual bool send(bool _is_announcing, bool _is_find = false) = 0; virtual void on_message(const byte_t *_data, length_t _length, - const boost::asio::ip::address &_sender) = 0; + const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_destination) = 0; virtual void on_offer_change() = 0; + + virtual void send_subscriptions(service_t _service, instance_t _instance, + client_t _client, bool _reliable) = 0; + + virtual void send_unicast_offer_service(const std::shared_ptr<const serviceinfo> &_info, + service_t _service, instance_t _instance, + major_version_t _major, + minor_version_t _minor) = 0; + virtual void send_multicast_offer_service(const std::shared_ptr<const serviceinfo>& _info, + service_t _service, instance_t _instance, + major_version_t _major, + minor_version_t _minor) = 0; + virtual void on_reliable_endpoint_connected( + service_t _service, instance_t _instance, + const std::shared_ptr<const vsomeip::endpoint> &_endpoint) = 0; }; } // namespace sd diff --git a/implementation/service_discovery/include/service_discovery_fsm.hpp b/implementation/service_discovery/include/service_discovery_fsm.hpp index f3fe7fd..915b3e3 100644 --- a/implementation/service_discovery/include/service_discovery_fsm.hpp +++ b/implementation/service_discovery/include/service_discovery_fsm.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -14,6 +14,8 @@ #include <boost/statechart/state.hpp> #include <boost/statechart/state_machine.hpp> #include <boost/statechart/transition.hpp> +#include "../../routing/include/serviceinfo.hpp" + #include "../include/fsm_base.hpp" #include "../include/fsm_events.hpp" @@ -40,7 +42,8 @@ struct fsm: sc::state_machine<fsm, inactive>, public fsm_base { void set_fsm(std::shared_ptr<service_discovery_fsm> _fsm); - void timer_expired(const boost::system::error_code &_error); + void timer_expired(const boost::system::error_code &_error, + bool _use_alt_timeout); uint32_t initial_delay_; uint32_t repetitions_base_delay_; @@ -95,9 +98,15 @@ struct repeat: sc::state<repeat, active> { sc::result react(const ev_find_service &_event); }; -struct announce: sc::state<announce, active> { +struct offer; +struct find; +struct main: sc::state<main, active, mpl::list<offer, find>> { + main(my_context _context); +}; + +struct offer: sc::state<offer, main::orthogonal<0> > { - announce(my_context _context); + offer(my_context _context); typedef mpl::list<sc::custom_reaction<ev_timeout>, sc::custom_reaction<ev_find_service>, @@ -106,9 +115,39 @@ struct announce: sc::state<announce, active> { sc::result react(const ev_timeout &_event); sc::result react(const ev_find_service &_event); sc::result react(const ev_offer_change &_event); + + uint8_t run_; +}; + +struct idle; +struct find: sc::state<find, main::orthogonal<1>, idle> { + + find(my_context _context); + + uint8_t run_; +}; + +struct idle: sc::state<idle, find> { + idle(my_context _context); + + typedef mpl::list<sc::custom_reaction<ev_request_service> >reactions; + + sc::result react(const ev_request_service &_event); }; -} // namespace _offer +struct send: sc::state<send, find> { + send(my_context _context); + + typedef mpl::list< + sc::custom_reaction<ev_alt_timeout>, + sc::custom_reaction<ev_none> + > reactions; + + sc::result react(const ev_alt_timeout &_event); + sc::result react(const ev_none &_event); +}; + +} // namespace _sd /////////////////////////////////////////////////////////////////////////////// // Interface @@ -121,13 +160,36 @@ public: void start(); void stop(); - void send(bool _is_announcing); + bool send(bool _is_announcing, bool _is_find = false); + + void send_unicast_offer_service( + const std::shared_ptr<const serviceinfo> &_info, + service_t _service, instance_t _instance, + major_version_t _major, + minor_version_t _minor); + + void send_multicast_offer_service( + const std::shared_ptr<const serviceinfo> &_info, + service_t _service, instance_t _instance, + major_version_t _major, + minor_version_t _minor); inline void process(const sc::event_base &_event) { std::lock_guard<std::mutex> its_lock(lock_); fsm_->process_event(_event); } + inline uint8_t get_repetition_max() const { + if (!fsm_) + return 0; + + return fsm_->repetitions_max_; + } + + std::chrono::milliseconds get_elapsed_offer_timer(); + + bool check_is_multicast_offer(); + private: std::weak_ptr<service_discovery> discovery_; std::shared_ptr<_sd::fsm> fsm_; diff --git a/implementation/service_discovery/include/service_discovery_host.hpp b/implementation/service_discovery/include/service_discovery_host.hpp index 27d8007..1795d89 100644 --- a/implementation/service_discovery/include/service_discovery_host.hpp +++ b/implementation/service_discovery/include/service_discovery_host.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -41,7 +41,7 @@ public: bool _flush) = 0; virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target, - const byte_t *_data, uint32_t _size) = 0; + const byte_t *_data, uint32_t _size, uint16_t _sd_port) = 0; virtual void add_routing_info(service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, ttl_t _ttl, @@ -53,12 +53,14 @@ public: virtual void del_routing_info(service_t _service, instance_t _instance, bool _has_reliable, bool _has_unreliable) = 0; - virtual ttl_t update_routing_info(ttl_t _elapsed) = 0; + virtual std::chrono::milliseconds update_routing_info( + std::chrono::milliseconds _elapsed) = 0; virtual void on_subscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, std::shared_ptr<endpoint_definition> _subscriber, - std::shared_ptr<endpoint_definition> _target) = 0; + std::shared_ptr<endpoint_definition> _target, + const std::chrono::high_resolution_clock::time_point &_expiration) = 0; virtual void on_unsubscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, @@ -67,11 +69,27 @@ public: virtual void on_subscribe_ack(service_t _service, instance_t _instance, const boost::asio::ip::address &_address, uint16_t _port) = 0; - virtual std::shared_ptr<endpoint> find_or_create_remote_client(service_t _service, - instance_t _instance, bool _reliable, client_t _client) = 0; + virtual void on_subscribe_ack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) = 0; + + virtual std::shared_ptr<endpoint> find_or_create_remote_client( + service_t _service, instance_t _instance, + bool _reliable, client_t _client) = 0; virtual void expire_subscriptions(const boost::asio::ip::address &_address) = 0; virtual void expire_services(const boost::asio::ip::address &_address) = 0; + + virtual bool on_subscribe_accepted(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, std::shared_ptr<endpoint_definition> _target, + const std::chrono::high_resolution_clock::time_point &_expiration) = 0; + + virtual void on_subscribe_nack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) = 0; + + virtual bool has_identified(client_t _client, service_t _service, + instance_t _instance, bool _reliable) = 0; + + virtual std::chrono::high_resolution_clock::time_point expire_subscriptions() = 0; }; } // namespace sd diff --git a/implementation/service_discovery/include/service_discovery_impl.hpp b/implementation/service_discovery/include/service_discovery_impl.hpp index 7efb6eb..4e64328 100644 --- a/implementation/service_discovery/include/service_discovery_impl.hpp +++ b/implementation/service_discovery/include/service_discovery_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -14,8 +14,11 @@ #include <boost/asio/system_timer.hpp> #include "service_discovery.hpp" +#include "../../endpoints/include/endpoint_definition.hpp" #include "../../routing/include/types.hpp" #include "ip_option_impl.hpp" +#include "ipv4_option_impl.hpp" +#include "ipv6_option_impl.hpp" namespace vsomeip { @@ -35,6 +38,15 @@ class subscription; typedef std::map<service_t, std::map<instance_t, std::shared_ptr<request> > > requests_t; +struct accepted_subscriber_t { + std::shared_ptr < endpoint_definition > subscriber; + std::shared_ptr < endpoint_definition > target; + std::chrono::high_resolution_clock::time_point its_expiration; + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::eventgroup_t eventgroup_; +}; + class service_discovery_impl: public service_discovery, public std::enable_shared_from_this<service_discovery_impl> { public: @@ -59,18 +71,36 @@ public: eventgroup_t _eventgroup, client_t _client); void unsubscribe_all(service_t _service, instance_t _instance); - void send(bool _is_announcing); + bool send(bool _is_announcing, bool _is_find); void on_message(const byte_t *_data, length_t _length, - const boost::asio::ip::address &_sender); + const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_destination); void on_offer_change(); + void send_unicast_offer_service(const std::shared_ptr<const serviceinfo> &_info, + service_t _service, instance_t _instance, + major_version_t _major, + minor_version_t _minor); + + void send_multicast_offer_service(const std::shared_ptr<const serviceinfo>& _info, + service_t _service, instance_t _instance, + major_version_t _major, + minor_version_t _minor); + + void on_reliable_endpoint_connected( + service_t _service, instance_t _instance, + const std::shared_ptr<const vsomeip::endpoint> &_endpoint); + private: + + std::pair<session_t, bool> get_session(const boost::asio::ip::address &_address); void increment_session(const boost::asio::ip::address &_address); - bool is_reboot(const boost::asio::ip::address &_address, + bool is_reboot(const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_destination, bool _reboot_flag, session_t _session); void insert_option(std::shared_ptr<message_impl> &_message, @@ -78,24 +108,29 @@ private: const boost::asio::ip::address &_address, uint16_t _port, bool _is_reliable); void insert_find_entries(std::shared_ptr<message_impl> &_message, - requests_t &_requests); + requests_t &_requests, uint32_t _start, uint32_t &_size, bool &_done); void insert_offer_entries(std::shared_ptr<message_impl> &_message, - services_t &_services); - void insert_offer_service(std::shared_ptr<message_impl> _message, + services_t &_services, uint32_t &_start, uint32_t _size, bool &_done); + bool insert_offer_service(std::shared_ptr<message_impl> _message, service_t _service, instance_t _instance, - const std::shared_ptr<const serviceinfo> &_info); + const std::shared_ptr<const serviceinfo> &_info, + uint32_t &_size); void insert_subscription(std::shared_ptr<message_impl> &_message, service_t _service, instance_t _instance, eventgroup_t _eventgroup, + std::shared_ptr<subscription> &_subscription, bool _insert_reliable, bool _insert_unreliable); + void insert_nack_subscription_on_resubscribe(std::shared_ptr<message_impl> &_message, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, std::shared_ptr<subscription> &_subscription); void insert_subscription_ack(std::shared_ptr<message_impl> &_message, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - std::shared_ptr<eventgroupinfo> &_info, ttl_t _ttl); + std::shared_ptr<eventgroupinfo> &_info, ttl_t _ttl, uint8_t _counter, major_version_t _major, uint16_t _reserved); void insert_subscription_nack(std::shared_ptr<message_impl> &_message, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - std::shared_ptr<eventgroupinfo> &_info); + uint8_t _counter, major_version_t _major, uint16_t _reserved); void process_serviceentry(std::shared_ptr<serviceentry_impl> &_entry, - const std::vector<std::shared_ptr<option_impl> > &_options); + const std::vector<std::shared_ptr<option_impl> > &_options, + bool _unicast_flag); void process_offerservice_serviceentry( service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, ttl_t _ttl, @@ -103,39 +138,63 @@ private: uint16_t _reliable_port, const boost::asio::ip::address &_unreliable_address, uint16_t _unreliable_port); - void send_unicast_offer_service(const std::shared_ptr<const serviceinfo>& _info, - service_t _service, instance_t _instance, - major_version_t _major, - minor_version_t _minor); - void process_findservice_serviceentry(service_t _service, - instance_t _instance, - major_version_t _major, - minor_version_t _minor); - void process_eventgroupentry(std::shared_ptr<eventgroupentry_impl> &_entry, - const std::vector<std::shared_ptr<option_impl> > &_options); + void send_offer_service( + const std::shared_ptr<const serviceinfo> &_info, service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor, + bool _unicast_flag); + void process_findservice_serviceentry(service_t _service, + instance_t _instance, + major_version_t _major, + minor_version_t _minor, + bool _unicast_flag); + void process_eventgroupentry( + std::shared_ptr<eventgroupentry_impl> &_entry, + const std::vector<std::shared_ptr<option_impl> > &_options, + std::shared_ptr < message_impl > &its_message_response, + std::vector <accepted_subscriber_t> &accepted_subscribers); void handle_eventgroup_subscription(service_t _service, instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, ttl_t _ttl, - const boost::asio::ip::address &_reliable_address, - uint16_t _reliable_port, uint16_t _unreliable_port); + major_version_t _major, ttl_t _ttl, uint8_t _counter, uint16_t _reserved, + const boost::asio::ip::address &_first_address, uint16_t _first_port, + bool _is_first_reliable, + const boost::asio::ip::address &_second_address, uint16_t _second_port, + bool _is_second_reliable, + std::shared_ptr < message_impl > &its_message, + std::vector <accepted_subscriber_t> &accepted_subscribers); void handle_eventgroup_subscription_ack(service_t _service, instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, ttl_t _ttl, + major_version_t _major, ttl_t _ttl, uint8_t _counter, const boost::asio::ip::address &_address, uint16_t _port); + void handle_eventgroup_subscription_nack(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, uint8_t _counter); void serialize_and_send(std::shared_ptr<message_impl> _message, const boost::asio::ip::address &_address); + bool is_tcp_connected(service_t _service, + instance_t _instance, + std::shared_ptr<vsomeip::endpoint_definition> its_endpoint); + void start_ttl_timer(); - ttl_t stop_ttl_timer(); + std::chrono::milliseconds stop_ttl_timer(); + void check_ttl(const boost::system::error_code &_error); boost::asio::ip::address get_current_remote_address() const; + + void start_subscription_expiration_timer(); + void stop_subscription_expiration_timer(); + void expire_subscriptions(const boost::system::error_code &_error); + + bool check_ipv4_address(boost::asio::ip::address its_address); + bool check_static_header_fields( const std::shared_ptr<const message> &_message) const; void send_eventgroup_subscription_nack(service_t _service, instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major); + major_version_t _major, + uint8_t _counter, + uint16_t _reserved); bool check_layer_four_protocol( const std::shared_ptr<const ip_option_impl> _ip_option) const; void get_subscription_endpoints(subscription_type_e _subscription_type, @@ -146,6 +205,28 @@ private: service_t _service, instance_t _instance, client_t _client) const; + void send_subscriptions(service_t _service, instance_t _instance, client_t _client, bool _reliable); + + template<class Option, typename AddressType> + std::shared_ptr<option_impl> find_existing_option( + std::shared_ptr<message_impl> &_message, + AddressType _address, uint16_t _port, + layer_four_protocol_e _protocol, + option_type_e _option_type); + template<class Option, typename AddressType> + bool check_message_for_ip_option_and_assign_existing( + std::shared_ptr<message_impl> &_message, + std::shared_ptr<entry_impl> _entry, AddressType _address, + uint16_t _port, layer_four_protocol_e _protocol, + option_type_e _option_type); + template<class Option, typename AddressType> + void assign_ip_option_to_entry(std::shared_ptr<Option> _option, + AddressType _address, uint16_t _port, + layer_four_protocol_e _protocol, + std::shared_ptr<entry_impl> _entry); + + std::shared_ptr<request> find_request(service_t _service, instance_t _instance); + private: boost::asio::io_service &io_; service_discovery_host *host_; @@ -165,25 +246,31 @@ private: std::mutex requested_mutex_; std::map<service_t, std::map<instance_t, - std::map<eventgroup_t, std::map<client_t, std::shared_ptr<subscription> > > > > subscribed_; + std::map<eventgroup_t, + std::map<client_t, + std::shared_ptr<subscription> > > > > subscribed_; std::mutex subscribed_mutex_; std::mutex serialize_mutex_; // Sessions - std::map<boost::asio::ip::address, std::pair<session_t, bool> > sessions_; - std::map<boost::asio::ip::address, session_t > sessions_receiving_; - - // Reboots - std::set<boost::asio::ip::address> reboots_; + std::map<boost::asio::ip::address, std::pair<session_t, bool> > sessions_sent_; + std::map<boost::asio::ip::address, + std::tuple<session_t, session_t, bool> > sessions_received_; // Runtime std::weak_ptr<runtime> runtime_; - // TTL handling + // TTL handling for services offered by other hosts boost::asio::system_timer ttl_timer_; - ttl_t smallest_ttl_; + std::chrono::milliseconds smallest_ttl_; ttl_t ttl_; + + // TTL handling for subscriptions done by other hosts + boost::asio::system_timer subscription_expiration_timer_; + std::chrono::high_resolution_clock::time_point next_subscription_expiration_; + + uint32_t max_message_size_; }; } // namespace sd diff --git a/implementation/service_discovery/include/serviceentry_impl.hpp b/implementation/service_discovery/include/serviceentry_impl.hpp index f83e62a..1385f84 100644 --- a/implementation/service_discovery/include/serviceentry_impl.hpp +++ b/implementation/service_discovery/include/serviceentry_impl.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/include/subscription.hpp b/implementation/service_discovery/include/subscription.hpp index 25df7b3..eb2fb66 100644 --- a/implementation/service_discovery/include/subscription.hpp +++ b/implementation/service_discovery/include/subscription.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -6,6 +6,7 @@ #ifndef VSOMEIP_SD_SUBSCRIPTION_HPP #define VSOMEIP_SD_SUBSCRIPTION_HPP +#include <chrono> #include <memory> #include <vsomeip/primitive_types.hpp> @@ -22,7 +23,9 @@ public: subscription(major_version_t _major, ttl_t _ttl, std::shared_ptr<endpoint> _reliable, std::shared_ptr<endpoint> _unreliable, - subscription_type_e _subscription_type); + subscription_type_e _subscription_type, + uint8_t _counter, + std::chrono::high_resolution_clock::time_point _expiration); ~subscription(); major_version_t get_major() const; @@ -34,8 +37,16 @@ public: bool is_acknowledged() const; void set_acknowledged(bool _is_acknowledged); + bool is_tcp_connection_established() const; + void set_tcp_connection_established(bool _is_established); + subscription_type_e get_subscription_type() const; + uint8_t get_counter() const; + + std::chrono::high_resolution_clock::time_point get_expiration() const; + void set_expiration(std::chrono::high_resolution_clock::time_point _expiration); + private: major_version_t major_; ttl_t ttl_; @@ -44,8 +55,13 @@ private: std::shared_ptr<endpoint> unreliable_; bool is_acknowledged_; + bool tcp_connection_established_; subscription_type_e subscription_type_; + + uint8_t counter_; + + std::chrono::high_resolution_clock::time_point expiration_; }; } // namespace sd diff --git a/implementation/service_discovery/src/configuration_option_impl.cpp b/implementation/service_discovery/src/configuration_option_impl.cpp index 793ec95..933f7b1 100755 --- a/implementation/service_discovery/src/configuration_option_impl.cpp +++ b/implementation/service_discovery/src/configuration_option_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -92,38 +92,36 @@ bool configuration_option_impl::serialize(vsomeip::serializer *_to) const { bool configuration_option_impl::deserialize(vsomeip::deserializer *_from) {
bool is_successful = option_impl::deserialize(_from);
- uint16_t l_length = 0;
- uint8_t l_itemLength;
+ uint8_t l_itemLength = 0;
std::string l_item(256, 0), l_key, l_value;
- is_successful = is_successful && _from->deserialize(l_length);
- if (l_length > _from->get_remaining()) {
- _from->set_remaining(0);
- return false;
- }
-
- if (l_length > 0) {
- do {
- is_successful = is_successful && _from->deserialize(l_itemLength);
- if (l_itemLength == 0)
- break;
-
- l_length = uint16_t(l_length - l_itemLength);
+ do {
+ l_itemLength = 0;
+ l_key.clear();
+ l_value.clear();
+ l_item.assign(256, '\0');
+ 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);
- size_t l_eqPos = l_item.find('=');
- l_key = l_item.substr(0, l_eqPos);
- l_value = l_item.substr(l_eqPos + 1);
-
- if (configuration_.end() == configuration_.find(l_key)) {
- configuration_[l_key] = l_value;
- } else {
- is_successful = false;
+ if (is_successful) {
+ size_t l_eqPos = l_item.find('='); //SWS_SD_00292
+ l_key = l_item.substr(0, l_eqPos);
+
+ //if no "=" is found, no value is present for key (SWS_SD_00466)
+ if( l_eqPos != std::string::npos )
+ l_value = l_item.substr(l_eqPos + 1);
+ if (configuration_.end() == configuration_.find(l_key)) {
+ configuration_[l_key] = l_value;
+ } else {
+ // TODO: log reason for failing deserialization
+ is_successful = false;
+ }
}
- } while (l_length > 0);
- }
+ }
+ } while (is_successful && _from->get_remaining() > 0);
return is_successful;
}
diff --git a/implementation/service_discovery/src/deserializer.cpp b/implementation/service_discovery/src/deserializer.cpp index cb86c52..744c463 100644 --- a/implementation/service_discovery/src/deserializer.cpp +++ b/implementation/service_discovery/src/deserializer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/src/entry_impl.cpp b/implementation/service_discovery/src/entry_impl.cpp index ea7a511..efff9da 100755 --- a/implementation/service_discovery/src/entry_impl.cpp +++ b/implementation/service_discovery/src/entry_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -85,20 +85,27 @@ const std::vector<uint8_t> & entry_impl::get_options(uint8_t _run) const { return invalid_options;
}
-void entry_impl::assign_option(const std::shared_ptr<option_impl> &_option,
- uint8_t _run) {
- if (_run > 0 && _run <= VSOMEIP_MAX_OPTION_RUN) {
- _run--; // Index = Run-1
-
- uint8_t option_index = uint8_t(get_owning_message()->get_option_index(_option));
- if (0x10 > option_index) { // as we have only a nibble for the option counter
- options_[_run].push_back(option_index);
- std::sort(options_[_run].begin(), options_[_run].end());
+void entry_impl::assign_option(const std::shared_ptr<option_impl> &_option) {
+ uint8_t option_index = uint8_t(get_owning_message()->get_option_index(_option));
+ if (0x10 > option_index) { // as we have only a nibble for the option counter
+ if (options_[0].empty() ||
+ options_[0][0] == option_index + 1 ||
+ options_[0][options_[0].size() - 1] + 1 == option_index) {
+ options_[0].push_back(option_index);
+ std::sort(options_[0].begin(), options_[0].end());
+ num_options_[0]++;
+ } else
+ if (options_[1].empty() ||
+ options_[1][0] == option_index + 1 ||
+ options_[1][options_[1].size() - 1] + 1 == option_index) {
+ options_[1].push_back(option_index);
+ std::sort(options_[1].begin(), options_[1].end());
+ num_options_[1]++;
} else {
- // TODO: decide what to do if option does not belong to the message.
+ // TODO: copy data
}
} else {
- // TODO: decide what to do if an illegal index for the option run is provided
+ // TODO: decide what to do if option does not belong to the message.
}
}
diff --git a/implementation/service_discovery/src/eventgroupentry_impl.cpp b/implementation/service_discovery/src/eventgroupentry_impl.cpp index 024756d..220fc47 100755 --- a/implementation/service_discovery/src/eventgroupentry_impl.cpp +++ b/implementation/service_discovery/src/eventgroupentry_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -13,11 +13,13 @@ namespace sd { eventgroupentry_impl::eventgroupentry_impl() {
eventgroup_ = 0xFFFF;
+ counter_ = 0;
}
eventgroupentry_impl::eventgroupentry_impl(const eventgroupentry_impl &_entry)
: entry_impl(_entry) {
eventgroup_ = _entry.eventgroup_;
+ counter_ = _entry.counter_;
}
eventgroupentry_impl::~eventgroupentry_impl() {
@@ -31,6 +33,22 @@ void eventgroupentry_impl::set_eventgroup(eventgroup_t _eventgroup) { eventgroup_ = _eventgroup;
}
+uint16_t eventgroupentry_impl::get_reserved() const {
+ return reserved_;
+}
+
+void eventgroupentry_impl::set_reserved(uint16_t _reserved) {
+ reserved_ = _reserved;
+}
+
+uint8_t eventgroupentry_impl::get_counter() const {
+ return counter_;
+}
+
+void eventgroupentry_impl::set_counter(uint8_t _counter) {
+ counter_ = _counter;
+}
+
bool eventgroupentry_impl::serialize(vsomeip::serializer *_to) const {
bool is_successful = entry_impl::serialize(_to);
@@ -39,9 +57,25 @@ bool eventgroupentry_impl::serialize(vsomeip::serializer *_to) const { is_successful = is_successful
&& _to->serialize(static_cast<uint32_t>(ttl_), true);
- is_successful = is_successful && _to->serialize(protocol::reserved_word);
+ // 4Bit only for counter field
+ if (counter_ >= 16) {
+ is_successful = false;
+ }
+ uint16_t counter_and_reserved = protocol::reserved_word;
+ if (!reserved_ ) {
+ //reserved was not set -> just store counter as uint16
+ counter_and_reserved = static_cast<uint16_t>(counter_);
+ }
+ else {
+ //reserved contains values -> put reserved and counter into 16 bit variable
+ counter_and_reserved = (uint16_t) (((uint16_t) reserved_ << 4) | counter_);
+ }
is_successful = is_successful
+ && _to->serialize((uint8_t)(counter_and_reserved >> 8)); // serialize reserved part 1
+ is_successful = is_successful
+ && _to->serialize((uint8_t)counter_and_reserved); // serialize reserved part 2 and counter
+ is_successful = is_successful
&& _to->serialize(static_cast<uint16_t>(eventgroup_));
return is_successful;
@@ -58,9 +92,20 @@ bool eventgroupentry_impl::deserialize(vsomeip::deserializer *_from) { is_successful = is_successful && _from->deserialize(its_ttl, true);
ttl_ = static_cast<ttl_t>(its_ttl);
- uint16_t its_reserved1;
- is_successful = is_successful && _from->deserialize(its_reserved1);
+ uint8_t reserved1, reserved2;
+ is_successful = is_successful && _from->deserialize(reserved1); // deserialize reserved part 1
+ is_successful = is_successful && _from->deserialize(reserved2); // deserialize reserved part 2 and counter
+
+ reserved_ = (uint16_t) (((uint16_t)reserved1 << 8) | reserved2); // combine reserved parts and counter
+ reserved_ = (uint16_t) (reserved_ >> 4); //remove counter from reserved field
+
+ //set 4 bits of reserved part 2 field to zero
+ counter_ = (uint8_t) (reserved2 & (~(0xF0)));
+ // 4Bit only for counter field
+ if (counter_ >= 16) {
+ is_successful = false;
+ }
uint16_t its_eventgroup = 0;
is_successful = is_successful && _from->deserialize(its_eventgroup);
eventgroup_ = static_cast<eventgroup_t>(its_eventgroup);
diff --git a/implementation/service_discovery/src/fsm_base.cpp b/implementation/service_discovery/src/fsm_base.cpp index 07a0def..e3c234b 100644 --- a/implementation/service_discovery/src/fsm_base.cpp +++ b/implementation/service_discovery/src/fsm_base.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -9,26 +9,42 @@ namespace vsomeip { namespace sd { fsm_base::fsm_base(boost::asio::io_service &_io) - : timer_(_io) { + : timer_(_io), alt_timer_(_io) { } fsm_base::~fsm_base() { } -void fsm_base::start_timer(uint32_t _milliseconds) { - timer_.expires_from_now(std::chrono::milliseconds(_milliseconds)); - timer_.async_wait( - std::bind(&fsm_base::timer_expired, shared_from_this(), - std::placeholders::_1)); +void fsm_base::start_timer(uint32_t _milliseconds, bool _use_alt_timer) { + if (_use_alt_timer) { + alt_timer_.expires_from_now(std::chrono::milliseconds(_milliseconds)); + alt_timer_.async_wait( + std::bind(&fsm_base::timer_expired, shared_from_this(), + std::placeholders::_1, true)); + } else { + timer_.expires_from_now(std::chrono::milliseconds(_milliseconds)); + timer_.async_wait( + std::bind(&fsm_base::timer_expired, shared_from_this(), + std::placeholders::_1, false)); + } } -void fsm_base::stop_timer() { - timer_.cancel(); +void fsm_base::stop_timer(bool _use_alt_timer) { + if (_use_alt_timer) { + alt_timer_.cancel(); + } else { + timer_.cancel(); + } } -uint32_t fsm_base::expired_from_now() { - return (uint32_t) std::chrono::duration_cast < std::chrono::milliseconds - > (timer_.expires_from_now()).count(); +uint32_t fsm_base::expired_from_now(bool _use_alt_timer) { + if (_use_alt_timer) { + return (uint32_t) std::chrono::duration_cast < std::chrono::milliseconds + > (alt_timer_.expires_from_now()).count(); + } else { + return (uint32_t) std::chrono::duration_cast < std::chrono::milliseconds + > (timer_.expires_from_now()).count(); + } } } // namespace sd diff --git a/implementation/service_discovery/src/ip_option_impl.cpp b/implementation/service_discovery/src/ip_option_impl.cpp index 3fcffac..08f78b9 100644 --- a/implementation/service_discovery/src/ip_option_impl.cpp +++ b/implementation/service_discovery/src/ip_option_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/service_discovery/src/ipv4_option_impl.cpp b/implementation/service_discovery/src/ipv4_option_impl.cpp index ca5a2c5..9f2cec4 100644 --- a/implementation/service_discovery/src/ipv4_option_impl.cpp +++ b/implementation/service_discovery/src/ipv4_option_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -6,6 +6,7 @@ #include <vsomeip/constants.hpp>
#include "../include/constants.hpp"
+#include "../include/defines.hpp"
#include "../include/ipv4_option_impl.hpp"
#include "../../message/include/deserializer.hpp"
#include "../../message/include/serializer.hpp"
@@ -42,7 +43,8 @@ bool ipv4_option_impl::serialize(vsomeip::serializer *_to) const { }
bool ipv4_option_impl::deserialize(vsomeip::deserializer *_from) {
- bool is_successful = option_impl::deserialize(_from);
+ bool is_successful = option_impl::deserialize(_from)
+ && length_ == VSOMEIP_SD_IPV4_OPTION_LENGTH;
uint8_t its_reserved;
_from->deserialize(address_.data(), 4);
_from->deserialize(its_reserved);
diff --git a/implementation/service_discovery/src/ipv6_option_impl.cpp b/implementation/service_discovery/src/ipv6_option_impl.cpp index 1aa2570..089b509 100755 --- a/implementation/service_discovery/src/ipv6_option_impl.cpp +++ b/implementation/service_discovery/src/ipv6_option_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -6,6 +6,7 @@ #include <cstring>
#include "../include/constants.hpp"
+#include "../include/defines.hpp"
#include "../include/ipv6_option_impl.hpp"
#include "../../message/include/deserializer.hpp"
#include "../../message/include/serializer.hpp"
@@ -42,7 +43,8 @@ bool ipv6_option_impl::serialize(vsomeip::serializer *_to) const { }
bool ipv6_option_impl::deserialize(vsomeip::deserializer *_from) {
- bool is_successful = option_impl::deserialize(_from);
+ bool is_successful = option_impl::deserialize(_from)
+ && length_ == VSOMEIP_SD_IPV6_OPTION_LENGTH;;
uint8_t its_reserved;
_from->deserialize(address_.data(), 16);
_from->deserialize(its_reserved);
diff --git a/implementation/service_discovery/src/load_balancing_option_impl.cpp b/implementation/service_discovery/src/load_balancing_option_impl.cpp index 47a5b70..5c12c39 100755 --- a/implementation/service_discovery/src/load_balancing_option_impl.cpp +++ b/implementation/service_discovery/src/load_balancing_option_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/src/message_element_impl.cpp b/implementation/service_discovery/src/message_element_impl.cpp index 6577115..4c1a683 100755 --- a/implementation/service_discovery/src/message_element_impl.cpp +++ b/implementation/service_discovery/src/message_element_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/src/message_impl.cpp b/implementation/service_discovery/src/message_impl.cpp index 3130dda..8159bd4 100755 --- a/implementation/service_discovery/src/message_impl.cpp +++ b/implementation/service_discovery/src/message_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -204,6 +204,7 @@ bool message_impl::serialize(vsomeip::serializer *_to) const { bool message_impl::deserialize(vsomeip::deserializer *_from) {
bool is_successful;
+ bool option_is_successful(true);
// header
is_successful = header_.deserialize(_from);
@@ -251,12 +252,12 @@ bool message_impl::deserialize(vsomeip::deserializer *_from) { _from->set_remaining(options_length_);
}
- while (is_successful && _from->get_remaining()) {
+ while (option_is_successful && _from->get_remaining()) {
std::shared_ptr < option_impl > its_option(deserialize_option(_from));
if (its_option) {
options_.push_back(its_option);
- } else {
- is_successful = false;
+ } else {
+ option_is_successful = false;
}
}
diff --git a/implementation/service_discovery/src/option_impl.cpp b/implementation/service_discovery/src/option_impl.cpp index cff6d61..71aa085 100755 --- a/implementation/service_discovery/src/option_impl.cpp +++ b/implementation/service_discovery/src/option_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/src/protection_option_impl.cpp b/implementation/service_discovery/src/protection_option_impl.cpp index 7197565..366f531 100755 --- a/implementation/service_discovery/src/protection_option_impl.cpp +++ b/implementation/service_discovery/src/protection_option_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/src/request.cpp b/implementation/service_discovery/src/request.cpp index 8673822..6ed2d66 100644 --- a/implementation/service_discovery/src/request.cpp +++ b/implementation/service_discovery/src/request.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -9,8 +9,7 @@ namespace vsomeip { namespace sd { request::request(major_version_t _major, minor_version_t _minor, ttl_t _ttl) - : major_(_major), minor_(_minor), ttl_(_ttl) { - + : major_(_major), minor_(_minor), ttl_(_ttl), sent_counter_(0) { } major_version_t request::get_major() const { @@ -37,5 +36,13 @@ void request::set_ttl(ttl_t _ttl) { ttl_ = _ttl; } +uint8_t request::get_sent_counter() const { + return sent_counter_; +} + +void request::set_sent_counter(uint8_t _sent_counter) { + sent_counter_ = _sent_counter; +} + } // namespace sd } // namespace vsomeip diff --git a/implementation/service_discovery/src/runtime.cpp b/implementation/service_discovery/src/runtime.cpp index f7d1a4f..be68d24 100644 --- a/implementation/service_discovery/src/runtime.cpp +++ b/implementation/service_discovery/src/runtime.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/service_discovery/src/runtime_impl.cpp b/implementation/service_discovery/src/runtime_impl.cpp index 2cc25d2..187b5bc 100644 --- a/implementation/service_discovery/src/runtime_impl.cpp +++ b/implementation/service_discovery/src/runtime_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/implementation/service_discovery/src/service_discovery_fsm.cpp b/implementation/service_discovery/src/service_discovery_fsm.cpp index d2428dd..a4ede7b 100644 --- a/implementation/service_discovery/src/service_discovery_fsm.cpp +++ b/implementation/service_discovery/src/service_discovery_fsm.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -9,6 +9,8 @@ #include "../include/defines.hpp" #include "../include/service_discovery.hpp" #include "../include/service_discovery_fsm.hpp" +#include "../../routing/include/serviceinfo.hpp" + #include "../../configuration/include/configuration.hpp" #include "../../logging/include/logger.hpp" @@ -31,11 +33,17 @@ void fsm::set_fsm(std::shared_ptr<service_discovery_fsm> _fsm) { fsm_ = _fsm; } -void fsm::timer_expired(const boost::system::error_code &_error) { +void fsm::timer_expired(const boost::system::error_code &_error, + bool _use_alt_timeout) { if (!_error) { std::shared_ptr<service_discovery_fsm> its_fsm = fsm_.lock(); - if (its_fsm) - its_fsm->process(ev_timeout()); + if (its_fsm) { + if (_use_alt_timeout) { + its_fsm->process(ev_alt_timeout()); + } else { + its_fsm->process(ev_timeout()); + } + } } } @@ -96,7 +104,7 @@ sc::result active::react(const ev_status_change &_event) { if (!outermost_context().is_up_) return transit<inactive>(); - return discard_event(); + return forward_event(); } /////////////////////////////////////////////////////////////////////////////// @@ -129,53 +137,142 @@ repeat::repeat(my_context _context) uint32_t its_timeout = (outermost_context().repetitions_base_delay_ << outermost_context().run_); outermost_context().run_++; - fsm->send(false); + (void)fsm->send(false); outermost_context().start_timer(its_timeout); } } sc::result repeat::react(const ev_timeout &_event) { (void)_event; - - if (outermost_context().run_ < outermost_context().repetitions_max_) + if (outermost_context().run_ < outermost_context().repetitions_max_) { return transit<repeat>(); - - return transit<announce>(); + } + return transit<main>(); } sc::result repeat::react(const ev_find_service &_event) { - (void)_event; - return discard_event(); + VSOMEIP_TRACE << "sd::active.repeat.react.find"; + std::shared_ptr < service_discovery_fsm > fsm = + outermost_context().fsm_.lock(); + // Answer Find Service messages with unicast offer in repetition phase + if (fsm) { + fsm->send_unicast_offer_service(_event.info_, _event.service_, _event.instance_, + _event.major_, _event.minor_); + } + return forward_event(); } /////////////////////////////////////////////////////////////////////////////// -// State "Active.Announce" +// State "Active.Main" /////////////////////////////////////////////////////////////////////////////// -announce::announce(my_context _context) - : sc::state<announce, active>(_context) { +main::main(my_context _context) + : sc::state<main, active, mpl::list<offer, find> >(_context) { + VSOMEIP_TRACE << "sd::active.main"; +} + +/////////////////////////////////////////////////////////////////////////////// +// State "Active.Main.Offer" +/////////////////////////////////////////////////////////////////////////////// +offer::offer(my_context _context) + : sc::state<offer, main::orthogonal<0> >(_context) { std::shared_ptr < service_discovery_fsm > fsm = outermost_context().fsm_.lock(); if (fsm) { - VSOMEIP_TRACE << "sd::active.announce"; + VSOMEIP_TRACE << "sd::active.main.offer"; outermost_context().start_timer( outermost_context().cyclic_offer_delay_); - fsm->send(true); + (void)fsm->send(true); } } -sc::result announce::react(const ev_timeout &_event) { +sc::result offer::react(const ev_timeout &_event) { (void)_event; - return transit<announce>(); + return transit<offer>(); } -sc::result announce::react(const ev_find_service &_event) { +sc::result offer::react(const ev_find_service &_event) { + VSOMEIP_TRACE << "sd::active.main.react.find"; + std::shared_ptr < service_discovery_fsm > fsm = + outermost_context().fsm_.lock(); + if (fsm) { + if(_event.unicast_flag_) { + if( !fsm->check_is_multicast_offer()) { // SIP_SD_89 + fsm->send_unicast_offer_service(_event.info_, _event.service_, _event.instance_, + _event.major_, _event.minor_); + } else { // SIP_SD_90 + fsm->send_multicast_offer_service(_event.info_, _event.service_, _event.instance_, + _event.major_, _event.minor_); + } + } else { // SIP_SD_91 + fsm->send_multicast_offer_service(_event.info_, _event.service_, _event.instance_, + _event.major_, _event.minor_); + } + } + return forward_event(); +} + +sc::result offer::react(const ev_offer_change &_event) { (void)_event; - return discard_event(); + return transit<offer>(); +} + +/////////////////////////////////////////////////////////////////////////////// +// State "Active.Announce.Main.Find" +/////////////////////////////////////////////////////////////////////////////// +find::find(my_context _context) + : sc::state<find, main::orthogonal<1>, idle>(_context) { + VSOMEIP_TRACE << "sd::active.main.find"; +} + +/////////////////////////////////////////////////////////////////////////////// +// State "Active.Announce.Idle" +/////////////////////////////////////////////////////////////////////////////// +idle::idle(my_context _context) + : sc::state<idle, find>(_context) { + VSOMEIP_TRACE << "sd::active.main.find.idle"; + context<find>().run_ = 0; +} + +sc::result idle::react(const ev_request_service &_event) { + (void)_event; + return transit<send>(); } -sc::result announce::react(const ev_offer_change &_event) { +/////////////////////////////////////////////////////////////////////////////// +// State "Active.Announce.Main.Find.Send" +/////////////////////////////////////////////////////////////////////////////// +send::send(my_context _context) + : sc::state<send, find>(_context) { + std::shared_ptr < service_discovery_fsm > fsm = + outermost_context().fsm_.lock(); + if (fsm) { + VSOMEIP_TRACE << "sd::active.main.find.send"; + // Increment to the maximum run value (which is repetition_max-1) + // As new request might be added in the meantime, this will be + // used to calculate the maximum cycle time. + if (context<find>().run_ < fsm->get_repetition_max()) { + context<find>().run_++; + uint32_t its_timeout = (outermost_context().repetitions_base_delay_ + << context<find>().run_); + if (fsm->send(true, true)) + outermost_context().start_timer(its_timeout, true); + } + else { + post_event(ev_none()); + } + } else { + post_event(ev_none()); + } +} + +sc::result send::react(const ev_alt_timeout &_event) { + (void)_event; + return transit<send>(); +} + +sc::result send::react(const ev_none &_event) { (void)_event; - return transit<announce>(); + return transit<idle>(); } } // namespace _sd @@ -187,7 +284,6 @@ service_discovery_fsm::service_discovery_fsm( std::shared_ptr<service_discovery> _discovery) : discovery_(_discovery), fsm_( std::make_shared < _sd::fsm > (_discovery->get_io())) { - std::shared_ptr < service_discovery > discovery = discovery_.lock(); if (discovery) { std::shared_ptr < configuration > its_configuration = @@ -232,10 +328,10 @@ service_discovery_fsm::service_discovery_fsm( if (fsm_->cyclic_offer_delay_ <= 0) fsm_->cyclic_offer_delay_ = VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY; - VSOMEIP_INFO << "SD configuration [" << fsm_->initial_delay_ << ":" - << fsm_->repetitions_base_delay_ << ":" - << (int) fsm_->repetitions_max_ << ":" - << fsm_->cyclic_offer_delay_ << "]"; + VSOMEIP_INFO << "SD configuration [" << std::dec << fsm_->initial_delay_ << ":" + << std::dec << fsm_->repetitions_base_delay_ << ":" + << std::dec << (int) fsm_->repetitions_max_ << ":" + << std::dec << fsm_->cyclic_offer_delay_ << "]"; } else { VSOMEIP_ERROR << "SD initialization failed"; } @@ -249,10 +345,57 @@ void service_discovery_fsm::start() { void service_discovery_fsm::stop() { } -void service_discovery_fsm::send(bool _is_announcing) { +bool service_discovery_fsm::send(bool _is_announcing, bool _is_find) { std::shared_ptr < service_discovery > discovery = discovery_.lock(); - if (discovery) - discovery->send(_is_announcing); + if (discovery) { + return discovery->send(_is_announcing, _is_find); + } + return false; +} + +void service_discovery_fsm::send_unicast_offer_service( + const std::shared_ptr<const serviceinfo> &_info, + service_t _service, instance_t _instance, + major_version_t _major, + minor_version_t _minor) { + std::shared_ptr < service_discovery > discovery = discovery_.lock(); + if (discovery) { + discovery->send_unicast_offer_service(_info, _service, + _instance, _major, _minor ); + } +} + +void service_discovery_fsm::send_multicast_offer_service( + const std::shared_ptr<const serviceinfo> &_info, service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor) { + std::shared_ptr < service_discovery > discovery = discovery_.lock(); + if (discovery) { + discovery->send_multicast_offer_service(_info, _service, + _instance, _major, _minor ); + } +} + +std::chrono::milliseconds service_discovery_fsm::get_elapsed_offer_timer() { + //get remaining time to next offer since last offer + std::chrono::milliseconds remaining = + std::chrono::milliseconds(fsm_->expired_from_now(false)); + + if( std::chrono::milliseconds(0) > remaining) { + remaining = std::chrono::milliseconds(fsm_->cyclic_offer_delay_); + } + return std::chrono::milliseconds(fsm_->cyclic_offer_delay_) - remaining; +} + +bool service_discovery_fsm::check_is_multicast_offer() { + bool is_multicast(false); + std::chrono::milliseconds elapsed_ = get_elapsed_offer_timer(); + uint32_t half_cyclic_offer_delay_ = fsm_->cyclic_offer_delay_ / 2; + + if( elapsed_ >= std::chrono::milliseconds(half_cyclic_offer_delay_)) { + // Response must be a multicast offer (SIP_SD_90) + is_multicast = true; + } + return is_multicast; } } // namespace sd diff --git a/implementation/service_discovery/src/service_discovery_impl.cpp b/implementation/service_discovery/src/service_discovery_impl.cpp index b5493b8..10c6c96 100644 --- a/implementation/service_discovery/src/service_discovery_impl.cpp +++ b/implementation/service_discovery/src/service_discovery_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -40,7 +40,13 @@ service_discovery_impl::service_discovery_impl(service_discovery_host *_host) serializer_(std::make_shared<serializer>()), deserializer_(std::make_shared<deserializer>()), ttl_timer_(_host->get_io()), - smallest_ttl_(DEFAULT_TTL) { + smallest_ttl_(DEFAULT_TTL), + subscription_expiration_timer_(_host->get_io()) { + std::chrono::seconds smallest_ttl(DEFAULT_TTL); + smallest_ttl_ = std::chrono::duration_cast<std::chrono::milliseconds>(smallest_ttl); + + // TODO: cleanup start condition! + next_subscription_expiration_ = std::chrono::high_resolution_clock::now() + std::chrono::hours(24); } service_discovery_impl::~service_discovery_impl() { @@ -66,6 +72,8 @@ void service_discovery_impl::init() { 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); serializer_->create_data( reliable_ ? @@ -99,19 +107,26 @@ void service_discovery_impl::stop() { void service_discovery_impl::request_service(service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, ttl_t _ttl) { - std::lock_guard<std::mutex> its_lock(requested_mutex_); - auto find_service = requested_.find(_service); - if (find_service != requested_.end()) { - auto find_instance = find_service->second.find(_instance); - if (find_instance != find_service->second.end()) { - // TODO: check version and report errors + bool is_new_request(true); + { + std::lock_guard<std::mutex> its_lock(requested_mutex_); + auto find_service = requested_.find(_service); + if (find_service != requested_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + is_new_request = false; + // TODO: check version and report errors + } else { + find_service->second[_instance] = std::make_shared < request + > (_major, _minor, _ttl); + } } else { - find_service->second[_instance] = std::make_shared < request + requested_[_service][_instance] = std::make_shared < request > (_major, _minor, _ttl); } - } else { - requested_[_service][_instance] = std::make_shared < request - > (_major, _minor, _ttl); + } + if (is_new_request) { + default_->process(ev_request_service()); } } @@ -123,11 +138,22 @@ void service_discovery_impl::release_service(service_t _service, } } +std::shared_ptr<request> +service_discovery_impl::find_request(service_t _service, instance_t _instance) { + auto find_service = requested_.find(_service); + if (find_service != requested_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + return find_instance->second; + } + } + return nullptr; +} + void service_discovery_impl::subscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, ttl_t _ttl, client_t _client, subscription_type_e _subscription_type) { std::lock_guard<std::mutex> its_lock(subscribed_mutex_); - auto found_service = subscribed_.find(_service); if (found_service != subscribed_.end()) { auto found_instance = found_service->second.find(_instance); @@ -138,6 +164,8 @@ void service_discovery_impl::subscribe(service_t _service, instance_t _instance, if (found_client != found_eventgroup->second.end()) { if (found_client->second->get_major() == _major) { found_client->second->set_ttl(_ttl); + found_client->second->set_expiration(std::chrono::high_resolution_clock::now() + + std::chrono::seconds(_ttl)); } else { VSOMEIP_ERROR << "Subscriptions to different versions of the same " @@ -157,25 +185,57 @@ void service_discovery_impl::subscribe(service_t _service, instance_t _instance, get_subscription_endpoints(_subscription_type, its_unreliable, its_reliable, &its_address, &has_address, _service, _instance, _client); + const uint8_t max_parallel_subscriptions = 16; // 4Bit Counter field + uint8_t subscribe_count = static_cast<uint8_t>(subscribed_[_service][_instance][_eventgroup].size()); + if (subscribe_count >= max_parallel_subscriptions) { + VSOMEIP_WARNING << "Too many parallel subscriptions (max.16) on same event group: " + << std::hex << _eventgroup << std::dec; + return; + } + // New subscription std::shared_ptr < subscription > its_subscription = std::make_shared - < subscription > (_major, _ttl, its_reliable, its_unreliable, _subscription_type); + < subscription > (_major, _ttl, its_reliable, its_unreliable, + _subscription_type, subscribe_count, + std::chrono::high_resolution_clock::time_point() + std::chrono::seconds(_ttl)); subscribed_[_service][_instance][_eventgroup][_client] = its_subscription; - if (has_address) { std::shared_ptr<runtime> its_runtime = runtime_.lock(); if (!its_runtime) return; + if (_client != VSOMEIP_ROUTING_CLIENT) { + if (its_subscription->get_endpoint(true) && + !host_->has_identified(_client, _service, _instance, true)) { + return; + } + if (its_subscription->get_endpoint(false) && + !host_->has_identified(_client, _service, _instance, false)) { + return; + } + } + std::shared_ptr<message_impl> its_message = its_runtime->create_message(); - - // TODO: consume major & ttl - insert_subscription(its_message, _service, _instance, _eventgroup, - its_subscription); - serialize_and_send(its_message, its_address); - - its_subscription->set_acknowledged(false); + if (its_subscription->get_endpoint(true) + && its_subscription->get_endpoint(true)->is_connected()) { + insert_subscription(its_message, + _service, _instance, + _eventgroup, + its_subscription, true, true); + } else { + // don't insert reliable endpoint option if the + // TCP client endpoint is not yet connected + insert_subscription(its_message, + _service, _instance, + _eventgroup, + its_subscription, false, true); + its_subscription->set_tcp_connection_established(false); + } + if(0 < its_message->get_entries().size()) { + serialize_and_send(its_message, its_address); + its_subscription->set_acknowledged(false); + } } } @@ -246,7 +306,7 @@ void service_discovery_impl::unsubscribe(service_t _service, instance_t _instance, eventgroup_t _eventgroup, client_t _client) { std::lock_guard<std::mutex> its_lock(subscribed_mutex_); - + std::shared_ptr < subscription > its_subscription; auto found_service = subscribed_.find(_service); if (found_service != subscribed_.end()) { auto found_instance = found_service->second.find(_instance); @@ -255,42 +315,33 @@ void service_discovery_impl::unsubscribe(service_t _service, if (found_eventgroup != found_instance->second.end()) { auto found_client = found_eventgroup->second.find(_client); if (found_client != found_eventgroup->second.end()) { - found_client->second->set_ttl(0); + its_subscription = found_client->second; + its_subscription->set_ttl(0); + std::shared_ptr < runtime > its_runtime = runtime_.lock(); + if (its_runtime) { + boost::asio::ip::address its_address; + auto endpoint = its_subscription->get_endpoint(false); + if (endpoint) { + endpoint->get_remote_address(its_address); + } else { + endpoint = its_subscription->get_endpoint(true); + if (endpoint) { + endpoint->get_remote_address(its_address); + } else { + return; + } + } + std::shared_ptr < message_impl > its_message = its_runtime->create_message(); + insert_subscription(its_message, _service, _instance, _eventgroup, + its_subscription, true, true); + serialize_and_send(its_message, its_address); + + found_eventgroup->second.erase(_client); + } } } } } - - boost::asio::ip::address its_address; - - std::shared_ptr < runtime > its_runtime = runtime_.lock(); - if (!its_runtime) - return; - - std::shared_ptr < subscription > its_subscription = - subscribed_[_service][_instance][_eventgroup][_client]; - - auto endpoint = its_subscription->get_endpoint(false); - if (endpoint) { - endpoint->get_remote_address(its_address); - } else { - endpoint = its_subscription->get_endpoint(true); - if (endpoint) { - endpoint->get_remote_address(its_address); - } - } - - std::shared_ptr < message_impl > its_message - = its_runtime->create_message(); - - insert_subscription(its_message, _service, _instance, _eventgroup, - its_subscription); - - std::pair<session_t, bool> its_session = get_session(its_address); - its_message->set_session(its_session.first); - its_message->set_reboot_flag(its_session.second); - - serialize_and_send(its_message, its_address); } void service_discovery_impl::unsubscribe_all(service_t _service, instance_t _instance) { @@ -313,9 +364,9 @@ void service_discovery_impl::unsubscribe_all(service_t _service, instance_t _ins std::pair<session_t, bool> service_discovery_impl::get_session( const boost::asio::ip::address &_address) { std::pair<session_t, bool> its_session; - auto found_session = sessions_.find(_address); - if (found_session == sessions_.end()) { - its_session = sessions_[_address] = { 1, true }; + auto found_session = sessions_sent_.find(_address); + if (found_session == sessions_sent_.end()) { + its_session = sessions_sent_[_address] = { 1, true }; } else { its_session = found_session->second; } @@ -324,174 +375,363 @@ std::pair<session_t, bool> service_discovery_impl::get_session( void service_discovery_impl::increment_session( const boost::asio::ip::address &_address) { - auto found_session = sessions_.find(_address); - if (found_session != sessions_.end()) { + auto found_session = sessions_sent_.find(_address); + if (found_session != sessions_sent_.end()) { found_session->second.first++; - if (found_session->second.first == 0) { // Wrap - found_session->second = { 1, false }; + if (found_session->second.first == 0) { // Wrap --> change the reboot flag! + found_session->second = { 1, !found_session->second.second }; } } } bool service_discovery_impl::is_reboot( - const boost::asio::ip::address &_address, + const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_destination, bool _reboot_flag, session_t _session) { - bool result(false); -#ifdef VSOMEIP_TODO - // Reboot detection: Either the flag has changed from false to true, - // or the session identifier overrun while the flag is true - if (reboots_.find(_address) == reboots_.end()) { - if (_reboot_flag) { - reboots_.insert(_address); - result = true; - } + + auto its_last_session = sessions_received_.find(_sender); + bool is_multicast = _destination.is_multicast(); + + session_t its_unicast_id = (is_multicast ? 0 : _session); + session_t its_multicast_id = (is_multicast ? _session : 0); + + if (its_last_session == sessions_received_.end()) { + sessions_received_[_sender] + = std::make_tuple(its_multicast_id, its_unicast_id, _reboot_flag); } else { - auto its_last_session = sessions_receiving_.find(_address); - if(its_last_session != sessions_receiving_.end()) { - if (_reboot_flag && its_last_session->second >= _session) { + // Reboot detection: Either the flag has changed from false to true, + // or the session identifier overrun while the flag is true + if (its_last_session != sessions_received_.end()) { + if (!std::get<2>(its_last_session->second) && _reboot_flag) { result = true; + } else { + session_t its_last_id = (is_multicast ? + std::get<0>(its_last_session->second) : + std::get<1>(its_last_session->second)); + + if (std::get<2>(its_last_session->second) && _reboot_flag && + its_last_id >= _session) { + result = true; + } } } + + if (result == false) { + // no reboot -> update session + if (is_multicast) { + std::get<0>(its_last_session->second) = its_multicast_id; + } else { + std::get<1>(its_last_session->second) = its_unicast_id; + } + } else { + // reboot -> reset the session + sessions_received_.erase(_sender); + } } - sessions_receiving_[_address] = _session; -#else - (void)_address; - (void)_reboot_flag; - (void)_session; -#endif return result; } +template<class Option, typename AddressType> +std::shared_ptr<option_impl> service_discovery_impl::find_existing_option( + std::shared_ptr<message_impl> &_message, + AddressType _address, + uint16_t _port, layer_four_protocol_e _protocol, + option_type_e _option_type) { + if (_message->get_options().size() > 0) { + std::uint16_t option_length(0x0); + if(_option_type == option_type_e::IP4_ENDPOINT || + _option_type == option_type_e::IP4_MULTICAST) { + option_length = 0x9; + } else if(_option_type == option_type_e::IP6_ENDPOINT || + _option_type == option_type_e::IP6_MULTICAST) { + option_length = 0x15; + } else { // unsupported option type + return nullptr; + } + + bool is_multicast(false); + if(_option_type == option_type_e::IP4_MULTICAST || + _option_type == option_type_e::IP6_MULTICAST) { + is_multicast = true; + } + + std::vector<std::shared_ptr<option_impl>> its_options = + _message->get_options(); + for (const std::shared_ptr<option_impl>& opt : its_options) { + if (opt->get_length() == option_length && + opt->get_type() == _option_type && + std::static_pointer_cast<ip_option_impl>(opt)->get_layer_four_protocol() == _protocol && + std::static_pointer_cast<ip_option_impl>(opt)->get_port() == _port && + std::static_pointer_cast<ip_option_impl>(opt)->is_multicast() == is_multicast && + std::static_pointer_cast<Option>(opt)->get_address() == _address) { + return opt; + } + } + } + return nullptr; +} +template<class Option, typename AddressType> +bool service_discovery_impl::check_message_for_ip_option_and_assign_existing( + std::shared_ptr<message_impl> &_message, + std::shared_ptr<entry_impl> _entry, AddressType _address, + uint16_t _port, layer_four_protocol_e _protocol, + option_type_e _option_type) { + + std::shared_ptr<option_impl> its_option + = find_existing_option<Option, AddressType>(_message, _address, _port, _protocol, _option_type); + if (its_option) { + _entry->assign_option(its_option); + return true; + } + return false; +} + +template<class Option, typename AddressType> +void service_discovery_impl::assign_ip_option_to_entry( + std::shared_ptr<Option> _option, AddressType _address, + uint16_t _port, layer_four_protocol_e _protocol, + std::shared_ptr<entry_impl> _entry) { + if (_option) { + _option->set_address(_address); + _option->set_port(_port); + _option->set_layer_four_protocol(_protocol); + _entry->assign_option(_option); + } +} + void service_discovery_impl::insert_option( std::shared_ptr<message_impl> &_message, std::shared_ptr<entry_impl> _entry, const boost::asio::ip::address &_address, uint16_t _port, bool _is_reliable) { + layer_four_protocol_e its_protocol = + _is_reliable ? layer_four_protocol_e::TCP : + layer_four_protocol_e::UDP; + bool entry_assigned(false); + if (unicast_ == _address) { if (unicast_.is_v4()) { ipv4_address_t its_address = unicast_.to_v4().to_bytes(); - std::shared_ptr < ipv4_option_impl > its_option = - _message->create_ipv4_option(false); - if (its_option) { - its_option->set_address(its_address); - its_option->set_port(_port); - its_option->set_layer_four_protocol( - _is_reliable ? layer_four_protocol_e::TCP : - layer_four_protocol_e::UDP); - _entry->assign_option(its_option, 1); + entry_assigned = check_message_for_ip_option_and_assign_existing< + ipv4_option_impl, ipv4_address_t>(_message, _entry, + its_address, _port, its_protocol, + option_type_e::IP4_ENDPOINT); + if(!entry_assigned) { + std::shared_ptr < ipv4_option_impl > its_option = + _message->create_ipv4_option(false); + assign_ip_option_to_entry<ipv4_option_impl, ipv4_address_t>( + its_option, its_address, _port, its_protocol, _entry); } } else { ipv6_address_t its_address = unicast_.to_v6().to_bytes(); - std::shared_ptr < ipv6_option_impl > its_option = - _message->create_ipv6_option(false); - if (its_option) { - its_option->set_address(its_address); - its_option->set_port(_port); - its_option->set_layer_four_protocol( - _is_reliable ? layer_four_protocol_e::TCP : - layer_four_protocol_e::UDP); - _entry->assign_option(its_option, 1); + entry_assigned = check_message_for_ip_option_and_assign_existing< + ipv6_option_impl, ipv6_address_t>(_message, _entry, + its_address, _port, its_protocol, + option_type_e::IP6_ENDPOINT); + if(!entry_assigned) { + std::shared_ptr < ipv6_option_impl > its_option = + _message->create_ipv6_option(false); + assign_ip_option_to_entry<ipv6_option_impl, ipv6_address_t>( + its_option, its_address, _port, its_protocol, _entry); } } } else { if (_address.is_v4()) { ipv4_address_t its_address = _address.to_v4().to_bytes(); - std::shared_ptr < ipv4_option_impl > its_option = - _message->create_ipv4_option(true); - if (its_option) { - its_option->set_address(its_address); - its_option->set_port(_port); - its_option->set_layer_four_protocol( - _is_reliable ? layer_four_protocol_e::TCP : - layer_four_protocol_e::UDP); - _entry->assign_option(its_option, 1); + entry_assigned = check_message_for_ip_option_and_assign_existing< + ipv4_option_impl, ipv4_address_t>(_message, _entry, + its_address, _port, its_protocol, + option_type_e::IP4_MULTICAST); + if(!entry_assigned) { + std::shared_ptr < ipv4_option_impl > its_option = + _message->create_ipv4_option(true); + assign_ip_option_to_entry<ipv4_option_impl, ipv4_address_t>( + its_option, its_address, _port, its_protocol, _entry); } } else { ipv6_address_t its_address = _address.to_v6().to_bytes(); - std::shared_ptr < ipv6_option_impl > its_option = - _message->create_ipv6_option(true); - if (its_option) { - its_option->set_address(its_address); - its_option->set_port(_port); - its_option->set_layer_four_protocol( - _is_reliable ? layer_four_protocol_e::TCP : - layer_four_protocol_e::UDP); - _entry->assign_option(its_option, 1); + entry_assigned = check_message_for_ip_option_and_assign_existing< + ipv6_option_impl, ipv6_address_t>(_message, _entry, + its_address, _port, its_protocol, + option_type_e::IP6_MULTICAST); + if(!entry_assigned) { + std::shared_ptr < ipv6_option_impl > its_option = + _message->create_ipv6_option(true); + assign_ip_option_to_entry<ipv6_option_impl, ipv6_address_t>( + its_option, its_address, _port, its_protocol, _entry); } } } } void service_discovery_impl::insert_find_entries( - std::shared_ptr<message_impl> &_message, requests_t &_requests) { + std::shared_ptr<message_impl> &_message, requests_t &_requests, + uint32_t _start, uint32_t &_size, bool &_done) { std::lock_guard<std::mutex> its_lock(requested_mutex_); + uint32_t its_size(0); + uint32_t i = 0; + + _done = true; for (auto its_service : _requests) { for (auto its_instance : its_service.second) { auto its_request = its_instance.second; - std::shared_ptr < serviceentry_impl > its_entry = - _message->create_service_entry(); - if (its_entry) { - its_entry->set_type(entry_type_e::FIND_SERVICE); - its_entry->set_service(its_service.first); - its_entry->set_instance(its_instance.first); - its_entry->set_major_version(its_request->get_major()); - its_entry->set_minor_version(its_request->get_minor()); - its_entry->set_ttl(its_request->get_ttl()); - } else { - VSOMEIP_ERROR << "Failed to create service entry!"; + uint8_t its_sent_counter = its_request->get_sent_counter(); + if (its_sent_counter != default_->get_repetition_max()) { + if (i >= _start) { + if (its_size + VSOMEIP_SOMEIP_SD_ENTRY_SIZE <= max_message_size_) { + std::shared_ptr < serviceentry_impl > its_entry = + _message->create_service_entry(); + if (its_entry) { + its_entry->set_type(entry_type_e::FIND_SERVICE); + its_entry->set_service(its_service.first); + its_entry->set_instance(its_instance.first); + its_entry->set_major_version(its_request->get_major()); + its_entry->set_minor_version(its_request->get_minor()); + its_entry->set_ttl(its_request->get_ttl()); + its_size += VSOMEIP_SOMEIP_SD_ENTRY_SIZE; + + its_sent_counter++; + its_request->set_sent_counter(its_sent_counter); + } else { + VSOMEIP_ERROR << "Failed to create service entry!"; + } + } else { + _done = false; + _size = its_size; + return; + } + } } + i++; } } + _size = its_size; } void service_discovery_impl::insert_offer_entries( - std::shared_ptr<message_impl> &_message, services_t &_services) { + std::shared_ptr<message_impl> &_message, services_t &_services, + uint32_t &_start, uint32_t _size, bool &_done) { + uint32_t i = 0; + uint32_t its_size(_size); for (auto its_service : _services) { for (auto its_instance : its_service.second) { - insert_offer_service(_message, its_service.first, - its_instance.first, its_instance.second); + // Only insert services with configured endpoint(s) + if (its_instance.second->get_endpoint(false) + || its_instance.second->get_endpoint(true)) { + if (i >= _start) { + if (!insert_offer_service(_message, its_service.first, + its_instance.first, its_instance.second, its_size)) { + _start = i; + _done = false; + return; + } + } + } + i++; } } + _start = i; + _done = true; } void service_discovery_impl::insert_subscription( std::shared_ptr<message_impl> &_message, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - std::shared_ptr<subscription> &_subscription) { + std::shared_ptr<subscription> &_subscription, + bool _insert_reliable, bool _insert_unreliable) { + if((_insert_reliable && !_insert_unreliable && !_subscription->get_endpoint(true)) || + (_insert_unreliable && !_insert_reliable && !_subscription->get_endpoint(false))) { + // don't create an eventgroup entry if there isn't an endpoint option + // to insert + return; + } std::shared_ptr < eventgroupentry_impl > its_entry = _message->create_eventgroup_entry(); its_entry->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP); its_entry->set_service(_service); its_entry->set_instance(_instance); its_entry->set_eventgroup(_eventgroup); + its_entry->set_counter(_subscription->get_counter()); its_entry->set_major_version(_subscription->get_major()); its_entry->set_ttl(_subscription->get_ttl()); - std::shared_ptr < endpoint > its_endpoint = _subscription->get_endpoint( - true); + std::shared_ptr < endpoint > its_endpoint; + if (_insert_reliable) { + its_endpoint = _subscription->get_endpoint(true); + if (its_endpoint) { + insert_option(_message, its_entry, unicast_, + its_endpoint->get_local_port(), true); + } + } + if (_insert_unreliable) { + its_endpoint = _subscription->get_endpoint(false); + if (its_endpoint) { + insert_option(_message, its_entry, unicast_, + its_endpoint->get_local_port(), false); + } + } +} + +void service_discovery_impl::insert_nack_subscription_on_resubscribe(std::shared_ptr<message_impl> &_message, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + std::shared_ptr<subscription> &_subscription) { + + // SIP_SD_844: + // This method is used for not acknowledged subscriptions on renew subscription + // Two entries: Stop subscribe & subscribe within one SD-Message + // One option: Both entries reference it + + std::shared_ptr < eventgroupentry_impl > its_stop_entry = + _message->create_eventgroup_entry(); + its_stop_entry->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP); + its_stop_entry->set_service(_service); + its_stop_entry->set_instance(_instance); + its_stop_entry->set_eventgroup(_eventgroup); + its_stop_entry->set_counter(_subscription->get_counter()); + its_stop_entry->set_major_version(_subscription->get_major()); + its_stop_entry->set_ttl(0); + + std::shared_ptr < eventgroupentry_impl > its_entry = + _message->create_eventgroup_entry(); + its_entry->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP); + its_entry->set_service(_service); + its_entry->set_instance(_instance); + its_entry->set_eventgroup(_eventgroup); + its_entry->set_counter(_subscription->get_counter()); + its_entry->set_major_version(_subscription->get_major()); + its_entry->set_ttl(_subscription->get_ttl()); + + std::shared_ptr < endpoint > its_endpoint; + its_endpoint = _subscription->get_endpoint(true); if (its_endpoint) { - insert_option(_message, its_entry, unicast_, its_endpoint->get_local_port(), - true); + insert_option(_message, its_stop_entry, unicast_, + its_endpoint->get_local_port(), true); + insert_option(_message, its_entry, unicast_, + its_endpoint->get_local_port(), true); } its_endpoint = _subscription->get_endpoint(false); if (its_endpoint) { - insert_option(_message, its_entry, unicast_, its_endpoint->get_local_port(), - false); + insert_option(_message, its_stop_entry, unicast_, + its_endpoint->get_local_port(), false); + insert_option(_message, its_entry, unicast_, + its_endpoint->get_local_port(), false); } } void service_discovery_impl::insert_subscription_ack( std::shared_ptr<message_impl> &_message, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - std::shared_ptr<eventgroupinfo> &_info, ttl_t _ttl) { + std::shared_ptr<eventgroupinfo> &_info, ttl_t _ttl, uint8_t _counter, major_version_t _major, uint16_t _reserved) { std::shared_ptr < eventgroupentry_impl > its_entry = _message->create_eventgroup_entry(); its_entry->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP_ACK); its_entry->set_service(_service); its_entry->set_instance(_instance); its_entry->set_eventgroup(_eventgroup); - its_entry->set_major_version(_info->get_major()); + its_entry->set_major_version(_major); + its_entry->set_reserved(_reserved); + its_entry->set_counter(_counter); // SWS_SD_00315 its_entry->set_ttl(_ttl); @@ -505,7 +745,7 @@ void service_discovery_impl::insert_subscription_ack( void service_discovery_impl::insert_subscription_nack( std::shared_ptr<message_impl> &_message, service_t _service, instance_t _instance, eventgroup_t _eventgroup, - std::shared_ptr<eventgroupinfo> &_info) { + uint8_t _counter, major_version_t _major, uint16_t _reserved) { std::shared_ptr < eventgroupentry_impl > its_entry = _message->create_eventgroup_entry(); // SWS_SD_00316 and SWS_SD_00385 @@ -513,51 +753,75 @@ void service_discovery_impl::insert_subscription_nack( its_entry->set_service(_service); its_entry->set_instance(_instance); its_entry->set_eventgroup(_eventgroup); - its_entry->set_major_version(_info->get_major()); + its_entry->set_major_version(_major); + its_entry->set_reserved(_reserved); + its_entry->set_counter(_counter); // SWS_SD_00432 its_entry->set_ttl(0x0); - - boost::asio::ip::address its_address; - uint16_t its_port; - if (_info->get_multicast(its_address, its_port)) { - insert_option(_message, its_entry, its_address, its_port, false); - } } -void service_discovery_impl::send(bool _is_announcing) { - +bool service_discovery_impl::send(bool _is_announcing, bool _is_find) { std::shared_ptr < runtime > its_runtime = runtime_.lock(); - if (!its_runtime) - return; - - std::shared_ptr < message_impl > its_message = - its_runtime->create_message(); - - // TODO: optimize building of SD message (common options, utilize the two runs) - - // If we are not in main phase, include "FindOffer"-entries - if (!_is_announcing) { - insert_find_entries(its_message, requested_); - } + if (its_runtime) { + std::vector< std::shared_ptr< message_impl > > its_messages; + std::shared_ptr < message_impl > its_message; + + uint32_t its_remaining(max_message_size_); + + if (_is_find || !_is_announcing) { + uint32_t its_start(0); + uint32_t its_size(0); + bool is_done(false); + while (!is_done) { + its_message = its_runtime->create_message(); + its_messages.push_back(its_message); + + insert_find_entries(its_message, requested_, its_start, its_size, is_done); + its_start += its_size / VSOMEIP_SOMEIP_SD_ENTRY_SIZE; + }; + its_remaining -= its_size; + } else { + its_message = its_runtime->create_message(); + its_messages.push_back(its_message); + } - // Always include the "OfferService"-entries for the service group - services_t its_offers = host_->get_offered_services(); - insert_offer_entries(its_message, its_offers); + if (!_is_find) { + services_t its_offers = host_->get_offered_services(); + + uint32_t its_start(0); + bool is_done(false); + while (!is_done) { + insert_offer_entries(its_message, its_offers, its_start, its_remaining, is_done); + if (!is_done) { + its_remaining = max_message_size_; + its_message = its_runtime->create_message(); + its_messages.push_back(its_message); + } + } + } - // Serialize and send - if (its_message->get_entries().size() > 0) { - std::pair<session_t, bool> its_session = get_session(unicast_); - its_message->set_session(its_session.first); - its_message->set_reboot_flag(its_session.second); - if (host_->send(VSOMEIP_SD_CLIENT, its_message, true)) { - increment_session (unicast_); + // Serialize and send + bool has_sent(false); + for (auto m : its_messages) { + if (m->get_entries().size() > 0) { + std::pair<session_t, bool> its_session = get_session(unicast_); + m->set_session(its_session.first); + m->set_reboot_flag(its_session.second); + if (host_->send(VSOMEIP_SD_CLIENT, m, true)) { + increment_session(unicast_); + } + has_sent = true; + } } + return has_sent; } + return false; } // Interface endpoint_host void service_discovery_impl::on_message(const byte_t *_data, length_t _length, - const boost::asio::ip::address &_sender) { + const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_destination) { #if 0 std::stringstream msg; msg << "sdi::on_message: "; @@ -574,30 +838,51 @@ void service_discovery_impl::on_message(const byte_t *_data, length_t _length, return; } // Expire all subscriptions / services in case of reboot - if (is_reboot(_sender, + if (is_reboot(_sender, _destination, its_message->get_reboot_flag(), its_message->get_session())) { host_->expire_subscriptions(_sender); host_->expire_services(_sender); } - ttl_t expired = stop_ttl_timer(); + std::chrono::milliseconds expired = stop_ttl_timer(); smallest_ttl_ = host_->update_routing_info(expired); std::vector < std::shared_ptr<option_impl> > its_options = its_message->get_options(); + + std::shared_ptr<runtime> its_runtime = runtime_.lock(); + if (!its_runtime) { + return; + } + + std::shared_ptr < message_impl > its_message_response + = its_runtime->create_message(); + std::vector <accepted_subscriber_t> accepted_subscribers; + for (auto its_entry : its_message->get_entries()) { if (its_entry->is_service_entry()) { std::shared_ptr < serviceentry_impl > its_service_entry = std::dynamic_pointer_cast < serviceentry_impl > (its_entry); - process_serviceentry(its_service_entry, its_options); + bool its_unicast_flag = its_message->get_unicast_flag(); + process_serviceentry(its_service_entry, its_options, its_unicast_flag ); } else { std::shared_ptr < eventgroupentry_impl > its_eventgroup_entry = std::dynamic_pointer_cast < eventgroupentry_impl > (its_entry); - process_eventgroupentry(its_eventgroup_entry, its_options); + process_eventgroupentry( its_eventgroup_entry, its_options, its_message_response, accepted_subscribers); } } + + //send ACK / NACK if present + if( 0 < its_message_response->get_entries().size() && its_message_response ) { + serialize_and_send(its_message_response, _sender); + } + + for( const auto &a : accepted_subscribers) { + host_->on_subscribe(a.service_id, a.instance_id, a.eventgroup_, a.subscriber, a.target, a.its_expiration); + } + accepted_subscribers.clear(); start_ttl_timer(); } else { VSOMEIP_ERROR << "service_discovery_impl::on_message: deserialization error."; @@ -612,7 +897,8 @@ void service_discovery_impl::on_offer_change() { // Entry processing void service_discovery_impl::process_serviceentry( std::shared_ptr<serviceentry_impl> &_entry, - const std::vector<std::shared_ptr<option_impl> > &_options) { + const std::vector<std::shared_ptr<option_impl> > &_options, + bool _unicast_flag) { // Read service info from entry entry_type_e its_type = _entry->get_type(); @@ -629,56 +915,60 @@ void service_discovery_impl::process_serviceentry( boost::asio::ip::address its_unreliable_address; uint16_t its_unreliable_port(ILLEGAL_PORT); - for (auto i : { 1, 2 }) { for (auto its_index : _entry->get_options(uint8_t(i))) { - std::shared_ptr < option_impl > its_option = _options[its_index]; + if( _options.size() > its_index ) { + std::shared_ptr < option_impl > its_option = _options[its_index]; - switch (its_option->get_type()) { - case option_type_e::IP4_ENDPOINT: { - std::shared_ptr < ipv4_option_impl > its_ipv4_option = - std::dynamic_pointer_cast < ipv4_option_impl - > (its_option); + switch (its_option->get_type()) { + case option_type_e::IP4_ENDPOINT: { + std::shared_ptr < ipv4_option_impl > its_ipv4_option = + std::dynamic_pointer_cast < ipv4_option_impl + > (its_option); - boost::asio::ip::address_v4 its_ipv4_address( - its_ipv4_option->get_address()); + boost::asio::ip::address_v4 its_ipv4_address( + its_ipv4_option->get_address()); - if (its_ipv4_option->get_layer_four_protocol() - == layer_four_protocol_e::UDP) { - its_unreliable_address = its_ipv4_address; - its_unreliable_port = its_ipv4_option->get_port(); - } else { - its_reliable_address = its_ipv4_address; - its_reliable_port = its_ipv4_option->get_port(); + if (its_ipv4_option->get_layer_four_protocol() + == layer_four_protocol_e::UDP) { + + + its_unreliable_address = its_ipv4_address; + its_unreliable_port = its_ipv4_option->get_port(); + } else { + its_reliable_address = its_ipv4_address; + its_reliable_port = its_ipv4_option->get_port(); + } + break; } - break; - } - case option_type_e::IP6_ENDPOINT: { - std::shared_ptr < ipv6_option_impl > its_ipv6_option = - std::dynamic_pointer_cast < ipv6_option_impl - > (its_option); + case option_type_e::IP6_ENDPOINT: { + std::shared_ptr < ipv6_option_impl > its_ipv6_option = + std::dynamic_pointer_cast < ipv6_option_impl + > (its_option); - boost::asio::ip::address_v6 its_ipv6_address( - its_ipv6_option->get_address()); + boost::asio::ip::address_v6 its_ipv6_address( + its_ipv6_option->get_address()); - if (its_ipv6_option->get_layer_four_protocol() - == layer_four_protocol_e::UDP) { - its_unreliable_address = its_ipv6_address; - its_unreliable_port = its_ipv6_option->get_port(); - } else { - its_reliable_address = its_ipv6_address; - its_reliable_port = its_ipv6_option->get_port(); + if (its_ipv6_option->get_layer_four_protocol() + == layer_four_protocol_e::UDP) { + its_unreliable_address = its_ipv6_address; + its_unreliable_port = its_ipv6_option->get_port(); + } else { + its_reliable_address = its_ipv6_address; + its_reliable_port = its_ipv6_option->get_port(); + } + break; + } + case option_type_e::IP4_MULTICAST: + case option_type_e::IP6_MULTICAST: + break; + case option_type_e::CONFIGURATION: + break; + case option_type_e::UNKNOWN: + default: + VSOMEIP_ERROR << "Unsupported service option"; + break; } - break; - } - case option_type_e::IP4_MULTICAST: - case option_type_e::IP6_MULTICAST: - VSOMEIP_ERROR << "Invalid service option (Multicast)"; - break; - case option_type_e::UNKNOWN: - default: - VSOMEIP_ERROR << "Unsupported service option"; - break; } } } @@ -687,7 +977,7 @@ void service_discovery_impl::process_serviceentry( switch(its_type) { case entry_type_e::FIND_SERVICE: process_findservice_serviceentry(its_service, its_instance, - its_major, its_minor); + its_major, its_minor, _unicast_flag); break; case entry_type_e::OFFER_SERVICE: process_offerservice_serviceentry(its_service, its_instance, @@ -701,6 +991,10 @@ void service_discovery_impl::process_serviceentry( } } else { + std::shared_ptr<request> its_request = find_request(its_service, its_instance); + if (its_request) + its_request->set_sent_counter(default_->get_repetition_max()); + unsubscribe_all(its_service, its_instance); host_->del_routing_info(its_service, its_instance, (its_reliable_port != ILLEGAL_PORT), @@ -719,6 +1013,10 @@ void service_discovery_impl::process_offerservice_serviceentry( if (!its_runtime) return; + std::shared_ptr<request> its_request = find_request(_service, _instance); + if (its_request) + its_request->set_sent_counter(default_->get_repetition_max()); + host_->add_routing_info(_service, _instance, _major, _minor, _ttl, _reliable_address, _reliable_port, @@ -732,31 +1030,54 @@ void service_discovery_impl::process_offerservice_serviceentry( if (0 < found_instance->second.size()) { std::shared_ptr<message_impl> its_message = its_runtime->create_message(); - for (auto its_eventgroup : found_instance->second) { for (auto its_client : its_eventgroup.second) { + if (its_client.first != VSOMEIP_ROUTING_CLIENT) { + if (its_client.second->get_endpoint(true) && + !host_->has_identified(its_client.first, _service, + _instance, true)) { + continue; + } + if (its_client.second->get_endpoint(false) && + !host_->has_identified(its_client.first, _service, + _instance, false)) { + continue; + } + } std::shared_ptr<subscription> its_subscription(its_client.second); + std::shared_ptr<endpoint> its_unreliable; + std::shared_ptr<endpoint> its_reliable; + bool has_address(false); + boost::asio::ip::address its_address; + get_subscription_endpoints( + its_client.second->get_subscription_type(), + its_unreliable, its_reliable, &its_address, + &has_address, _service, _instance, + its_client.first); + its_subscription->set_endpoint(its_reliable, true); + its_subscription->set_endpoint(its_unreliable, false); if (its_subscription->is_acknowledged()) { - std::shared_ptr<endpoint> its_unreliable; - std::shared_ptr<endpoint> its_reliable; - bool has_address(false); - boost::asio::ip::address its_address; - get_subscription_endpoints( - its_client.second->get_subscription_type(), - its_unreliable, its_reliable, &its_address, - &has_address, _service, _instance, - its_client.first); - its_subscription->set_endpoint(its_reliable, true); - its_subscription->set_endpoint(its_unreliable, - false); - - // TODO: consume major & ttl - insert_subscription(its_message, - _service, _instance, - its_eventgroup.first, - its_subscription); + if (its_subscription->get_endpoint(true) + && its_subscription->get_endpoint(true)->is_connected()) { + insert_subscription(its_message, + _service, _instance, + its_eventgroup.first, + its_subscription, true, true); + } else { + // don't insert reliable endpoint option if the + // TCP client endpoint is not yet connected + insert_subscription(its_message, + _service, _instance, + its_eventgroup.first, + its_subscription, false, true); + its_client.second->set_tcp_connection_established(false); + } its_subscription->set_acknowledged(false); + } else { + insert_nack_subscription_on_resubscribe(its_message, + _service, _instance, its_eventgroup.first, + its_subscription); } } } @@ -780,7 +1101,7 @@ void service_discovery_impl::process_offerservice_serviceentry( serializer_->serialize(its_message.get()); if (host_->send_to(its_target, serializer_->get_data(), - serializer_->get_size())) { + serializer_->get_size(), port_)) { increment_session(its_target->get_address()); } serializer_->reset(); @@ -793,7 +1114,7 @@ void service_discovery_impl::process_offerservice_serviceentry( void service_discovery_impl::process_findservice_serviceentry( service_t _service, instance_t _instance, major_version_t _major, - minor_version_t _minor) { + minor_version_t _minor, bool _unicast_flag) { services_t offered_services = host_->get_offered_services(); auto found_service = offered_services.find(_service); if (found_service != offered_services.end()) { @@ -801,14 +1122,18 @@ void service_discovery_impl::process_findservice_serviceentry( auto found_instance = found_service->second.find(_instance); if (found_instance != found_service->second.end()) { std::shared_ptr<serviceinfo> its_info = found_instance->second; - send_unicast_offer_service(its_info, _service, _instance, - _major, _minor); + + ev_find_service find_event(its_info, _service, + _instance, _major, _minor, _unicast_flag ); + default_->process(find_event); } } else { // send back all available instances for (const auto &found_instance : found_service->second) { - send_unicast_offer_service(found_instance.second, _service, - _instance, _major, _minor); + + ev_find_service find_event(found_instance.second, _service, + _instance, _major, _minor, _unicast_flag ); + default_->process(find_event); } } } @@ -818,76 +1143,224 @@ void service_discovery_impl::send_unicast_offer_service( const std::shared_ptr<const serviceinfo> &_info, service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) { if (_major == ANY_MAJOR || _major == _info->get_major()) { - if (_minor == 0xFFFFFFFF || _minor == _info->get_minor()) { + if (_minor == 0xFFFFFFFF || _minor <= _info->get_minor()) { std::shared_ptr<runtime> its_runtime = runtime_.lock(); if (!its_runtime) { return; } std::shared_ptr<message_impl> its_message = its_runtime->create_message(); - insert_offer_service(its_message, _service, _instance, _info); + + uint32_t its_size(max_message_size_); + insert_offer_service(its_message, _service, _instance, _info, its_size); serialize_and_send(its_message, get_current_remote_address()); } } } -void service_discovery_impl::insert_offer_service( +void service_discovery_impl::send_multicast_offer_service( + const std::shared_ptr<const serviceinfo> &_info, service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor) { + if (_major == ANY_MAJOR || _major == _info->get_major()) { + if (_minor == 0xFFFFFFFF || _minor <= _info->get_minor()) { + std::shared_ptr<runtime> its_runtime = runtime_.lock(); + if (!its_runtime) { + return; + } + std::shared_ptr<message_impl> its_message = + its_runtime->create_message(); + + uint32_t its_size(max_message_size_); + insert_offer_service(its_message, _service, _instance, _info, its_size); + + if (its_message->get_entries().size() > 0) { + std::pair<session_t, bool> its_session = get_session(unicast_); + its_message->set_session(its_session.first); + its_message->set_reboot_flag(its_session.second); + if (host_->send(VSOMEIP_SD_CLIENT, its_message, true)) { + increment_session(unicast_); + } + } + } + } +} + +void service_discovery_impl::on_reliable_endpoint_connected( + service_t _service, instance_t _instance, + const std::shared_ptr<const vsomeip::endpoint> &_endpoint) { + std::shared_ptr<runtime> its_runtime = runtime_.lock(); + if (!its_runtime) { + return; + } + + // send out subscriptions for services where the tcp connection + // wasn't established at time of subscription + + std::lock_guard<std::mutex> its_lock(subscribed_mutex_); + + auto found_service = subscribed_.find(_service); + if (found_service != subscribed_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + if(0 < found_instance->second.size()) { + std::shared_ptr<message_impl> its_message(its_runtime->create_message()); + bool has_address(false); + boost::asio::ip::address its_address; + + for(const auto &its_eventgroup : found_instance->second) { + for(const auto &its_client : its_eventgroup.second) { + if (its_client.first != VSOMEIP_ROUTING_CLIENT) { + if (its_client.second->get_endpoint(true) && + !host_->has_identified(its_client.first, _service, + _instance, true)) { + continue; + } + } + std::shared_ptr<subscription> its_subscription(its_client.second); + if(its_subscription && !its_subscription->is_tcp_connection_established()) { + const std::shared_ptr<const endpoint> its_endpoint( + its_subscription->get_endpoint(true)); + if(its_endpoint && its_endpoint->is_connected()) { + if(its_endpoint.get() == _endpoint.get()) { + // mark as established + its_subscription->set_tcp_connection_established(true); + + std::shared_ptr<endpoint> its_unreliable; + std::shared_ptr<endpoint> its_reliable; + get_subscription_endpoints( + its_subscription->get_subscription_type(), + its_unreliable, its_reliable, &its_address, + &has_address, _service, _instance, + its_client.first); + its_subscription->set_endpoint(its_reliable, true); + its_subscription->set_endpoint(its_unreliable, false); + // only insert reliable subscriptions as unreliable + // ones are immediately sent out + insert_subscription(its_message, _service, + _instance, its_eventgroup.first, + its_subscription, true, false); + its_subscription->set_acknowledged(false); + } + } + } + } + } + if (0 < its_message->get_entries().size() && has_address) { + serialize_and_send(its_message, its_address); + } + } + } + } +} + +bool service_discovery_impl::insert_offer_service( std::shared_ptr < message_impl > _message, service_t _service, - instance_t _instance, const std::shared_ptr<const serviceinfo> &_info) { - std::shared_ptr < serviceentry_impl > its_entry = - _message->create_service_entry(); - if (its_entry) { - its_entry->set_type(entry_type_e::OFFER_SERVICE); - its_entry->set_service(_service); - its_entry->set_instance(_instance); - its_entry->set_major_version(_info->get_major()); - its_entry->set_minor_version(_info->get_minor()); - - ttl_t its_ttl = _info->get_ttl(); - if (its_ttl > 0) - its_ttl = ttl_; - its_entry->set_ttl(its_ttl); - - std::shared_ptr < endpoint > its_endpoint = - _info->get_endpoint(true); - if (its_endpoint) { - insert_option(_message, its_entry, unicast_, - its_endpoint->get_local_port(), true); - if (0 == _info->get_ttl()) { - host_->del_routing_info(_service, - _instance, true, false); + instance_t _instance, const std::shared_ptr<const serviceinfo> &_info, + uint32_t &_size) { + + std::shared_ptr < endpoint > its_reliable = _info->get_endpoint(true); + std::shared_ptr < endpoint > its_unreliable = _info->get_endpoint(false); + + uint32_t its_size = VSOMEIP_SOMEIP_SD_ENTRY_SIZE; + if (its_reliable) { + uint32_t its_endpoint_size(0); + if (unicast_.is_v4()) { + if (!find_existing_option<ipv4_option_impl, ipv4_address_t>(_message, + unicast_.to_v4().to_bytes(), its_reliable->get_local_port(), + layer_four_protocol_e::TCP, option_type_e::IP4_ENDPOINT)) { + its_endpoint_size = VSOMEIP_SOMEIP_SD_IPV4_OPTION_SIZE; + } + } else { + if (!find_existing_option<ipv6_option_impl, ipv6_address_t>(_message, + unicast_.to_v6().to_bytes(), its_reliable->get_local_port(), + layer_four_protocol_e::TCP, option_type_e::IP6_ENDPOINT)) { + its_endpoint_size = VSOMEIP_SOMEIP_SD_IPV6_OPTION_SIZE; } } + its_size += its_endpoint_size; + } + if (its_unreliable) { + uint32_t its_endpoint_size(0); + if (unicast_.is_v4()) { + if (!find_existing_option<ipv4_option_impl, ipv4_address_t>(_message, + unicast_.to_v4().to_bytes(), its_unreliable->get_local_port(), + layer_four_protocol_e::UDP, option_type_e::IP4_ENDPOINT)) { + its_endpoint_size = VSOMEIP_SOMEIP_SD_IPV4_OPTION_SIZE; + } + } else { + if (!find_existing_option<ipv6_option_impl, ipv6_address_t>(_message, + unicast_.to_v6().to_bytes(), its_reliable->get_local_port(), + layer_four_protocol_e::UDP, option_type_e::IP6_ENDPOINT)) { + its_endpoint_size = VSOMEIP_SOMEIP_SD_IPV6_OPTION_SIZE; + } + } + its_size += its_endpoint_size; + } - its_endpoint = _info->get_endpoint(false); - if (its_endpoint) { - insert_option(_message, its_entry, unicast_, - its_endpoint->get_local_port(), false); - if (0 == _info->get_ttl()) { - host_->del_routing_info(_service, - _instance, false, true); + if (its_size <= _size) { + _size -= its_size; + + std::shared_ptr < serviceentry_impl > its_entry = + _message->create_service_entry(); + if (its_entry) { + its_entry->set_type(entry_type_e::OFFER_SERVICE); + its_entry->set_service(_service); + its_entry->set_instance(_instance); + its_entry->set_major_version(_info->get_major()); + its_entry->set_minor_version(_info->get_minor()); + + ttl_t its_ttl = _info->get_ttl(); + if (its_ttl > 0) + its_ttl = ttl_; + its_entry->set_ttl(its_ttl); + + if (its_reliable) { + insert_option(_message, its_entry, unicast_, + its_reliable->get_local_port(), true); + if (0 == _info->get_ttl()) { + host_->del_routing_info(_service, + _instance, true, false); + } + } + + if (its_unreliable) { + insert_option(_message, its_entry, unicast_, + its_unreliable->get_local_port(), false); + if (0 == _info->get_ttl()) { + host_->del_routing_info(_service, + _instance, false, true); + } } + // This would be a clean solution but does _not_ work with the ANDi tool + //unsubscribe_all(_service, _instance); + } else { + VSOMEIP_ERROR << "Failed to create service entry."; } - } else { - VSOMEIP_ERROR << "Failed to create service entry."; + return true; } + + return false; } void service_discovery_impl::process_eventgroupentry( std::shared_ptr<eventgroupentry_impl> &_entry, - const std::vector<std::shared_ptr<option_impl> > &_options) { + const std::vector<std::shared_ptr<option_impl> > &_options, + std::shared_ptr < message_impl > &its_message_response, + std::vector <accepted_subscriber_t> &accepted_subscribers) { service_t its_service = _entry->get_service(); instance_t its_instance = _entry->get_instance(); eventgroup_t its_eventgroup = _entry->get_eventgroup(); entry_type_e its_type = _entry->get_type(); major_version_t its_major = _entry->get_major_version(); ttl_t its_ttl = _entry->get_ttl(); + uint16_t its_reserved = _entry->get_reserved(); + uint8_t its_counter = _entry->get_counter(); if (_entry->get_owning_message()->get_return_code() != return_code) { VSOMEIP_ERROR << "Invalid return code in SD header"; - send_eventgroup_subscription_nack(its_service, its_instance, - its_eventgroup, its_major); + insert_subscription_nack(its_message_response, its_service, its_instance, + its_eventgroup, its_counter, its_major, its_reserved); return; } @@ -895,30 +1368,35 @@ void service_discovery_impl::process_eventgroupentry( if (_entry->get_num_options(1) == 0 && _entry->get_num_options(2) == 0) { VSOMEIP_ERROR << "Invalid number of options in SubscribeEventGroup entry"; - send_eventgroup_subscription_nack(its_service, its_instance, - its_eventgroup, its_major); + insert_subscription_nack(its_message_response, its_service, its_instance, + its_eventgroup, its_counter, its_major, its_reserved); return; } if(_entry->get_owning_message()->get_options_length() < 12) { VSOMEIP_ERROR << "Invalid options length in SD message"; - send_eventgroup_subscription_nack(its_service, its_instance, - its_eventgroup, its_major); + insert_subscription_nack(its_message_response, its_service, its_instance, + its_eventgroup, its_counter, its_major, its_reserved); return; } if (_options.size() - < (_entry->get_num_options(1) + _entry->get_num_options(2))) { + // cast is needed in order to get unsigned type since int will be promoted + // by the + operator on 16 bit or higher machines. + < static_cast<std::vector<std::shared_ptr<option_impl>>::size_type>( + (_entry->get_num_options(1)) + (_entry->get_num_options(2)))) { VSOMEIP_ERROR << "Fewer options in SD message than " - "referenced in EventGroup entry"; - send_eventgroup_subscription_nack(its_service, its_instance, - its_eventgroup, its_major); + "referenced in EventGroup entry or malformed option received"; + insert_subscription_nack(its_message_response, its_service, its_instance, + its_eventgroup, its_counter, its_major, its_reserved); return; } } - boost::asio::ip::address its_reliable_address; - uint16_t its_reliable_port(ILLEGAL_PORT); - boost::asio::ip::address its_unreliable_address; - uint16_t its_unreliable_port(ILLEGAL_PORT); + boost::asio::ip::address its_first_address; + uint16_t its_first_port(ILLEGAL_PORT); + bool is_first_reliable(false); + boost::asio::ip::address its_second_address; + uint16_t its_second_port(ILLEGAL_PORT); + bool is_second_reliable(false); for (auto i : { 1, 2 }) { for (auto its_index : _entry->get_options(uint8_t(i))) { @@ -926,12 +1404,15 @@ void service_discovery_impl::process_eventgroupentry( try { its_option = _options.at(its_index); } catch(const std::out_of_range& e) { +#ifdef WIN32 + e; // silence MSVC warining C4101 +#endif VSOMEIP_ERROR << "Fewer options in SD message than " "referenced in EventGroup entry for " "option run number: " << i; if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type) { - send_eventgroup_subscription_nack(its_service, its_instance, - its_eventgroup, its_major); + insert_subscription_nack(its_message_response, its_service, its_instance, + its_eventgroup, its_counter, its_major, its_reserved); } return; } @@ -945,18 +1426,40 @@ void service_discovery_impl::process_eventgroupentry( boost::asio::ip::address_v4 its_ipv4_address( its_ipv4_option->get_address()); if (!check_layer_four_protocol(its_ipv4_option)) { - send_eventgroup_subscription_nack(its_service, - its_instance, its_eventgroup, its_major); + insert_subscription_nack(its_message_response, its_service, its_instance, + its_eventgroup, its_counter, its_major, its_reserved); return; } - // TODO: add error handling (port already set) here - if (its_ipv4_option->get_layer_four_protocol() - == layer_four_protocol_e::UDP) { - its_unreliable_address = its_ipv4_address; - its_unreliable_port = its_ipv4_option->get_port(); + + if (its_first_port == ILLEGAL_PORT) { + its_first_address = its_ipv4_address; + its_first_port = its_ipv4_option->get_port(); + is_first_reliable = (its_ipv4_option->get_layer_four_protocol() + == layer_four_protocol_e::TCP); + + if(!check_ipv4_address(its_first_address) + || 0 == its_first_port) { + insert_subscription_nack(its_message_response, its_service, its_instance, + its_eventgroup, its_counter, its_major, its_reserved); + VSOMEIP_ERROR << "Invalid port or IP address in first endpoint option specified!"; + return; + } + } else + if (its_second_port == ILLEGAL_PORT) { + its_second_address = its_ipv4_address; + its_second_port = its_ipv4_option->get_port(); + is_second_reliable = (its_ipv4_option->get_layer_four_protocol() + == layer_four_protocol_e::TCP); + + if(!check_ipv4_address(its_second_address) + || 0 == its_second_port) { + insert_subscription_nack(its_message_response, its_service, its_instance, + its_eventgroup, its_counter, its_major, its_reserved); + VSOMEIP_ERROR << "Invalid port or IP address in second endpoint option specified!"; + return; + } } else { - its_reliable_address = its_ipv4_address; - its_reliable_port = its_ipv4_option->get_port(); + // TODO: error message, too many endpoint options! } } else { VSOMEIP_ERROR @@ -973,18 +1476,24 @@ void service_discovery_impl::process_eventgroupentry( boost::asio::ip::address_v6 its_ipv6_address( its_ipv6_option->get_address()); if (!check_layer_four_protocol(its_ipv6_option)) { - send_eventgroup_subscription_nack(its_service, - its_instance, its_eventgroup, its_major); + insert_subscription_nack(its_message_response, its_service, its_instance, + its_eventgroup, its_counter, its_major, its_reserved); return; } - // TODO: add error handling (port already set) here - if (its_ipv6_option->get_layer_four_protocol() - == layer_four_protocol_e::UDP) { - its_unreliable_address = its_ipv6_address; - its_unreliable_port = its_ipv6_option->get_port(); + + if (its_first_port == ILLEGAL_PORT) { + its_first_address = its_ipv6_address; + its_first_port = its_ipv6_option->get_port(); + is_first_reliable = (its_ipv6_option->get_layer_four_protocol() + == layer_four_protocol_e::TCP); + } else + if (its_second_port == ILLEGAL_PORT) { + its_second_address = its_ipv6_address; + its_second_port = its_ipv6_option->get_port(); + is_second_reliable = (its_ipv6_option->get_layer_four_protocol() + == layer_four_protocol_e::TCP); } else { - its_reliable_address = its_ipv6_address; - its_reliable_port = its_ipv6_option->get_port(); + // TODO: error message, too many endpoint options! } } else { VSOMEIP_ERROR @@ -1001,8 +1510,16 @@ void service_discovery_impl::process_eventgroupentry( boost::asio::ip::address_v4 its_ipv4_address( its_ipv4_option->get_address()); - its_unreliable_address = its_ipv4_address; - its_unreliable_port = its_ipv4_option->get_port(); + if (its_first_port == ILLEGAL_PORT) { + its_first_address = its_ipv4_address; + its_first_port = its_ipv4_option->get_port(); + } else + if (its_second_port == ILLEGAL_PORT) { + its_second_address = its_ipv4_address; + its_second_port = its_ipv4_option->get_port(); + } else { + // TODO: error message, too many endpoint options! + } } else { VSOMEIP_ERROR << "Invalid eventgroup option (IPv4 Multicast)"; @@ -1017,18 +1534,32 @@ void service_discovery_impl::process_eventgroupentry( boost::asio::ip::address_v6 its_ipv6_address( its_ipv6_option->get_address()); - its_unreliable_address = its_ipv6_address; - its_unreliable_port = its_ipv6_option->get_port(); + if (its_first_port == ILLEGAL_PORT) { + its_first_address = its_ipv6_address; + its_first_port = its_ipv6_option->get_port(); + } else + if (its_second_port == ILLEGAL_PORT) { + its_second_address = its_ipv6_address; + its_second_port = its_ipv6_option->get_port(); + } else { + // TODO: error message, too many endpoint options! + } } else { VSOMEIP_ERROR << "Invalid eventgroup option (IPv6 Multicast)"; } break; + case option_type_e::CONFIGURATION: { + if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type) { + } + break; + } case option_type_e::UNKNOWN: default: VSOMEIP_WARNING << "Unsupported eventgroup option"; - send_eventgroup_subscription_nack(its_service, its_instance, - its_eventgroup, its_major); + insert_subscription_nack(its_message_response, its_service, its_instance, + its_eventgroup, its_counter, its_major, its_reserved); + break; } } @@ -1036,93 +1567,180 @@ void service_discovery_impl::process_eventgroupentry( if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type) { handle_eventgroup_subscription(its_service, its_instance, - its_eventgroup, its_major, its_ttl, - (its_reliable_port != ILLEGAL_PORT ? - its_reliable_address : its_unreliable_address), - its_reliable_port, its_unreliable_port); + its_eventgroup, its_major, its_ttl, its_counter, its_reserved, + its_first_address, its_first_port, is_first_reliable, + its_second_address, its_second_port, is_second_reliable, its_message_response, accepted_subscribers); } else { - handle_eventgroup_subscription_ack(its_service, its_instance, - its_eventgroup, its_major, its_ttl, its_unreliable_address, - its_unreliable_port); + if( entry_type_e::SUBSCRIBE_EVENTGROUP_ACK == its_type) { //this type is used for ACK and NACK messages + if(its_ttl > 0) { + handle_eventgroup_subscription_ack(its_service, its_instance, + its_eventgroup, its_major, its_ttl, its_counter, + its_first_address, its_first_port); + } else { + handle_eventgroup_subscription_nack(its_service, its_instance, its_eventgroup, its_counter); + } + } } } void service_discovery_impl::handle_eventgroup_subscription(service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, - ttl_t _ttl, const boost::asio::ip::address &_address, - uint16_t _reliable_port, uint16_t _unreliable_port) { + ttl_t _ttl, uint8_t _counter, uint16_t _reserved, + const boost::asio::ip::address &_first_address, uint16_t _first_port, bool _is_first_reliable, + const boost::asio::ip::address &_second_address, uint16_t _second_port, bool _is_second_reliable, + std::shared_ptr < message_impl > &its_message, + std::vector <accepted_subscriber_t> &accepted_subscribers) { - std::shared_ptr < runtime > its_runtime = runtime_.lock(); - if (!its_runtime) - return; - - std::shared_ptr < message_impl > its_message = - its_runtime->create_message(); if (its_message) { std::shared_ptr < eventgroupinfo > its_info = host_->find_eventgroup( _service, _instance, _eventgroup); bool is_nack(false); - std::shared_ptr < endpoint_definition > its_reliable_subscriber, - its_unreliable_subscriber; - std::shared_ptr < endpoint_definition > its_reliable_target, - its_unreliable_target; + std::shared_ptr < endpoint_definition > its_first_subscriber, + its_second_subscriber; + std::shared_ptr < endpoint_definition > its_first_target, + its_second_target; // Could not find eventgroup or wrong version if (!its_info || _major != its_info->get_major()) { // Create a temporary info object with TTL=0 --> send NACK its_info = std::make_shared < eventgroupinfo > (_major, 0); is_nack = true; - insert_subscription_nack(its_message, _service, _instance, _eventgroup, - its_info); - serialize_and_send(its_message, _address); - //TODO add check if required tcp connection is open + insert_subscription_nack(its_message, _service, _instance, + _eventgroup, _counter, _major, _reserved); return; } else { - boost::asio::ip::address its_target_address; - uint16_t its_target_port; - if (ILLEGAL_PORT != _unreliable_port) { - its_unreliable_subscriber = endpoint_definition::get( - _address, _unreliable_port, false); - if (its_info->get_multicast(its_target_address, - its_target_port)) { - its_unreliable_target = endpoint_definition::get( - its_target_address, its_target_port, false); - } else { - its_unreliable_target = its_unreliable_subscriber; + boost::asio::ip::address its_first_address, its_second_address; + uint16_t its_first_port, its_second_port; + if (ILLEGAL_PORT != _first_port) { + its_first_subscriber = endpoint_definition::get( + _first_address, _first_port, _is_first_reliable); + if (!_is_first_reliable && + its_info->get_multicast(its_first_address, its_first_port)) { // udp multicast + its_first_target = endpoint_definition::get( + its_first_address, its_first_port, false); + } else if(_is_first_reliable) { // tcp unicast + its_first_target = its_first_subscriber; + // check if TCP connection is established by client + if( !is_tcp_connected(_service, _instance, its_first_target) ) { + is_nack = true; + insert_subscription_nack(its_message, _service, _instance, + _eventgroup, _counter, _major, _reserved); + return; + } + } else { // udp unicast + its_first_target = its_first_subscriber; } } - if (ILLEGAL_PORT != _reliable_port) { - its_reliable_subscriber = endpoint_definition::get( - _address, _reliable_port, true); - its_reliable_target = its_reliable_subscriber; + if (ILLEGAL_PORT != _second_port) { + its_second_subscriber = endpoint_definition::get( + _second_address, _second_port, _is_second_reliable); + if (!_is_second_reliable && + its_info->get_multicast(its_second_address, its_second_port)) { // udp multicast + its_second_target = endpoint_definition::get( + its_second_address, its_second_port, false); + } else if (_is_second_reliable) { // tcp unicast + its_second_target = its_second_subscriber; + // check if TCP connection is established by client + if( !is_tcp_connected(_service, _instance, its_second_target) ) { + is_nack = true; + insert_subscription_nack(its_message, _service, _instance, + _eventgroup, _counter, _major, _reserved); + return; + } + } else { // udp unicast + its_second_target = its_second_subscriber; + } } } if (_ttl == 0) { // --> unsubscribe - if (its_unreliable_target) { - host_->on_unsubscribe(_service, _instance, _eventgroup, its_unreliable_target); + if (its_first_subscriber) { + host_->on_unsubscribe(_service, _instance, _eventgroup, its_first_subscriber); } - if (its_reliable_target) { - host_->on_unsubscribe(_service, _instance, _eventgroup, its_reliable_target); + if (its_second_subscriber) { + host_->on_unsubscribe(_service, _instance, _eventgroup, its_second_subscriber); } return; } - insert_subscription_ack(its_message, _service, _instance, _eventgroup, - its_info, _ttl); + std::chrono::high_resolution_clock::time_point its_expiration + = std::chrono::high_resolution_clock::now() + std::chrono::seconds(_ttl); + + if (its_first_target) { + if(!host_->on_subscribe_accepted(_service, _instance, _eventgroup, + its_first_subscriber, its_expiration)) { + is_nack = true; + insert_subscription_nack(its_message, _service, _instance, _eventgroup, + _counter, _major, _reserved); + } + } + if (its_second_subscriber) { + if(!host_->on_subscribe_accepted(_service, _instance, _eventgroup, + its_second_subscriber, its_expiration)) { + is_nack = true; + insert_subscription_nack(its_message, _service, _instance, _eventgroup, + _counter, _major, _reserved); + } + } + + if (!is_nack) + { + insert_subscription_ack(its_message, _service, _instance, _eventgroup, + its_info, _ttl, _counter, _major, _reserved); + + if (its_expiration < next_subscription_expiration_) { + stop_subscription_expiration_timer(); + next_subscription_expiration_ = its_expiration; + start_subscription_expiration_timer(); + } - serialize_and_send(its_message, _address); + if (its_first_target && its_first_subscriber) { + accepted_subscriber_t subscriber_; + subscriber_.service_id = _service; + subscriber_.instance_id = _instance; + subscriber_.eventgroup_ = _eventgroup; + subscriber_.subscriber = its_first_subscriber; + subscriber_.target = its_first_target; + subscriber_.its_expiration = its_expiration; - // Finally register the new subscriber and send him all the fields(!) - if (!is_nack) { - if (its_unreliable_target && its_unreliable_subscriber) { - host_->on_subscribe(_service, _instance, _eventgroup, - its_unreliable_subscriber, its_unreliable_target); + accepted_subscribers.push_back(subscriber_); + } + if (its_second_target && its_second_subscriber) { + accepted_subscriber_t subscriber_; + subscriber_.service_id = _service; + subscriber_.instance_id = _instance; + subscriber_.eventgroup_ = _eventgroup; + subscriber_.subscriber = its_second_subscriber; + subscriber_.target = its_second_target; + subscriber_.its_expiration = its_expiration; + + accepted_subscribers.push_back(subscriber_); } - if (its_reliable_target && its_reliable_subscriber) { - host_->on_subscribe(_service, _instance, _eventgroup, - its_reliable_subscriber, its_reliable_target); + } + } +} + +void service_discovery_impl::handle_eventgroup_subscription_nack(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, uint8_t _counter) { + client_t nackedClient = 0; + std::lock_guard<std::mutex> its_lock(subscribed_mutex_); + auto found_service = subscribed_.find(_service); + if (found_service != subscribed_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + for (auto client : found_eventgroup->second) { + if (client.second->get_counter() == _counter) { + // Deliver nack + nackedClient = client.first; + host_->on_subscribe_nack(client.first, _service, _instance, _eventgroup); + break; + } + } + // Remove nacked subscription + found_eventgroup->second.erase(nackedClient); } } } @@ -1130,11 +1748,11 @@ void service_discovery_impl::handle_eventgroup_subscription(service_t _service, void service_discovery_impl::handle_eventgroup_subscription_ack( service_t _service, instance_t _instance, eventgroup_t _eventgroup, - major_version_t _major, ttl_t _ttl, + major_version_t _major, ttl_t _ttl, uint8_t _counter, const boost::asio::ip::address &_address, uint16_t _port) { (void)_major; (void)_ttl; - + std::lock_guard<std::mutex> its_lock(subscribed_mutex_); auto found_service = subscribed_.find(_service); if (found_service != subscribed_.end()) { auto found_instance = found_service->second.find(_instance); @@ -1142,16 +1760,48 @@ void service_discovery_impl::handle_eventgroup_subscription_ack( auto found_eventgroup = found_instance->second.find(_eventgroup); if (found_eventgroup != found_instance->second.end()) { for (auto its_client : found_eventgroup->second) { - its_client.second->set_acknowledged(true); + if (its_client.second->get_counter() == _counter) { + its_client.second->set_acknowledged(true); + } if (_address.is_multicast()) { host_->on_subscribe_ack(_service, _instance, _address, _port); } + host_->on_subscribe_ack(its_client.first, _service, + _instance, _eventgroup); } + } + } + } +} +bool service_discovery_impl::is_tcp_connected(service_t _service, + instance_t _instance, + std::shared_ptr<vsomeip::endpoint_definition> its_endpoint) { + bool is_connected = false; + services_t offered_services = host_->get_offered_services(); + auto found_service = offered_services.find(_service); + if (found_service != offered_services.end()) { + if (_instance != ANY_INSTANCE) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + std::shared_ptr<serviceinfo> its_info = found_instance->second; + if(its_info) { + //get reliable server endpoint + auto its_reliable_endpoint = its_info->get_endpoint(true); + if(its_reliable_endpoint) { + std::shared_ptr<tcp_server_endpoint_impl> its_ptr(std::static_pointer_cast<tcp_server_endpoint_impl>(its_reliable_endpoint)); + if( !its_ptr->is_established(its_endpoint)) { + } + else { + is_connected = true; + } + } + } } } } + return is_connected; } void service_discovery_impl::serialize_and_send( @@ -1165,23 +1815,23 @@ void service_discovery_impl::serialize_and_send( return; } if (host_->send_to(endpoint_definition::get(_address, port_, reliable_), - serializer_->get_data(), serializer_->get_size())) { + serializer_->get_data(), serializer_->get_size(), port_)) { increment_session(_address); } serializer_->reset(); } void service_discovery_impl::start_ttl_timer() { - ttl_timer_.expires_from_now(std::chrono::seconds(smallest_ttl_)); + ttl_timer_.expires_from_now(std::chrono::milliseconds(smallest_ttl_)); ttl_timer_.async_wait( std::bind(&service_discovery_impl::check_ttl, shared_from_this(), std::placeholders::_1)); } -ttl_t service_discovery_impl::stop_ttl_timer() { - ttl_t remaining = ttl_t(std::chrono::duration_cast< - std::chrono::seconds - >(ttl_timer_.expires_from_now()).count()); +std::chrono::milliseconds service_discovery_impl::stop_ttl_timer() { + std::chrono::milliseconds remaining = std::chrono::duration_cast< + std::chrono::milliseconds + >(ttl_timer_.expires_from_now()); ttl_timer_.cancel(); return (smallest_ttl_ - remaining); } @@ -1215,11 +1865,17 @@ bool service_discovery_impl::check_static_header_fields( VSOMEIP_ERROR << "Invalid message type in SD header"; return false; } + if(_message->get_return_code() > return_code_e::E_OK + && _message->get_return_code()< return_code_e::E_UNKNOWN) { + VSOMEIP_ERROR << "Invalid return code in SD header"; + return false; + } return true; } void service_discovery_impl::send_eventgroup_subscription_nack( - service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major) { + service_t _service, instance_t _instance,eventgroup_t _eventgroup, + major_version_t _major, uint8_t _counter, uint16_t _reserved) { std::shared_ptr<runtime> its_runtime = runtime_.lock(); if (!its_runtime) { return; @@ -1233,7 +1889,7 @@ void service_discovery_impl::send_eventgroup_subscription_nack( its_info = std::make_shared < eventgroupinfo > (_major, 0); } insert_subscription_nack(its_message, _service, _instance, _eventgroup, - its_info); + _counter, _major, _reserved); serialize_and_send(its_message, get_current_remote_address()); } } @@ -1247,5 +1903,113 @@ bool service_discovery_impl::check_layer_four_protocol( return true; } +void service_discovery_impl::send_subscriptions(service_t _service, instance_t _instance, + client_t _client, bool _reliable) { + std::shared_ptr<runtime> its_runtime = runtime_.lock(); + if (!its_runtime) { + return; + } + std::lock_guard<std::mutex> its_lock(subscribed_mutex_); + auto found_service = subscribed_.find(_service); + if (found_service != subscribed_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (auto found_eventgroup : found_instance->second) { + auto found_client = found_eventgroup.second.find(_client); + if (found_client != found_eventgroup.second.end()) { + boost::asio::ip::address its_address; + auto endpoint = found_client->second->get_endpoint(_reliable); + if (endpoint) { + endpoint->get_remote_address(its_address); + std::shared_ptr<message_impl> its_message + = its_runtime->create_message(); + + if(_reliable) { + if(endpoint->is_connected()) { + insert_subscription(its_message, _service, + _instance, found_eventgroup.first, + found_client->second, _reliable, !_reliable); + found_client->second->set_tcp_connection_established(true); + } else { + // don't insert reliable endpoint option if the + // TCP client endpoint is not yet connected + found_client->second->set_tcp_connection_established(false); + } + } else { + insert_subscription(its_message, _service, + _instance, found_eventgroup.first, + found_client->second, _reliable, !_reliable); + } + if(0 < its_message->get_entries().size()) { + serialize_and_send(its_message, its_address); + found_client->second->set_acknowledged(false); + } + } + } + } + } + } +} + +void service_discovery_impl::start_subscription_expiration_timer() { + subscription_expiration_timer_.expires_at(next_subscription_expiration_); + subscription_expiration_timer_.async_wait( + std::bind(&service_discovery_impl::expire_subscriptions, + shared_from_this(), + std::placeholders::_1)); +} + +void service_discovery_impl::stop_subscription_expiration_timer() { + subscription_expiration_timer_.cancel(); +} + +void service_discovery_impl::expire_subscriptions(const boost::system::error_code &_error) { + if (!_error) { + next_subscription_expiration_ = host_->expire_subscriptions(); + start_subscription_expiration_timer(); + } +} + +bool service_discovery_impl::check_ipv4_address( + boost::asio::ip::address its_address) { + //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 + is_valid = false; + + } else { +#if 0 + VSOMEIP_DEBUG << "First 3 triples of subscribers endpoint IP address are valid!"; +#endif + } + } + return is_valid; +} + } // namespace sd } // namespace vsomeip diff --git a/implementation/service_discovery/src/serviceentry_impl.cpp b/implementation/service_discovery/src/serviceentry_impl.cpp index fe31703..9f82b83 100755 --- a/implementation/service_discovery/src/serviceentry_impl.cpp +++ b/implementation/service_discovery/src/serviceentry_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/service_discovery/src/subscription.cpp b/implementation/service_discovery/src/subscription.cpp index dcb2461..402304c 100644 --- a/implementation/service_discovery/src/subscription.cpp +++ b/implementation/service_discovery/src/subscription.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -11,11 +11,16 @@ namespace sd { subscription::subscription(major_version_t _major, ttl_t _ttl, std::shared_ptr<endpoint> _reliable, std::shared_ptr<endpoint> _unreliable, - subscription_type_e _subscription_type) + subscription_type_e _subscription_type, + uint8_t _counter, + std::chrono::high_resolution_clock::time_point _expiration) : major_(_major), ttl_(_ttl), reliable_(_reliable), unreliable_(_unreliable), is_acknowledged_(true), - subscription_type_(_subscription_type) { + tcp_connection_established_(false), + subscription_type_(_subscription_type), + counter_(_counter), + expiration_(_expiration) { } subscription::~subscription() { @@ -53,9 +58,28 @@ void subscription::set_acknowledged(bool _is_acknowledged) { is_acknowledged_ = _is_acknowledged; } +bool subscription::is_tcp_connection_established() const { + return tcp_connection_established_; +} +void subscription::set_tcp_connection_established(bool _is_established) { + tcp_connection_established_ = _is_established; +} + subscription_type_e subscription::get_subscription_type() const { return subscription_type_; } +uint8_t subscription::get_counter() const { + return counter_; +} + +std::chrono::high_resolution_clock::time_point subscription::get_expiration() const { + return expiration_; +} + +void subscription::set_expiration(std::chrono::high_resolution_clock::time_point _expiration) { + expiration_ = _expiration; +} + } // namespace sd } // namespace vsomeip diff --git a/implementation/tracing/include/defines.hpp b/implementation/tracing/include/defines.hpp new file mode 100644 index 0000000..84ad5b6 --- /dev/null +++ b/implementation/tracing/include/defines.hpp @@ -0,0 +1,12 @@ +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef TRACING_INCLUDE_DEFINES_HPP_ +#define TRACING_INCLUDE_DEFINES_HPP_ + +#define VSOMEIP_TC_DEFAULT_CHANNEL_NAME "Trace Connector Network Logging" +#define VSOMEIP_TC_DEFAULT_CHANNEL_ID "TC" + +#endif /* TRACING_INCLUDE_DEFINES_HPP_ */ diff --git a/implementation/tracing/include/enumeration_types.hpp b/implementation/tracing/include/enumeration_types.hpp new file mode 100644 index 0000000..18ac861 --- /dev/null +++ b/implementation/tracing/include/enumeration_types.hpp @@ -0,0 +1,21 @@ +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_TC_ENUMERATION_TYPES_HPP +#define VSOMEIP_TC_ENUMERATION_TYPES_HPP + +namespace vsomeip { +namespace tc { + +enum class filter_criteria_e : uint8_t { + SERVICES = 0x00, + METHODS = 0x01, + CLIENTS = 0x02, +}; + +} // namespace tc +} // namespace vsomeip + +#endif // VSOMEIP_TC_ENUMERATION_TYPES_HPP diff --git a/implementation/tracing/include/trace_connector.hpp b/implementation/tracing/include/trace_connector.hpp new file mode 100644 index 0000000..95803c3 --- /dev/null +++ b/implementation/tracing/include/trace_connector.hpp @@ -0,0 +1,100 @@ +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_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, std::vector<filter_expression_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(); + + 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_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/include/trace_header.hpp b/implementation/tracing/include/trace_header.hpp new file mode 100644 index 0000000..9e86d84 --- /dev/null +++ b/implementation/tracing/include/trace_header.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_TC_TRACE_HEADER_HPP +#define VSOMEIP_TC_TRACE_HEADER_HPP + +#include <memory> + +#include <vsomeip/primitive_types.hpp> + +#define VSOMEIP_TRACE_HEADER_SIZE 8 + +namespace vsomeip { + +class endpoint; + +namespace tc { + +enum class protocol_e : uint8_t { + local = 0x0, + udp = 0x1, + tcp = 0x2, + unknown = 0xFF +}; + +struct trace_header { + bool prepare(const std::shared_ptr<endpoint> &_endpoint, bool _is_sending); + bool prepare(const endpoint* _endpoint, bool _is_sending); + + byte_t data_[VSOMEIP_TRACE_HEADER_SIZE]; +}; + +} // namespace tc +} // namespace vsomeip + +#endif // VSOMEIP_TC_TRACE_HEADER_HPP diff --git a/implementation/tracing/src/trace_connector.cpp b/implementation/tracing/src/trace_connector.cpp new file mode 100644 index 0000000..dc01aa2 --- /dev/null +++ b/implementation/tracing/src/trace_connector.cpp @@ -0,0 +1,361 @@ +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/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_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 + // 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_DEBUG, 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); + } +#endif + + // reset to default + + channels_.clear(); + channels_.insert(std::make_pair(VSOMEIP_TC_DEFAULT_CHANNEL_ID, VSOMEIP_TC_DEFAULT_CHANNEL_NAME)); + + filter_rules_.clear(); +} + +void trace_connector::set_enabled(const bool _enabled) { + is_enabled_ = _enabled; +} + +bool trace_connector::is_enabled() { + return is_enabled_; +} + +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_DEBUG, 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 = its_filter_rule.find(_criteria); + if(it_filter_rule != its_filter_rule.end()) { + // add expression + it_filter_rule->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 = its_filter_rule.find(_criteria); + if(it_filter_rule != its_filter_rule.end()) { + // change expressions + it_filter_rule->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 + + // 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, (void * )_header, + _data_size, (void * )_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 filter_rule_matches = false; + for(auto it_filter_rule = its_filter_rule.begin(); it_filter_rule != its_filter_rule.end(); ++it_filter_rule) { + filter_criteria_e its_criteria = it_filter_rule->first; + auto &its_filter_expressions = it_filter_rule->second; + + // check if filter expressions of filter criteria match + filter_rule_matches = filter_expressions_match(its_criteria, its_filter_expressions, _data, _data_size); + if(!filter_rule_matches) { + // filter expressions of filter criteria does not match + break; + } + } + + if(filter_rule_matches) { + //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) { + for (auto it_expressions = _expressions.begin(); + it_expressions != _expressions.end(); + ++it_expressions) { + filter_expression_t its_filter_expression = *it_expressions; + uint16_t its_message_value = 0; + + + // check if one expression matches (byte order is sometimes wrong -> check both) + its_message_value = (uint16_t)((its_message_value << 8) + first); + its_message_value = (uint16_t)((its_message_value << 8) + second); + if(its_filter_expression == its_message_value) { + return true; + } + + its_message_value = 0; + its_message_value = (uint16_t)((its_message_value << 8) + second); + its_message_value = (uint16_t)((its_message_value << 8) + first); + if(its_filter_expression == its_message_value) { + return true; + } + } + } + + return false; +} + +} // namespace tc +} // namespace vsomeip diff --git a/implementation/tracing/src/trace_header.cpp b/implementation/tracing/src/trace_header.cpp new file mode 100644 index 0000000..6609412 --- /dev/null +++ b/implementation/tracing/src/trace_header.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstring> + +#include "../include/trace_header.hpp" +#include "../../endpoints/include/endpoint.hpp" +#include "../../utility/include/byteorder.hpp" + +namespace vsomeip { +namespace tc { + +bool trace_header::prepare(const std::shared_ptr<endpoint> &_endpoint, bool _is_sending) { + return prepare(_endpoint.get(), _is_sending); +} + +bool trace_header::prepare(const endpoint *_endpoint, bool _is_sending) { + if (!_endpoint) + return false; + + boost::asio::ip::address its_address; + if (_endpoint->get_remote_address(its_address)) { + if (its_address.is_v6()) + return false; + + unsigned long its_address_as_long = its_address.to_v4().to_ulong(); + + data_[0] = VSOMEIP_LONG_BYTE0(its_address_as_long); + data_[1] = VSOMEIP_LONG_BYTE1(its_address_as_long); + data_[2] = VSOMEIP_LONG_BYTE2(its_address_as_long); + data_[3] = VSOMEIP_LONG_BYTE3(its_address_as_long); + + unsigned short its_port = _endpoint->get_remote_port(); + data_[4] = VSOMEIP_WORD_BYTE0(its_port); + data_[5] = VSOMEIP_WORD_BYTE1(its_port); + + if (_endpoint->is_local()) { + data_[6] = static_cast<byte_t>(protocol_e::local); + } else { + if (_endpoint->is_reliable()) { + data_[6] = static_cast<byte_t>(protocol_e::tcp); + } else { + data_[6] = static_cast<byte_t>(protocol_e::udp); + } + } + + data_[7] = static_cast<byte_t>(_is_sending); + + } else { + std::memset(data_, 0, VSOMEIP_TRACE_HEADER_SIZE); + } + return true; +} + +} // namespace tc +} // namespace vsomeip diff --git a/implementation/utility/include/byteorder.hpp b/implementation/utility/include/byteorder.hpp index baea175..2774618 100644 --- a/implementation/utility/include/byteorder.hpp +++ b/implementation/utility/include/byteorder.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/implementation/utility/include/utility.hpp b/implementation/utility/include/utility.hpp index 1b3f7eb..9f3a7e3 100644 --- a/implementation/utility/include/utility.hpp +++ b/implementation/utility/include/utility.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -73,13 +73,17 @@ public: static bool is_folder(const std::string &_path); static struct configuration_data_t *the_configuration_data__; - static bool auto_configuration_init(); + static bool auto_configuration_init(const std::string &_name); static void auto_configuration_exit(); static bool is_routing_manager_host__; static bool is_routing_manager_host(); - static client_t get_client_id(); + static bool is_used_client_id(client_t _client); + static client_t request_client_id(client_t _client); + static void release_client_id(client_t _client); + + static uint16_t its_configuration_refs__; }; } // namespace vsomeip diff --git a/implementation/utility/src/utility.cpp b/implementation/utility/src/utility.cpp index e2cbde4..c711320 100644 --- a/implementation/utility/src/utility.cpp +++ b/implementation/utility/src/utility.cpp @@ -1,29 +1,36 @@ -// Copyright (C) 2014-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifdef WIN32 -#include <Windows.h> -#include <iostream> + #include <iostream> #else -#include <dlfcn.h> -#include <sys/mman.h> + #include <dlfcn.h> + #include <sys/mman.h> #endif #include <sys/stat.h> #ifndef WIN32 -#include <fcntl.h> + #include <fcntl.h> #endif +#include <vsomeip/constants.hpp> #include <vsomeip/defines.hpp> #include "../include/byteorder.hpp" #include "../include/utility.hpp" +#include "../../configuration/include/configuration.hpp" #include "../../configuration/include/internal.hpp" #include "../../logging/include/logger.hpp" +#ifdef WIN32 + #ifndef _WINSOCKAPI_ + #include <Windows.h> + #endif +#endif + namespace vsomeip { uint32_t utility::get_message_size(const byte_t *_data, uint32_t _size) { @@ -109,36 +116,153 @@ bool utility::is_folder(const std::string &_path) { configuration_data_t *utility::the_configuration_data__(nullptr); bool utility::is_routing_manager_host__(false); +uint16_t utility::its_configuration_refs__(0); -bool utility::auto_configuration_init() { -#ifndef WIN32 - int its_descriptor = shm_open(VSOMEIP_SHM_NAME, O_RDWR|O_CREAT|O_EXCL, 0660); +#ifdef WIN32 +HANDLE its_descriptor; +#endif + +bool utility::auto_configuration_init(const std::string &_name) { + std::shared_ptr<configuration> its_config(configuration::get()); +#ifdef WIN32 + its_descriptor = CreateFileMapping( + INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // maximum object size (high-order DWORD) + sizeof(configuration_data_t), // maximum object size (low-order DWORD) + VSOMEIP_SHM_NAME); // name of mapping object + + if (its_descriptor != NULL) { + void *its_segment = (LPTSTR)MapViewOfFile(its_descriptor, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + sizeof(configuration_data_t)); + the_configuration_data__ + = reinterpret_cast<configuration_data_t *>(its_segment); + if (the_configuration_data__ != nullptr && is_routing_manager_host__) { + the_configuration_data__->mutex_ = CreateMutex( + NULL, // default security attributes + true, // initially owned + "vSomeIP\\SharedMemoryLock"); // named mutex + + the_configuration_data__->client_base_ + = static_cast<unsigned short>(its_config->get_diagnosis_address() << 8); + the_configuration_data__->used_client_ids_[0] + = the_configuration_data__->client_base_; + the_configuration_data__->client_base_++; + the_configuration_data__->max_used_client_ids_index_ = 1; + + if (its_config->get_routing_host() == "" || + its_config->get_routing_host() == _name) + is_routing_manager_host__ = true; + + its_configuration_refs__++; + + ReleaseMutex(the_configuration_data__->mutex_); + } + } else { + // TODO: Error + } +#else + const mode_t previous_mask(::umask(static_cast<mode_t>(its_config->get_umask()))); + int its_descriptor = shm_open(VSOMEIP_SHM_NAME, O_RDWR | O_CREAT | O_EXCL, + static_cast<mode_t>(its_config->get_permissions_shm())); + ::umask(previous_mask); if (its_descriptor > -1) { - if (0 == ftruncate(its_descriptor, sizeof(configuration_data_t))) { + if (-1 == ftruncate(its_descriptor, sizeof(configuration_data_t))) { + VSOMEIP_ERROR << "utility::auto_configuration_init: " + "ftruncate failed: " << std::strerror(errno); + } else { void *its_segment = mmap(0, sizeof(configuration_data_t), PROT_READ | PROT_WRITE, MAP_SHARED, its_descriptor, 0); - the_configuration_data__ - = reinterpret_cast<configuration_data_t *>(its_segment); - if (the_configuration_data__ != nullptr) { - std::lock_guard<std::mutex> its_lock(the_configuration_data__->mutex_); - the_configuration_data__->ref_ = 0; - the_configuration_data__->next_client_id_ = (VSOMEIP_DIAGNOSIS_ADDRESS << 8); - is_routing_manager_host__ = true; + if(MAP_FAILED == its_segment) { + VSOMEIP_ERROR << "utility::auto_configuration_init: " + "mmap failed: " << std::strerror(errno); + } else { + the_configuration_data__ + = reinterpret_cast<configuration_data_t *>(its_segment); + if(-1 == ::close(its_descriptor)) { + VSOMEIP_ERROR << "utility::auto_configuration_init: " + "close failed: " << std::strerror(errno); + } + if (the_configuration_data__ != nullptr) { + int ret; + pthread_mutexattr_t attr; + ret = pthread_mutexattr_init(&attr); + if (0 == ret) { + ret = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); + if (0 != ret) { + VSOMEIP_ERROR << "pthread_mutexattr_setpshared() failed " << ret; + } + } else { + VSOMEIP_ERROR << "pthread_mutexattr_init() failed " << ret; + } + ret = pthread_mutex_init(&the_configuration_data__->mutex_, (0==ret)?&attr:NULL); + if (0 != ret) { + VSOMEIP_ERROR << "pthread_mutex_init() failed " << ret; + } + ret = pthread_mutex_lock(&the_configuration_data__->mutex_); + if (0 != ret) { + VSOMEIP_ERROR << "pthread_mutex_lock() failed " << ret; + } + + the_configuration_data__->client_base_ + = static_cast<unsigned short>(its_config->get_diagnosis_address() << 8); + the_configuration_data__->used_client_ids_[0] + = the_configuration_data__->client_base_; + the_configuration_data__->client_base_++; + the_configuration_data__->max_used_client_ids_index_ = 1; + + if (its_config->get_routing_host() == "" || + its_config->get_routing_host() == _name) + is_routing_manager_host__ = true; + + its_configuration_refs__++; + + ret = pthread_mutex_unlock(&the_configuration_data__->mutex_); + if (0 != ret) { + VSOMEIP_ERROR << "pthread_mutex_unlock() failed " << ret; + } + } } - } else { - // TODO: an error message } } else { - its_descriptor = shm_open(VSOMEIP_SHM_NAME, O_RDWR, 0660); - if (its_descriptor > -1) { + const mode_t previous_mask(::umask(static_cast<mode_t>(its_config->get_umask()))); + its_descriptor = shm_open(VSOMEIP_SHM_NAME, O_RDWR, + static_cast<mode_t>(its_config->get_permissions_shm())); + ::umask(previous_mask); + if (-1 == its_descriptor) { + VSOMEIP_ERROR << "utility::auto_configuration_init: " + "shm_open failed: " << std::strerror(errno); + } else { void *its_segment = mmap(0, sizeof(configuration_data_t), PROT_READ | PROT_WRITE, MAP_SHARED, its_descriptor, 0); - the_configuration_data__ - = reinterpret_cast<configuration_data_t *>(its_segment); - } else { - // TODO: an error message + if(MAP_FAILED == its_segment) { + VSOMEIP_ERROR << "utility::auto_configuration_init: " + "mmap failed: " << std::strerror(errno); + } else { + the_configuration_data__ + = reinterpret_cast<configuration_data_t *>(its_segment); + if (-1 == ::close(its_descriptor)) { + VSOMEIP_ERROR << "utility::auto_configuration_init: " + "close failed: " << std::strerror(errno); + } +#ifdef WIN32 + WaitForSingleObject(the_configuration_data__->mutex_, INFINITE); +#else + pthread_mutex_lock(&the_configuration_data__->mutex_); +#endif + its_configuration_refs__++; +#ifdef WIN32 + ReleaseMutex(the_configuration_data__->mutex_); +#else + pthread_mutex_unlock(&the_configuration_data__->mutex_); +#endif + } } } #endif @@ -146,25 +270,110 @@ bool utility::auto_configuration_init() { } void utility::auto_configuration_exit() { -#ifndef WIN32 if (the_configuration_data__) { - munmap(the_configuration_data__, sizeof(configuration_data_t)); +#ifdef WIN32 + WaitForSingleObject(the_configuration_data__->mutex_, INFINITE); + its_configuration_refs__--; + ReleaseMutex(the_configuration_data__->mutex_); + + if (its_configuration_refs__ == 0) { + UnmapViewOfFile(the_configuration_data__); + } + + if (is_routing_manager_host__) { + CloseHandle(its_descriptor); + } +#else + pthread_mutex_lock(&the_configuration_data__->mutex_); + its_configuration_refs__--; + pthread_mutex_unlock(&the_configuration_data__->mutex_); + + if (its_configuration_refs__ == 0) { + if (-1 == ::munmap(the_configuration_data__, sizeof(configuration_data_t))) { + VSOMEIP_ERROR << "utility::auto_configuration_exit: " + "munmap failed: " << std::strerror(errno); + } else { + VSOMEIP_DEBUG << "utility::auto_configuration_exit: " + "munmap succeeded."; + the_configuration_data__ = nullptr; + } + } if (is_routing_manager_host__) { shm_unlink(VSOMEIP_SHM_NAME); } - } #endif + } } -client_t utility::get_client_id() { +bool utility::is_used_client_id(client_t _client) { + for (int i = 0; + i < the_configuration_data__->max_used_client_ids_index_; + i++) { + if (the_configuration_data__->used_client_ids_[i] == _client) + return true; + } + return false; +} + +client_t utility::request_client_id(client_t _client) { if (the_configuration_data__ != nullptr) { - std::lock_guard<std::mutex> its_lock(the_configuration_data__->mutex_); - the_configuration_data__->next_client_id_++; - return the_configuration_data__->next_client_id_; +#ifdef WIN32 + WaitForSingleObject(the_configuration_data__->mutex_, INFINITE); +#else + pthread_mutex_lock(&the_configuration_data__->mutex_); +#endif + if (the_configuration_data__->max_used_client_ids_index_ + == VSOMEIP_MAX_CLIENTS) { + return ILLEGAL_CLIENT; + } + + if (_client == ILLEGAL_CLIENT || is_used_client_id(_client)) { + _client = the_configuration_data__->client_base_; + } + + while (is_used_client_id(_client)) _client++; + + the_configuration_data__->used_client_ids_[ + the_configuration_data__->max_used_client_ids_index_] = _client; + the_configuration_data__->max_used_client_ids_index_++; +#ifdef WIN32 + ReleaseMutex(the_configuration_data__->mutex_); +#else + pthread_mutex_unlock(&the_configuration_data__->mutex_); +#endif + return _client; } return VSOMEIP_DIAGNOSIS_ADDRESS; } +void utility::release_client_id(client_t _client) { + if (the_configuration_data__ != nullptr) { +#ifdef WIN32 + WaitForSingleObject(the_configuration_data__->mutex_, INFINITE); +#else + pthread_mutex_lock(&the_configuration_data__->mutex_); +#endif + int i = 0; + while (the_configuration_data__->used_client_ids_[i] != _client && + i < the_configuration_data__->max_used_client_ids_index_) { + i++; + } + + if (i < the_configuration_data__->max_used_client_ids_index_) { + the_configuration_data__->max_used_client_ids_index_--; + for (; i < the_configuration_data__->max_used_client_ids_index_; i++) { + the_configuration_data__->used_client_ids_[i] + = the_configuration_data__->used_client_ids_[i+1]; + } + } +#ifdef WIN32 + ReleaseMutex(the_configuration_data__->mutex_); +#else + pthread_mutex_unlock(&the_configuration_data__->mutex_); +#endif + } +} + bool utility::is_routing_manager_host() { return is_routing_manager_host__; } |