| // Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) |
| // This Source Code Form is subject to the terms of the Mozilla Public |
| // License, v. 2.0. If a copy of the MPL was not distributed with this |
| // file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| |
| #include <iomanip> |
| #include <sstream> |
| |
| #include <vsomeip/constants.hpp> |
| #include <vsomeip/defines.hpp> |
| #include <vsomeip/message.hpp> |
| #include <vsomeip/payload.hpp> |
| #include <vsomeip/runtime.hpp> |
| #include <vsomeip/internal/logger.hpp> |
| |
| #include "../include/event.hpp" |
| #include "../include/routing_manager.hpp" |
| #include "../../message/include/payload_impl.hpp" |
| |
| #include "../../endpoints/include/endpoint_definition.hpp" |
| |
| namespace vsomeip_v3 { |
| |
| event::event(routing_manager *_routing, bool _is_shadow) : |
| routing_(_routing), |
| message_(runtime::get()->create_notification()), |
| type_(event_type_e::ET_EVENT), |
| cycle_timer_(_routing->get_io()), |
| cycle_(std::chrono::milliseconds::zero()), |
| change_resets_cycle_(false), |
| is_updating_on_change_(true), |
| is_set_(false), |
| is_provided_(false), |
| is_shadow_(_is_shadow), |
| is_cache_placeholder_(false), |
| epsilon_change_func_(std::bind(&event::compare, this, |
| std::placeholders::_1, std::placeholders::_2)), |
| reliability_(reliability_type_e::RT_UNKNOWN) { |
| } |
| |
| service_t event::get_service() const { |
| return (message_->get_service()); |
| } |
| |
| void event::set_service(service_t _service) { |
| message_->set_service(_service); |
| } |
| |
| instance_t event::get_instance() const { |
| return (message_->get_instance()); |
| } |
| |
| void event::set_instance(instance_t _instance) { |
| message_->set_instance(_instance); |
| } |
| |
| major_version_t event::get_version() const { |
| return message_->get_interface_version(); |
| } |
| |
| void event::set_version(major_version_t _major) { |
| message_->set_interface_version(_major); |
| } |
| |
| event_t event::get_event() const { |
| return (message_->get_method()); |
| } |
| |
| void event::set_event(event_t _event) { |
| message_->set_method(_event); |
| } |
| |
| event_type_e event::get_type() const { |
| return (type_); |
| } |
| |
| void event::set_type(const event_type_e _type) { |
| type_ = _type; |
| } |
| |
| bool event::is_field() const { |
| return (type_ == event_type_e::ET_FIELD); |
| } |
| |
| bool event::is_provided() const { |
| return (is_provided_); |
| } |
| |
| void event::set_provided(bool _is_provided) { |
| is_provided_ = _is_provided; |
| } |
| |
| bool event::is_set() const { |
| return is_set_; |
| } |
| |
| const std::shared_ptr<payload> event::get_payload() const { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| return (message_->get_payload()); |
| } |
| |
| bool event::set_payload_dont_notify(const std::shared_ptr<payload> &_payload) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| if (is_cache_placeholder_) { |
| reset_payload(_payload); |
| is_set_ = true; |
| } else { |
| if (set_payload_helper(_payload, false)) { |
| reset_payload(_payload); |
| } else { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| void event::set_payload(const std::shared_ptr<payload> &_payload, bool _force) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| if (is_provided_) { |
| if (set_payload_helper(_payload, _force)) { |
| reset_payload(_payload); |
| if (is_updating_on_change_) { |
| if (change_resets_cycle_) |
| stop_cycle(); |
| |
| notify(); |
| |
| if (change_resets_cycle_) |
| start_cycle(); |
| } |
| } |
| } else { |
| VSOMEIP_INFO << "Can't set payload for event " |
| << std::hex << std::setw(4) << std::setfill('0') |
| << get_service() << "." << get_instance() << "." << get_event() |
| << " as it isn't provided"; |
| } |
| } |
| |
| void event::set_payload(const std::shared_ptr<payload> &_payload, client_t _client, |
| bool _force) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| if (is_provided_) { |
| if (set_payload_helper(_payload, _force)) { |
| reset_payload(_payload); |
| if (is_updating_on_change_) { |
| notify_one_unlocked(_client); |
| } |
| } |
| } else { |
| VSOMEIP_INFO << "Can't set payload for event " |
| << std::hex << std::setw(4) << std::setfill('0') |
| << get_service() << "." << get_instance() << "." << get_event() |
| << ". It isn't provided"; |
| } |
| } |
| |
| void event::set_payload(const std::shared_ptr<payload> &_payload, |
| const client_t _client, |
| const std::shared_ptr<endpoint_definition>& _target, |
| bool _force) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| if (is_provided_) { |
| if (set_payload_helper(_payload, _force)) { |
| reset_payload(_payload); |
| if (is_updating_on_change_) { |
| notify_one_unlocked(_client, _target); |
| } |
| } |
| } else { |
| VSOMEIP_INFO << "Can't set payload for event " |
| << std::hex << std::setw(4) << std::setfill('0') |
| << get_service() << "." << get_instance() << "." << get_event() |
| << ". It isn't provided"; |
| } |
| } |
| |
| bool event::set_payload_notify_pending(const std::shared_ptr<payload> &_payload) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| if (!is_set_ && is_provided_) { |
| reset_payload(_payload); |
| |
| // Send pending initial events. |
| for (const auto &its_target : pending_) { |
| message_->set_session(routing_->get_session()); |
| routing_->send_to(VSOMEIP_ROUTING_CLIENT, |
| its_target, message_); |
| } |
| pending_.clear(); |
| |
| return true; |
| } |
| |
| return false; |
| } |
| |
| void event::unset_payload(bool _force) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| if (_force) { |
| is_set_ = false; |
| stop_cycle(); |
| message_->set_payload(std::make_shared<payload_impl>()); |
| } else { |
| if (is_provided_) { |
| is_set_ = false; |
| stop_cycle(); |
| message_->set_payload(std::make_shared<payload_impl>()); |
| } |
| } |
| } |
| |
| void event::set_update_cycle(std::chrono::milliseconds &_cycle) { |
| if (is_provided_) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| stop_cycle(); |
| cycle_ = _cycle; |
| start_cycle(); |
| } |
| } |
| |
| void event::set_change_resets_cycle(bool _change_resets_cycle) { |
| change_resets_cycle_ = _change_resets_cycle; |
| } |
| |
| void event::set_update_on_change(bool _is_active) { |
| if (is_provided_) { |
| is_updating_on_change_ = _is_active; |
| } |
| } |
| |
| void event::set_epsilon_change_function(const epsilon_change_func_t &_epsilon_change_func) { |
| if (_epsilon_change_func) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| epsilon_change_func_ = _epsilon_change_func; |
| } |
| } |
| |
| const std::set<eventgroup_t> event::get_eventgroups() const { |
| std::set<eventgroup_t> its_eventgroups; |
| { |
| std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); |
| for (const auto& e : eventgroups_) { |
| its_eventgroups.insert(e.first); |
| } |
| } |
| return its_eventgroups; |
| } |
| |
| std::set<eventgroup_t> event::get_eventgroups(client_t _client) const { |
| std::set<eventgroup_t> its_eventgroups; |
| |
| std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); |
| for (auto e : eventgroups_) { |
| if (e.second.find(_client) != e.second.end()) |
| its_eventgroups.insert(e.first); |
| } |
| return its_eventgroups; |
| } |
| |
| void event::add_eventgroup(eventgroup_t _eventgroup) { |
| std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); |
| if (eventgroups_.find(_eventgroup) == eventgroups_.end()) |
| eventgroups_[_eventgroup] = std::set<client_t>(); |
| } |
| |
| void event::set_eventgroups(const std::set<eventgroup_t> &_eventgroups) { |
| std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); |
| for (auto e : _eventgroups) |
| eventgroups_[e] = std::set<client_t>(); |
| } |
| |
| void event::update_cbk(boost::system::error_code const &_error) { |
| if (!_error) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| cycle_timer_.expires_from_now(cycle_); |
| notify(); |
| auto its_handler = |
| std::bind(&event::update_cbk, shared_from_this(), |
| std::placeholders::_1); |
| cycle_timer_.async_wait(its_handler); |
| } |
| } |
| |
| void event::notify() { |
| if (is_set_) { |
| message_->set_session(routing_->get_session()); |
| routing_->send(VSOMEIP_ROUTING_CLIENT, message_); |
| } else { |
| VSOMEIP_INFO << __func__ |
| << ": Notifying " |
| << std::hex << std::setw(4) << std::setfill('0') |
| << get_service() << "." << get_instance() << "." << get_event() |
| << " failed. Event payload not (yet) set!"; |
| } |
| } |
| |
| void event::notify_one(client_t _client, |
| const std::shared_ptr<endpoint_definition> &_target) { |
| if (_target) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| notify_one_unlocked(_client, _target); |
| } else { |
| VSOMEIP_WARNING << __func__ |
| << ": Notifying " |
| << std::hex << std::setw(4) << std::setfill('0') |
| << get_service() << "." << get_instance() << "." << get_event() |
| << " failed. Target undefined"; |
| } |
| } |
| |
| void event::notify_one_unlocked(client_t _client, |
| const std::shared_ptr<endpoint_definition> &_target) { |
| if (_target) { |
| if (is_set_) { |
| message_->set_session(routing_->get_session()); |
| routing_->send_to(_client, _target, message_); |
| } else { |
| VSOMEIP_INFO << __func__ |
| << ": Notifying " |
| << std::hex << std::setw(4) << std::setfill('0') |
| << get_service() << "." << get_instance() << "." << get_event() |
| << " failed. Event payload not (yet) set!"; |
| pending_.insert(_target); |
| } |
| } else { |
| VSOMEIP_WARNING << __func__ |
| << ": Notifying " |
| << std::hex << std::setw(4) << std::setfill('0') |
| << get_service() << "." << get_instance() << "." << get_event() |
| << " failed. Target undefined"; |
| } |
| } |
| |
| void event::notify_one(client_t _client) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| notify_one_unlocked(_client); |
| } |
| |
| void event::notify_one_unlocked(client_t _client) { |
| if (is_set_) { |
| message_->set_session(routing_->get_session()); |
| routing_->send(_client, message_); |
| } else { |
| VSOMEIP_INFO << __func__ |
| << ": Notifying " |
| << std::hex << std::setw(4) << std::setfill('0') |
| << get_service() << "." << get_instance() << "." << get_event() |
| << " to client " << _client |
| << " failed. Event payload not set!"; |
| } |
| } |
| |
| bool event::set_payload_helper(const std::shared_ptr<payload> &_payload, bool _force) { |
| std::shared_ptr<payload> its_payload = message_->get_payload(); |
| bool is_change(type_ != event_type_e::ET_FIELD); |
| if (!is_change) { |
| is_change = _force || epsilon_change_func_(its_payload, _payload); |
| } |
| return is_change; |
| } |
| |
| void event::reset_payload(const std::shared_ptr<payload> &_payload) { |
| std::shared_ptr<payload> its_new_payload |
| = runtime::get()->create_payload( |
| _payload->get_data(), _payload->get_length()); |
| message_->set_payload(its_new_payload); |
| |
| if (!is_set_) |
| start_cycle(); |
| |
| is_set_ = true; |
| } |
| |
| void event::add_ref(client_t _client, bool _is_provided) { |
| std::lock_guard<std::mutex> its_lock(refs_mutex_); |
| auto its_client = refs_.find(_client); |
| if (its_client == refs_.end()) { |
| refs_[_client][_is_provided] = 1; |
| } else { |
| auto its_provided = its_client->second.find(_is_provided); |
| if (its_provided == its_client->second.end()) { |
| refs_[_client][_is_provided] = 1; |
| } else { |
| its_provided->second++; |
| } |
| } |
| } |
| |
| void event::remove_ref(client_t _client, bool _is_provided) { |
| std::lock_guard<std::mutex> its_lock(refs_mutex_); |
| auto its_client = refs_.find(_client); |
| if (its_client != refs_.end()) { |
| auto its_provided = its_client->second.find(_is_provided); |
| if (its_provided != its_client->second.end()) { |
| its_provided->second--; |
| if (0 == its_provided->second) { |
| its_client->second.erase(_is_provided); |
| if (0 == its_client->second.size()) { |
| refs_.erase(_client); |
| } |
| } |
| } |
| } |
| } |
| |
| bool event::has_ref() { |
| std::lock_guard<std::mutex> its_lock(refs_mutex_); |
| return refs_.size() != 0; |
| } |
| |
| bool event::add_subscriber(eventgroup_t _eventgroup, client_t _client, bool _force) { |
| std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); |
| bool ret = false; |
| if (_force // remote events managed by rm_impl |
| || is_provided_ // events provided by rm_proxies |
| || is_shadow_ // local events managed by rm_impl |
| || is_cache_placeholder_) { |
| ret = eventgroups_[_eventgroup].insert(_client).second; |
| } else { |
| VSOMEIP_WARNING << __func__ << ": Didnt' insert client " |
| << std::hex << std::setw(4) << std::setfill('0') |
| << _client |
| << " to eventgroup " |
| << std::hex << std::setw(4) << std::setfill('0') |
| << get_service() << "." << get_instance() << "." |
| << _eventgroup; |
| } |
| return ret; |
| } |
| |
| void event::remove_subscriber(eventgroup_t _eventgroup, client_t _client) { |
| std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); |
| auto find_eventgroup = eventgroups_.find(_eventgroup); |
| if (find_eventgroup != eventgroups_.end()) |
| find_eventgroup->second.erase(_client); |
| } |
| |
| bool event::has_subscriber(eventgroup_t _eventgroup, client_t _client) { |
| std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); |
| auto find_eventgroup = eventgroups_.find(_eventgroup); |
| if (find_eventgroup != eventgroups_.end()) { |
| if (_client == ANY_CLIENT) { |
| return (find_eventgroup->second.size() > 0); |
| } else { |
| return (find_eventgroup->second.find(_client) |
| != find_eventgroup->second.end()); |
| } |
| } |
| return false; |
| } |
| |
| std::set<client_t> event::get_subscribers() { |
| std::set<client_t> its_subscribers; |
| std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); |
| for (const auto &e : eventgroups_) |
| its_subscribers.insert(e.second.begin(), e.second.end()); |
| return its_subscribers; |
| } |
| |
| void event::clear_subscribers() { |
| std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); |
| for (auto &e : eventgroups_) |
| e.second.clear(); |
| } |
| |
| bool event::has_ref(client_t _client, bool _is_provided) { |
| std::lock_guard<std::mutex> its_lock(refs_mutex_); |
| auto its_client = refs_.find(_client); |
| if (its_client != refs_.end()) { |
| auto its_provided = its_client->second.find(_is_provided); |
| if (its_provided != its_client->second.end()) { |
| if(its_provided->second > 0) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| bool event::is_shadow() const { |
| return is_shadow_; |
| } |
| |
| void event::set_shadow(bool _shadow) { |
| is_shadow_ = _shadow; |
| } |
| |
| bool event::is_cache_placeholder() const { |
| return is_cache_placeholder_; |
| } |
| |
| void event::set_cache_placeholder(bool _is_cache_place_holder) { |
| is_cache_placeholder_ = _is_cache_place_holder; |
| } |
| |
| void event::start_cycle() { |
| if (std::chrono::milliseconds::zero() != cycle_) { |
| cycle_timer_.expires_from_now(cycle_); |
| auto its_handler = |
| std::bind(&event::update_cbk, shared_from_this(), |
| std::placeholders::_1); |
| cycle_timer_.async_wait(its_handler); |
| } |
| } |
| |
| void event::stop_cycle() { |
| if (std::chrono::milliseconds::zero() != cycle_) { |
| boost::system::error_code ec; |
| cycle_timer_.cancel(ec); |
| } |
| } |
| |
| bool event::compare(const std::shared_ptr<payload> &_lhs, |
| const std::shared_ptr<payload> &_rhs) const { |
| bool is_change = (_lhs->get_length() != _rhs->get_length()); |
| if (!is_change) { |
| std::size_t its_pos = 0; |
| const byte_t *its_old_data = _lhs->get_data(); |
| const byte_t *its_new_data = _rhs->get_data(); |
| while (!is_change && its_pos < _lhs->get_length()) { |
| is_change = (*its_old_data++ != *its_new_data++); |
| its_pos++; |
| } |
| } |
| return is_change; |
| } |
| |
| std::set<client_t> event::get_subscribers(eventgroup_t _eventgroup) { |
| std::set<client_t> its_subscribers; |
| std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); |
| auto found_eventgroup = eventgroups_.find(_eventgroup); |
| if (found_eventgroup != eventgroups_.end()) { |
| its_subscribers = found_eventgroup->second; |
| } |
| return its_subscribers; |
| } |
| |
| bool event::is_subscribed(client_t _client) { |
| std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); |
| for (const auto &egp : eventgroups_) { |
| if (egp.second.find(_client) != egp.second.end()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| reliability_type_e |
| event::get_reliability() const { |
| return reliability_; |
| } |
| |
| void |
| event::set_reliability(const reliability_type_e _reliability) { |
| reliability_ = _reliability; |
| } |
| |
| void |
| event::remove_pending(const std::shared_ptr<endpoint_definition> &_target) { |
| std::lock_guard<std::mutex> its_lock(mutex_); |
| pending_.erase(_target); |
| } |
| |
| } // namespace vsomeip_v3 |