summaryrefslogtreecommitdiff
path: root/implementation
diff options
context:
space:
mode:
authorJürgen Gehring <Juergen.Gehring@bmw.de>2016-09-20 03:59:53 -0700
committerJürgen Gehring <Juergen.Gehring@bmw.de>2016-09-20 03:59:53 -0700
commit273814c76be4a8f906dc053492529b8d53b9e807 (patch)
treee7160dc68fe3f478a0c5c86aaccaeb620d528b63 /implementation
parent4c5d160362d8693aed8abd642212e68c9778bbda (diff)
downloadvSomeIP-273814c76be4a8f906dc053492529b8d53b9e807.tar.gz
vSomeIP 2.2.42.2.4
Diffstat (limited to 'implementation')
-rw-r--r--implementation/configuration/include/client.hpp28
-rw-r--r--implementation/configuration/include/configuration.hpp39
-rw-r--r--implementation/configuration/include/configuration_impl.hpp137
-rw-r--r--implementation/configuration/include/event.hpp2
-rw-r--r--implementation/configuration/include/eventgroup.hpp4
-rw-r--r--implementation/configuration/include/internal.hpp.in61
-rw-r--r--implementation/configuration/include/service.hpp3
-rw-r--r--implementation/configuration/include/trace.hpp62
-rw-r--r--implementation/configuration/include/watchdog.hpp21
-rw-r--r--implementation/configuration/src/configuration.cpp2
-rw-r--r--implementation/configuration/src/configuration_impl.cpp907
-rw-r--r--implementation/endpoints/include/buffer.hpp2
-rw-r--r--implementation/endpoints/include/client_endpoint_impl.hpp27
-rw-r--r--implementation/endpoints/include/endpoint.hpp6
-rw-r--r--implementation/endpoints/include/endpoint_definition.hpp2
-rw-r--r--implementation/endpoints/include/endpoint_host.hpp8
-rw-r--r--implementation/endpoints/include/endpoint_impl.hpp18
-rw-r--r--implementation/endpoints/include/local_client_endpoint_impl.hpp25
-rw-r--r--implementation/endpoints/include/local_server_endpoint_impl.hpp22
-rw-r--r--implementation/endpoints/include/server_endpoint_impl.hpp21
-rw-r--r--implementation/endpoints/include/tcp_client_endpoint_impl.hpp8
-rw-r--r--implementation/endpoints/include/tcp_server_endpoint_impl.hpp13
-rw-r--r--implementation/endpoints/include/udp_client_endpoint_impl.hpp9
-rw-r--r--implementation/endpoints/include/udp_server_endpoint_impl.hpp30
-rw-r--r--implementation/endpoints/include/virtual_server_endpoint_impl.hpp6
-rw-r--r--implementation/endpoints/src/client_endpoint_impl.cpp159
-rw-r--r--implementation/endpoints/src/endpoint_definition.cpp2
-rw-r--r--implementation/endpoints/src/endpoint_impl.cpp93
-rw-r--r--implementation/endpoints/src/local_client_endpoint_impl.cpp150
-rw-r--r--implementation/endpoints/src/local_server_endpoint_impl.cpp62
-rw-r--r--implementation/endpoints/src/server_endpoint_impl.cpp97
-rw-r--r--implementation/endpoints/src/tcp_client_endpoint_impl.cpp93
-rw-r--r--implementation/endpoints/src/tcp_server_endpoint_impl.cpp124
-rw-r--r--implementation/endpoints/src/udp_client_endpoint_impl.cpp58
-rw-r--r--implementation/endpoints/src/udp_server_endpoint_impl.cpp218
-rw-r--r--implementation/endpoints/src/virtual_server_endpoint_impl.cpp12
-rw-r--r--implementation/helper/boost/asio/basic_datagram_socket_ext.hpp954
-rw-r--r--implementation/helper/boost/asio/datagram_socket_service_ext.hpp437
-rw-r--r--implementation/helper/boost/asio/detail/handler_type_requirements_ext.hpp516
-rw-r--r--implementation/helper/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp270
-rw-r--r--implementation/helper/boost/asio/detail/impl/socket_ops_ext.ipp210
-rw-r--r--implementation/helper/boost/asio/detail/reactive_socket_recv_op_ext.hpp126
-rw-r--r--implementation/helper/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp136
-rw-r--r--implementation/helper/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp128
-rw-r--r--implementation/helper/boost/asio/detail/reactive_socket_service_base_ext.hpp455
-rw-r--r--implementation/helper/boost/asio/detail/reactive_socket_service_ext.hpp462
-rw-r--r--implementation/helper/boost/asio/detail/reactor_op_ext.hpp42
-rw-r--r--implementation/helper/boost/asio/detail/socket_ops_ext.hpp62
-rw-r--r--implementation/helper/boost/asio/ip/udp_ext.hpp115
-rw-r--r--implementation/logging/include/defines.hpp15
-rw-r--r--implementation/logging/include/dlt_sink_backend.hpp6
-rw-r--r--implementation/logging/include/logger.hpp2
-rw-r--r--implementation/logging/include/logger_impl.hpp5
-rw-r--r--implementation/logging/src/dlt_sink_backend.cpp15
-rw-r--r--implementation/logging/src/logger.cpp2
-rw-r--r--implementation/logging/src/logger_impl.cpp23
-rw-r--r--implementation/message/include/deserializer.hpp2
-rw-r--r--implementation/message/include/message_base_impl.hpp6
-rw-r--r--implementation/message/include/message_header_impl.hpp2
-rw-r--r--implementation/message/include/message_impl.hpp12
-rw-r--r--implementation/message/include/payload_impl.hpp2
-rw-r--r--implementation/message/include/serializer.hpp2
-rw-r--r--implementation/message/src/deserializer.cpp6
-rw-r--r--implementation/message/src/message_base_impl.cpp10
-rw-r--r--implementation/routing/include/event.hpp29
-rw-r--r--implementation/routing/include/eventgroupinfo.hpp35
-rw-r--r--implementation/routing/include/routing_manager.hpp21
-rw-r--r--implementation/routing/include/routing_manager_adapter.hpp2
-rw-r--r--implementation/routing/include/routing_manager_base.hpp193
-rw-r--r--implementation/routing/include/routing_manager_host.hpp6
-rw-r--r--implementation/routing/include/routing_manager_impl.hpp160
-rw-r--r--implementation/routing/include/routing_manager_proxy.hpp83
-rw-r--r--implementation/routing/include/routing_manager_stub.hpp47
-rw-r--r--implementation/routing/include/routing_manager_stub_host.hpp29
-rw-r--r--implementation/routing/include/serviceinfo.hpp22
-rw-r--r--implementation/routing/include/types.hpp2
-rw-r--r--implementation/routing/src/event.cpp123
-rw-r--r--implementation/routing/src/eventgroupinfo.cpp86
-rw-r--r--implementation/routing/src/routing_manager_base.cpp782
-rw-r--r--implementation/routing/src/routing_manager_impl.cpp1824
-rw-r--r--implementation/routing/src/routing_manager_proxy.cpp809
-rw-r--r--implementation/routing/src/routing_manager_stub.cpp586
-rw-r--r--implementation/routing/src/serviceinfo.cpp50
-rw-r--r--implementation/runtime/include/application_impl.hpp125
-rw-r--r--implementation/runtime/include/runtime_impl.hpp7
-rw-r--r--implementation/runtime/src/application_impl.cpp963
-rw-r--r--implementation/runtime/src/error.cpp2
-rw-r--r--implementation/runtime/src/runtime.cpp10
-rw-r--r--implementation/runtime/src/runtime_impl.cpp14
-rw-r--r--implementation/service_discovery/include/configuration_option_impl.hpp2
-rw-r--r--implementation/service_discovery/include/constants.hpp2
-rw-r--r--implementation/service_discovery/include/defines.hpp16
-rwxr-xr-ximplementation/service_discovery/include/deserializer.hpp2
-rwxr-xr-ximplementation/service_discovery/include/entry_impl.hpp5
-rw-r--r--implementation/service_discovery/include/enumeration_types.hpp2
-rwxr-xr-ximplementation/service_discovery/include/eventgroupentry_impl.hpp13
-rw-r--r--implementation/service_discovery/include/fsm_base.hpp12
-rw-r--r--implementation/service_discovery/include/fsm_events.hpp21
-rw-r--r--implementation/service_discovery/include/ip_option_impl.hpp2
-rw-r--r--implementation/service_discovery/include/ipv4_option_impl.hpp2
-rw-r--r--implementation/service_discovery/include/ipv6_option_impl.hpp2
-rwxr-xr-ximplementation/service_discovery/include/load_balancing_option_impl.hpp2
-rwxr-xr-ximplementation/service_discovery/include/message_element_impl.hpp2
-rwxr-xr-ximplementation/service_discovery/include/message_impl.hpp12
-rw-r--r--implementation/service_discovery/include/option_impl.hpp2
-rw-r--r--implementation/service_discovery/include/primitive_types.hpp2
-rwxr-xr-ximplementation/service_discovery/include/protection_option_impl.hpp2
-rw-r--r--implementation/service_discovery/include/request.hpp7
-rw-r--r--implementation/service_discovery/include/runtime.hpp2
-rw-r--r--implementation/service_discovery/include/runtime_impl.hpp2
-rw-r--r--implementation/service_discovery/include/service_discovery.hpp24
-rw-r--r--implementation/service_discovery/include/service_discovery_fsm.hpp74
-rw-r--r--implementation/service_discovery/include/service_discovery_host.hpp30
-rw-r--r--implementation/service_discovery/include/service_discovery_impl.hpp157
-rw-r--r--implementation/service_discovery/include/serviceentry_impl.hpp2
-rw-r--r--implementation/service_discovery/include/subscription.hpp20
-rwxr-xr-ximplementation/service_discovery/src/configuration_option_impl.cpp50
-rw-r--r--implementation/service_discovery/src/deserializer.cpp2
-rwxr-xr-ximplementation/service_discovery/src/entry_impl.cpp31
-rwxr-xr-ximplementation/service_discovery/src/eventgroupentry_impl.cpp53
-rw-r--r--implementation/service_discovery/src/fsm_base.cpp40
-rw-r--r--implementation/service_discovery/src/ip_option_impl.cpp2
-rw-r--r--implementation/service_discovery/src/ipv4_option_impl.cpp6
-rwxr-xr-ximplementation/service_discovery/src/ipv6_option_impl.cpp6
-rwxr-xr-ximplementation/service_discovery/src/load_balancing_option_impl.cpp2
-rwxr-xr-ximplementation/service_discovery/src/message_element_impl.cpp2
-rwxr-xr-ximplementation/service_discovery/src/message_impl.cpp9
-rwxr-xr-ximplementation/service_discovery/src/option_impl.cpp2
-rwxr-xr-ximplementation/service_discovery/src/protection_option_impl.cpp2
-rw-r--r--implementation/service_discovery/src/request.cpp13
-rw-r--r--implementation/service_discovery/src/runtime.cpp2
-rw-r--r--implementation/service_discovery/src/runtime_impl.cpp2
-rw-r--r--implementation/service_discovery/src/service_discovery_fsm.cpp205
-rw-r--r--implementation/service_discovery/src/service_discovery_impl.cpp1536
-rwxr-xr-ximplementation/service_discovery/src/serviceentry_impl.cpp2
-rw-r--r--implementation/service_discovery/src/subscription.cpp30
-rw-r--r--implementation/tracing/include/defines.hpp12
-rw-r--r--implementation/tracing/include/enumeration_types.hpp21
-rw-r--r--implementation/tracing/include/trace_connector.hpp100
-rw-r--r--implementation/tracing/include/trace_header.hpp38
-rw-r--r--implementation/tracing/src/trace_connector.cpp361
-rw-r--r--implementation/tracing/src/trace_header.cpp58
-rw-r--r--implementation/utility/include/byteorder.hpp2
-rw-r--r--implementation/utility/include/utility.hpp10
-rw-r--r--implementation/utility/src/utility.cpp273
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__;
}