diff options
author | Jürgen Gehring <Juergen.Gehring@bmw.de> | 2016-09-20 03:59:53 -0700 |
---|---|---|
committer | Jürgen Gehring <Juergen.Gehring@bmw.de> | 2016-09-20 03:59:53 -0700 |
commit | 273814c76be4a8f906dc053492529b8d53b9e807 (patch) | |
tree | e7160dc68fe3f478a0c5c86aaccaeb620d528b63 /implementation/service_discovery | |
parent | 4c5d160362d8693aed8abd642212e68c9778bbda (diff) | |
download | vSomeIP-273814c76be4a8f906dc053492529b8d53b9e807.tar.gz |
vSomeIP 2.2.42.2.4
Diffstat (limited to 'implementation/service_discovery')
47 files changed, 1836 insertions, 582 deletions
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 |