// Copyright (C) 2014-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include #include #include #include // internal[_android.hpp] must be included before defines.hpp #ifdef ANDROID #include "../../configuration/include/internal_android.hpp" #else #include "../../configuration/include/internal.hpp" #endif // ANDROID #include "../include/constants.hpp" #include "../include/defines.hpp" #include "../include/eventgroupentry_impl.hpp" #include "../include/serviceentry_impl.hpp" #include "../include/configuration_option_impl.hpp" #include "../include/ipv4_option_impl.hpp" #include "../include/ipv6_option_impl.hpp" #include "../include/load_balancing_option_impl.hpp" #include "../include/protection_option_impl.hpp" #include "../include/selective_option_impl.hpp" #include "../include/message_impl.hpp" #include "../../message/include/deserializer.hpp" #include "../../message/include/payload_impl.hpp" #include "../../message/include/serializer.hpp" namespace vsomeip_v3 { namespace sd { message_impl::message_impl() : flags_(0x0), options_length_(0x0), current_message_size_(VSOMEIP_SOMEIP_SD_EMPTY_MESSAGE_SIZE) { header_.service_ = VSOMEIP_SD_SERVICE; header_.instance_ = VSOMEIP_SD_INSTANCE; header_.method_ = VSOMEIP_SD_METHOD; header_.client_ = VSOMEIP_SD_CLIENT; // session must be set dynamically header_.protocol_version_ = protocol_version; header_.interface_version_ = interface_version; header_.type_ = message_type; header_.code_ = return_code; set_unicast_flag(true); } message_impl::~message_impl() { } length_t message_impl::get_length() const { length_t current_length = VSOMEIP_SOMEIP_SD_DATA_SIZE; if( entries_.size()) { current_length += VSOMEIP_SOMEIP_SD_ENTRY_LENGTH_SIZE; current_length += uint32_t(entries_.size() * VSOMEIP_SOMEIP_SD_ENTRY_SIZE); } current_length += VSOMEIP_SOMEIP_SD_OPTION_LENGTH_SIZE; if(options_.size()) { for (size_t i = 0; i < options_.size(); ++i) { current_length += static_cast(options_[i]->get_length() + VSOMEIP_SOMEIP_SD_OPTION_HEADER_SIZE); } } return current_length; } length_t message_impl::get_size() const { return current_message_size_; } #define VSOMEIP_REBOOT_FLAG 0x80 bool message_impl::get_reboot_flag() const { return ((flags_ & VSOMEIP_REBOOT_FLAG) != 0); } void message_impl::set_reboot_flag(bool _is_set) { if (_is_set) flags_ |= flags_t(VSOMEIP_REBOOT_FLAG); else flags_ &= flags_t(~VSOMEIP_REBOOT_FLAG); } #define VSOMEIP_UNICAST_FLAG 0x40 bool message_impl::get_unicast_flag() const { return ((flags_ & VSOMEIP_UNICAST_FLAG) != 0); } void message_impl::set_unicast_flag(bool _is_set) { if (_is_set) flags_ |= flags_t(VSOMEIP_UNICAST_FLAG); else flags_ &= flags_t(~VSOMEIP_UNICAST_FLAG); } bool message_impl::add_entry_data(const std::shared_ptr &_entry, const std::vector > &_options, const std::shared_ptr &_other) { std::uint32_t its_entry_size = VSOMEIP_SOMEIP_SD_ENTRY_SIZE; std::map, bool> its_options; if (_other) { its_entry_size += VSOMEIP_SOMEIP_SD_ENTRY_SIZE; } // TODO: Check whether it is possible to express the options // by the two runs. If there are more than two options, it // might be necessary to copy an option, which then increases // the size... for (const std::shared_ptr &its_option : _options) { const auto its_existing_option = find_option(its_option); if (!its_existing_option) { its_entry_size += its_option->get_size(); its_options[its_option] = true; } else { its_options[its_existing_option] = false; } } if (current_message_size_ + its_entry_size > VSOMEIP_MAX_UDP_SD_PAYLOAD) return false; entries_.push_back(_entry); _entry->set_owning_message(this); for (const auto &its_option : its_options) { if (its_option.second) { options_.push_back(its_option.first); its_option.first->set_owning_message(this); } _entry->assign_option(its_option.first); } if (_other) { entries_.push_back(_other); _other->set_owning_message(this); for (const auto &its_option : its_options) { _other->assign_option(its_option.first); } } current_message_size_ += its_entry_size; return true; } bool message_impl::has_entry() const { return (0 < entries_.size()); } bool message_impl::has_option() const { return (0 < options_.size()); } void message_impl::set_length(length_t _length) { (void)_length; } const message_impl::entries_t & message_impl::get_entries() const { return entries_; } const message_impl::options_t & message_impl::get_options() const { return options_; } std::shared_ptr message_impl::find_option(const std::shared_ptr &_option) const { for (auto its_option : options_) { if (its_option->equals(_option)) return its_option; } return nullptr; } int16_t message_impl::get_option_index( const std::shared_ptr &_option) const { int16_t i = 0; while (i < int16_t(options_.size())) { if (options_[static_cast(i)] == _option) return i; i++; } return -1; } std::shared_ptr message_impl::get_option(int16_t _index) const { if (_index > -1) { size_t its_index = static_cast(_index); if (its_index < options_.size()) return options_[its_index]; } return nullptr; } uint32_t message_impl::get_options_length() { return options_length_; } std::shared_ptr message_impl::get_payload() const { return std::make_shared(); } void message_impl::set_payload(std::shared_ptr _payload) { (void)_payload; } uint8_t message_impl::get_check_result() const { return 1; } void message_impl::set_check_result(uint8_t _check_result) { (void)_check_result; } bool message_impl::is_valid_crc() const { return false; } bool message_impl::serialize(vsomeip_v3::serializer *_to) const { bool is_successful = header_.serialize(_to); is_successful = is_successful && _to->serialize(flags_); is_successful = is_successful && _to->serialize(protocol::reserved_long, true); uint32_t entries_length = uint32_t(entries_.size() * VSOMEIP_SOMEIP_SD_ENTRY_SIZE); is_successful = is_successful && _to->serialize(entries_length); for (const auto& its_entry : entries_) is_successful = is_successful && its_entry && its_entry->serialize(_to); uint32_t options_length = 0; for (const auto& its_option : options_) options_length += its_option ? static_cast(its_option->get_length() + VSOMEIP_SOMEIP_SD_OPTION_HEADER_SIZE) : 0; is_successful = is_successful && _to->serialize(options_length); for (const auto& its_option : options_) is_successful = is_successful && its_option && its_option->serialize(_to); return is_successful; } bool message_impl::deserialize(vsomeip_v3::deserializer *_from) { bool is_successful; bool option_is_successful(true); // header is_successful = header_.deserialize(_from); // flags is_successful = is_successful && _from->deserialize(flags_); // reserved uint32_t reserved; is_successful = is_successful && _from->deserialize(reserved, true); // entries uint32_t entries_length = 0; is_successful = is_successful && _from->deserialize(entries_length); // backup the current remaining length uint32_t save_remaining = uint32_t(_from->get_remaining()); if (!is_successful) { // couldn't deserialize entries length return is_successful; } else if (entries_length > save_remaining) { // not enough data available to deserialize entries array is_successful = false; return is_successful; } // set remaining bytes to length of entries array _from->set_remaining(entries_length); // deserialize the entries while (is_successful && _from->get_remaining()) { std::shared_ptr < entry_impl > its_entry(deserialize_entry(_from)); if (its_entry) { entries_.push_back(its_entry); } else { is_successful = false; } } // set length to remaining bytes after entries array _from->set_remaining(save_remaining - entries_length); // Don't try to deserialize options if there aren't any if(_from->get_remaining() == 0) { return is_successful; } // deserialize the options is_successful = is_successful && _from->deserialize(options_length_); // check if there is unreferenced data behind the last option and discard it if(_from->get_remaining() > options_length_) { _from->set_remaining(options_length_); } 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 { option_is_successful = false; } } current_message_size_ = 0; return is_successful; } entry_impl * message_impl::deserialize_entry(vsomeip_v3::deserializer *_from) { entry_impl *deserialized_entry = 0; uint8_t tmp_entry_type; if (_from->look_ahead(0, tmp_entry_type)) { entry_type_e deserialized_entry_type = static_cast(tmp_entry_type); switch (deserialized_entry_type) { case entry_type_e::FIND_SERVICE: case entry_type_e::OFFER_SERVICE: //case entry_type_e::STOP_OFFER_SERVICE: case entry_type_e::REQUEST_SERVICE: deserialized_entry = new serviceentry_impl; break; case entry_type_e::FIND_EVENT_GROUP: case entry_type_e::PUBLISH_EVENTGROUP: //case entry_type_e::STOP_PUBLISH_EVENTGROUP: case entry_type_e::SUBSCRIBE_EVENTGROUP: //case entry_type_e::STOP_SUBSCRIBE_EVENTGROUP: case entry_type_e::SUBSCRIBE_EVENTGROUP_ACK: //case entry_type_e::STOP_SUBSCRIBE_EVENTGROUP_ACK: deserialized_entry = new eventgroupentry_impl; break; default: break; }; // deserialize object if (0 != deserialized_entry) { deserialized_entry->set_owning_message(this); if (!deserialized_entry->deserialize(_from)) { delete deserialized_entry; deserialized_entry = 0; }; } } return deserialized_entry; } option_impl * message_impl::deserialize_option(vsomeip_v3::deserializer *_from) { option_impl *deserialized_option = 0; uint8_t tmp_option_type; if (_from->look_ahead(2, tmp_option_type)) { option_type_e deserialized_option_type = static_cast(tmp_option_type); switch (deserialized_option_type) { case option_type_e::CONFIGURATION: deserialized_option = new configuration_option_impl; break; case option_type_e::LOAD_BALANCING: deserialized_option = new load_balancing_option_impl; break; case option_type_e::PROTECTION: deserialized_option = new protection_option_impl; break; case option_type_e::IP4_ENDPOINT: case option_type_e::IP4_MULTICAST: deserialized_option = new ipv4_option_impl; break; case option_type_e::IP6_ENDPOINT: case option_type_e::IP6_MULTICAST: deserialized_option = new ipv6_option_impl; break; case option_type_e::SELECTIVE: deserialized_option = new selective_option_impl; break; default: deserialized_option = new option_impl(); break; }; // deserialize object if (0 != deserialized_option && !deserialized_option->deserialize(_from)) { delete deserialized_option; deserialized_option = 0; }; } return deserialized_option; } length_t message_impl::get_someip_length() const { return header_.length_; } uid_t message_impl::get_uid() const { return ANY_UID; } gid_t message_impl::get_gid() const { return ANY_GID; } } // namespace sd } // namespace vsomeip_v3