summaryrefslogtreecommitdiff
path: root/implementation/endpoints/src/tp_message.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'implementation/endpoints/src/tp_message.cpp')
-rw-r--r--implementation/endpoints/src/tp_message.cpp352
1 files changed, 352 insertions, 0 deletions
diff --git a/implementation/endpoints/src/tp_message.cpp b/implementation/endpoints/src/tp_message.cpp
new file mode 100644
index 0000000..f786a4f
--- /dev/null
+++ b/implementation/endpoints/src/tp_message.cpp
@@ -0,0 +1,352 @@
+// Copyright (C) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.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/internal/logger.hpp>
+
+#include "../include/tp_message.hpp"
+#include "../include/tp.hpp"
+#include "../../utility/include/byteorder.hpp"
+
+#ifdef ANDROID
+#include "../../configuration/include/internal_android.hpp"
+#else
+#include "../../configuration/include/internal.hpp"
+#endif // ANDROID
+
+#ifndef _WIN32
+#include <arpa/inet.h>
+#else
+#include <Winsock2.h>
+#endif
+
+
+namespace vsomeip_v3 {
+namespace tp {
+
+tp_message::tp_message(const byte_t* const _data, std::uint32_t _data_length,
+ std::uint32_t _max_message_size) :
+ timepoint_creation_(std::chrono::steady_clock::now()),
+ max_message_size_(_max_message_size),
+ current_message_size_(0),
+ last_segment_received_(false) {
+ if (_data_length < VSOMEIP_FULL_HEADER_SIZE + VSOMEIP_TP_HEADER_SIZE) {
+ VSOMEIP_ERROR << __func__ << " received too short SOME/IP-TP message "
+ << get_message_id(_data, _data_length);
+ return;
+ }
+ // copy header
+ message_.insert(message_.end(), _data, _data + VSOMEIP_FULL_HEADER_SIZE);
+ // remove TP flag
+ message_[VSOMEIP_MESSAGE_TYPE_POS] = static_cast<byte_t>(tp::tp_flag_unset(
+ message_[VSOMEIP_MESSAGE_TYPE_POS]));
+
+ const length_t its_segment_size = _data_length - VSOMEIP_FULL_HEADER_SIZE
+ - VSOMEIP_TP_HEADER_SIZE;
+ const tp_header_t its_tp_header = VSOMEIP_BYTES_TO_LONG(
+ _data[VSOMEIP_TP_HEADER_POS_MIN],
+ _data[VSOMEIP_TP_HEADER_POS_MIN + 1],
+ _data[VSOMEIP_TP_HEADER_POS_MIN + 2],
+ _data[VSOMEIP_TP_HEADER_POS_MAX]);
+
+ if (check_lengths(_data, _data_length, its_segment_size,
+ tp::more_segments(its_tp_header))) {
+ const length_t its_offset = tp::get_offset(its_tp_header);
+ segments_.emplace(segment_t(its_offset, its_offset + its_segment_size - 1));
+ if (its_offset != 0) {
+ // segment different than the first segment was received
+ message_.resize(VSOMEIP_FULL_HEADER_SIZE + its_offset, 0x0);
+ if (!tp::more_segments(its_tp_header)) {
+ // received the last segment of the segmented message first
+ last_segment_received_ = true;
+ }
+ }
+ message_.insert(message_.end(), &_data[VSOMEIP_TP_PAYLOAD_POS],
+ &_data[VSOMEIP_TP_PAYLOAD_POS] + its_segment_size);
+ current_message_size_ += VSOMEIP_FULL_HEADER_SIZE + its_segment_size;
+ }
+}
+
+bool tp_message::add_segment(const byte_t* const _data,
+ std::uint32_t _data_length) {
+ if (_data_length < VSOMEIP_FULL_HEADER_SIZE + VSOMEIP_TP_HEADER_SIZE) {
+ VSOMEIP_ERROR << __func__ << " received too short SOME/IP-TP message "
+ << get_message_id(_data, _data_length);
+ return false;
+ }
+ bool ret = false;
+
+ const length_t its_segment_size = _data_length - VSOMEIP_FULL_HEADER_SIZE
+ - VSOMEIP_TP_HEADER_SIZE;
+ const tp_header_t its_tp_header = VSOMEIP_BYTES_TO_LONG(
+ _data[VSOMEIP_TP_HEADER_POS_MIN],
+ _data[VSOMEIP_TP_HEADER_POS_MIN + 1],
+ _data[VSOMEIP_TP_HEADER_POS_MIN + 2],
+ _data[VSOMEIP_TP_HEADER_POS_MAX]);
+
+ if (check_lengths(_data, _data_length, its_segment_size,
+ tp::more_segments(its_tp_header))) {
+ const length_t its_offset = tp::get_offset(its_tp_header);
+ const auto emplace_res = segments_.emplace(
+ segment_t(its_offset, its_offset + its_segment_size - 1));
+ if (!emplace_res.second) {
+ VSOMEIP_WARNING << __func__ << ":" << __LINE__
+ << " received duplicate segment " << get_message_id(_data, _data_length)
+ << "TP offset: 0x" << std::hex << its_offset;
+ } else {
+ const auto& seg_current = emplace_res.first;
+ const auto& seg_next = std::next(seg_current);
+ const bool current_segment_is_last = (seg_next == segments_.end());
+ const bool current_segment_is_first = (seg_current == segments_.begin());
+ if (current_segment_is_last) {
+ if (current_segment_is_first) {
+ // received segment of message but the first received segment was invalid
+ // resize + append
+ VSOMEIP_WARNING << __func__ << ":" << __LINE__
+ << " received 2nd segment of message. But the "
+ "first received segment already wasn't accepted. "
+ "The message can't be completed anymore: "
+ << get_message_id(_data, _data_length);
+ if (its_offset != 0) {
+ // segment different than the first segment was received
+ message_.resize(VSOMEIP_FULL_HEADER_SIZE + its_offset, 0x0);
+ if (!tp::more_segments(its_tp_header)) {
+ // received the last segment of the segmented message first
+ last_segment_received_ = true;
+ }
+ }
+ // append to end of message
+ message_.insert(message_.end(), &_data[VSOMEIP_TP_PAYLOAD_POS],
+ &_data[VSOMEIP_TP_PAYLOAD_POS] + its_segment_size);
+ current_message_size_ += its_segment_size;
+ } else {
+ const auto& seg_prev = std::prev(seg_current);
+ if (seg_prev->end_ < seg_current->start_) {
+ const bool direct_previous_segment_present = (seg_prev->end_ + 1 == seg_current->start_);
+ if (!direct_previous_segment_present) {
+ // received segment out of order behind the current end of received segments
+ //resize + append
+ message_.resize(VSOMEIP_FULL_HEADER_SIZE + its_offset, 0x0);
+ }
+ // append to end of message
+ message_.insert(message_.end(), &_data[VSOMEIP_TP_PAYLOAD_POS],
+ &_data[VSOMEIP_TP_PAYLOAD_POS] + its_segment_size);
+ current_message_size_ += its_segment_size;
+ } else {
+ // this segment starts before the end of the previous and
+ // would overwrite already received data
+ VSOMEIP_WARNING << __func__ << ":" << __LINE__
+ << " completely accepting segment would overwrite previous segment "
+ << get_message_id(_data, _data_length)
+ << "previous segment end: " << std::dec << seg_prev->end_ + 1
+ << " this segment start: " << std::dec << seg_current->start_;
+ message_.insert(message_.end(),
+ &_data[VSOMEIP_TP_PAYLOAD_POS] + ((seg_prev->end_ + 1) - seg_current->start_),
+ &_data[VSOMEIP_TP_PAYLOAD_POS] + its_segment_size);
+ // update start of current segment
+ const std::uint32_t current_end = seg_current->end_;
+ segments_.erase(seg_current);
+ segments_.emplace(segment_t(seg_prev->end_ + 1, current_end));
+ current_message_size_ += current_end - seg_prev->end_;
+ }
+ }
+ } else {
+ // received segment in wrong order and other segments afterwards were already received
+ if ((seg_current != segments_.begin() && std::prev(seg_current)->end_ < seg_current->start_)
+ || seg_current == segments_.begin()) { // no need to check prev_segment if current segment is the first
+ if (seg_current->end_ < seg_next->start_) {
+ std::memcpy(&message_[VSOMEIP_FULL_HEADER_SIZE + its_offset], &_data[VSOMEIP_TP_PAYLOAD_POS], its_segment_size);
+ current_message_size_ += its_segment_size;
+ } else {
+ // this segment ends after the start of the next and
+ // would overwrite already received data
+ VSOMEIP_WARNING << __func__ << ":" << __LINE__
+ << " completely accepting segment would overwrite next segment "
+ << get_message_id(_data, _data_length)
+ << "next segment start: " << std::dec << seg_next->start_
+ << " this segment end: " << std::dec << seg_current->end_ + 1;
+ std::memcpy(&message_[VSOMEIP_FULL_HEADER_SIZE + its_offset], &_data[VSOMEIP_TP_PAYLOAD_POS], seg_next->start_ - its_offset);
+ // update current segment length to match size of memory
+ std::uint32_t current_start = seg_current->start_;
+ segments_.erase(seg_current);
+ segments_.emplace(segment_t(current_start, seg_next->start_ - 1));
+ current_message_size_ += seg_next->start_ - current_start;
+ }
+ } else if (seg_current->end_ < seg_next->start_) {
+ // this segment starts before the end of the previous and
+ // would overwrite already received data. But ends before the
+ // start of the next segment
+ const auto& seg_prev = std::prev(seg_current);
+ VSOMEIP_WARNING << __func__ << ":" << __LINE__
+ << " completely accepting segment would overwrite previous segment "
+ << get_message_id(_data, _data_length)
+ << "previous segment end: " << std::dec << seg_prev->end_
+ << " this segment start: " << std::dec << seg_current->start_;
+ const length_t its_corrected_offset = seg_prev->end_ + 1;
+ std::memcpy(&message_[VSOMEIP_FULL_HEADER_SIZE + its_corrected_offset],
+ &_data[VSOMEIP_TP_PAYLOAD_POS] + its_corrected_offset - its_offset,
+ seg_next->start_ - its_corrected_offset);
+ // update current segment length to match size of memory
+ std::uint32_t current_end = seg_current->end_;
+ segments_.erase(seg_current);
+ segments_.emplace(segment_t(seg_prev->end_ + 1, current_end));
+ current_message_size_ += current_end - seg_prev->end_;
+ } else {
+ // this segment starts before the end of the previous and
+ // ends after the start of the next segment and would
+ // overwrite already received data.
+ const auto& seg_prev = std::prev(seg_current);
+ VSOMEIP_WARNING << __func__ << ":" << __LINE__
+ << " completely accepting segment would overwrite "
+ << "previous and next segment "
+ << get_message_id(_data, _data_length)
+ << "previous segment end: " << std::dec << seg_prev->end_
+ << " this segment start: " << std::dec << seg_current->start_
+ << " this segment end: " << std::dec << seg_current->end_
+ << " next segment start: " << std::dec << seg_next->start_;
+ const length_t its_corrected_offset = seg_prev->end_ + 1;
+ std::memcpy(&message_[VSOMEIP_FULL_HEADER_SIZE + its_corrected_offset],
+ &_data[VSOMEIP_TP_PAYLOAD_POS] + its_corrected_offset - its_offset,
+ seg_next->start_ - its_corrected_offset);
+ segments_.erase(seg_current);
+ segments_.emplace(segment_t(seg_prev->end_ + 1, seg_next->start_ - 1));
+ current_message_size_ += seg_next->start_ - (seg_prev->end_ + 1);
+ }
+ }
+ if (!tp::more_segments(its_tp_header)) {
+ // received the last segment
+ last_segment_received_ = true;
+ }
+ if (last_segment_received_) {
+ // check if all segments are present
+ std::uint32_t last_end = (std::numeric_limits<std::uint32_t>::max)();
+ bool complete(true);
+ for (const auto& seg : segments_) {
+ if (last_end + 1 != seg.start_) {
+ complete = false;
+ break;
+ } else {
+ last_end = seg.end_;
+ }
+ }
+ if (complete) {
+ // all segments were received -> update length field of message
+ const length_t its_length = static_cast<length_t>(
+ message_.size() - VSOMEIP_SOMEIP_HEADER_SIZE);
+ *(reinterpret_cast<length_t*>(&message_[VSOMEIP_LENGTH_POS_MIN])) = htonl(its_length);
+ // all segments were received -> update return code field of message
+ message_[VSOMEIP_RETURN_CODE_POS] = _data[VSOMEIP_RETURN_CODE_POS];
+ ret = true;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+message_buffer_t tp_message::get_message() {
+ return std::move(message_);
+}
+
+std::chrono::steady_clock::time_point tp_message::get_creation_time() const {
+ return timepoint_creation_;
+}
+
+std::string tp_message::get_message_id(const byte_t* const _data, std::uint32_t _data_length) {
+ std::stringstream ss;
+ if (_data_length >= VSOMEIP_FULL_HEADER_SIZE) {
+ const service_t its_service = VSOMEIP_BYTES_TO_WORD(
+ _data[VSOMEIP_SERVICE_POS_MIN], _data[VSOMEIP_SERVICE_POS_MAX]);
+ const method_t its_method = VSOMEIP_BYTES_TO_WORD(
+ _data[VSOMEIP_METHOD_POS_MIN], _data[VSOMEIP_METHOD_POS_MAX]);
+ const client_t its_client = VSOMEIP_BYTES_TO_WORD(
+ _data[VSOMEIP_CLIENT_POS_MIN], _data[VSOMEIP_CLIENT_POS_MAX]);
+ const session_t its_session = VSOMEIP_BYTES_TO_WORD(
+ _data[VSOMEIP_SESSION_POS_MIN], _data[VSOMEIP_SESSION_POS_MAX]);
+ const interface_version_t its_interface_version =
+ _data[VSOMEIP_INTERFACE_VERSION_POS];
+ const message_type_e its_msg_type = tp::tp_flag_unset(
+ _data[VSOMEIP_MESSAGE_TYPE_POS]);
+
+ ss << "("
+ << std::hex << std::setw(4) << std::setfill('0') << its_client << ") ["
+ << std::hex << std::setw(4) << std::setfill('0') << its_service << "."
+ << std::hex << std::setw(4) << std::setfill('0') << its_method << "."
+ << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(its_interface_version) << "."
+ << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(its_msg_type) << "."
+ << std::hex << std::setw(4) << std::setfill('0') << its_session
+ << "] ";
+ if (_data_length > VSOMEIP_TP_HEADER_POS_MAX) {
+ const tp_header_t its_tp_header = VSOMEIP_BYTES_TO_LONG(
+ _data[VSOMEIP_TP_HEADER_POS_MIN],
+ _data[VSOMEIP_TP_HEADER_POS_MIN + 1],
+ _data[VSOMEIP_TP_HEADER_POS_MIN + 2],
+ _data[VSOMEIP_TP_HEADER_POS_MAX]);
+ const length_t its_offset = tp::get_offset(its_tp_header);
+ ss << " TP offset: 0x" << std::hex << its_offset << " ";
+ }
+ }
+ return ss.str();
+}
+
+bool tp_message::check_lengths(const byte_t* const _data,
+ std::uint32_t _data_length,
+ length_t _segment_size, bool _more_fragments) {
+ const length_t its_length = VSOMEIP_BYTES_TO_LONG(
+ _data[VSOMEIP_LENGTH_POS_MIN],
+ _data[VSOMEIP_LENGTH_POS_MIN + 1],
+ _data[VSOMEIP_LENGTH_POS_MIN + 2],
+ _data[VSOMEIP_LENGTH_POS_MAX]);
+ bool ret(true);
+ if (!tp::tp_flag_is_set(_data[VSOMEIP_MESSAGE_TYPE_POS])) {
+ VSOMEIP_ERROR << __func__ << ": TP flag not set "
+ << get_message_id(_data, _data_length);
+ ret = false;
+ } else if (_data_length != its_length + VSOMEIP_SOMEIP_HEADER_SIZE) {
+ VSOMEIP_ERROR << __func__
+ << ": data length doesn't match header length field"
+ << get_message_id(_data, _data_length)
+ << " data: " << std::dec << _data_length
+ << " header: " << std::dec << its_length;
+ ret = false;
+ } else if (_segment_size != its_length - VSOMEIP_TP_HEADER_SIZE
+ - (VSOMEIP_FULL_HEADER_SIZE - VSOMEIP_SOMEIP_HEADER_SIZE)) {
+ VSOMEIP_ERROR << __func__
+ << ": segment size doesn't align with header length field"
+ << get_message_id(_data, _data_length)
+ << "segment size: " << std::dec << _segment_size
+ << " data: " << std::dec << _data_length
+ << " header: " << std::dec << its_length;
+ ret = false;
+ } else if (_segment_size > tp::tp_max_segment_length_) {
+ VSOMEIP_ERROR << __func__ << ": Segment exceeds allowed size "
+ << get_message_id(_data, _data_length)
+ << "segment size: " << std::dec << _segment_size << " (max. "
+ << std::dec << tp::tp_max_segment_length_
+ << ") data: " << std::dec << _data_length
+ << " header: " << std::dec << its_length;
+ ret = false;
+ } else if (_more_fragments && _segment_size % 16 > 0) {
+ VSOMEIP_ERROR << __func__ << ": Segment size not multiple of 16 "
+ << get_message_id(_data, _data_length)
+ << "segment size: " << std::dec << _segment_size
+ << " data: " << std::dec << _data_length
+ << " header: " << std::dec << its_length;
+ ret = false;
+ } else if (current_message_size_ + _segment_size > max_message_size_) {
+ VSOMEIP_ERROR << __func__ << ": Message exceeds maximum configured size: "
+ << get_message_id(_data, _data_length)
+ << "segment size: " << std::dec << _segment_size
+ << " current message size: " << std::dec << current_message_size_
+ << " maximum message size: " << std::dec << max_message_size_;
+ ret = false;
+ }
+ return ret;
+}
+
+} // namespace tp
+} // namespace vsomeip_v3