From 6da9b7bc0c2c742d4ce011fcd64769572bd52d44 Mon Sep 17 00:00:00 2001 From: Michael Saborov Date: Wed, 22 Jul 2026 16:09:42 +0200 Subject: [PATCH 1/2] Dynamic config and file_transfer impl migration --- .../dynamic_config/dynamic_config_impl/BUILD | 58 +++ .../dynamic_config_session.h | 59 +++ .../dynamic_config_session_factory.h | 42 ++ .../file_transfer/file_transfer_impl/BUILD | 64 +++ .../file_transfer_stream_handler_factory.h | 76 ++++ .../filetransfer_stream.cpp | 364 ++++++++++++++++++ .../file_transfer_impl/filetransfer_stream.h | 83 ++++ 7 files changed, 746 insertions(+) create mode 100644 score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/BUILD create mode 100644 score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/dynamic_config_session.h create mode 100644 score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/dynamic_config_session_factory.h create mode 100644 score/datarouter/src/file_transfer/file_transfer_impl/BUILD create mode 100644 score/datarouter/src/file_transfer/file_transfer_impl/file_transfer_stream_handler_factory.h create mode 100644 score/datarouter/src/file_transfer/file_transfer_impl/filetransfer_stream.cpp create mode 100644 score/datarouter/src/file_transfer/file_transfer_impl/filetransfer_stream.h diff --git a/score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/BUILD b/score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/BUILD new file mode 100644 index 00000000..165e01ba --- /dev/null +++ b/score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/BUILD @@ -0,0 +1,58 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") + +[ + cc_library( + name = "dynamic_config_session" + name, + testonly = test_only, + hdrs = [ + "dynamic_config_session.h", + "dynamic_config_session_factory.h", + ], + features = COMPILER_WARNING_FEATURES, + strip_include_prefix = ".", + visibility = visibility, + deps = deps + [ + "//score/datarouter/src/configuration/dynamic_config:i_session", + ], + ) + for name, test_only, visibility, deps in [ + ( + "", + False, + [ + "@score_logging//score/datarouter:__pkg__", + "@score_logging//score/datarouter:__subpackages__", + ], + [ + "@score_logging//score/datarouter:unixdomain_server", + "//score/datarouter/src/configuration/dynamic_config:config_session_factory", + ], + ), + ( + "_testing", + True, + [ + "@score_logging//score/datarouter:__pkg__", + "//score/datarouter/test:__subpackages__", + ], + [ + "@score_logging//score/datarouter:unixdomain_mock", + "//score/datarouter/src/configuration/dynamic_config:config_session_factory_testing", + ], + ), + ] +] diff --git a/score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/dynamic_config_session.h b/score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/dynamic_config_session.h new file mode 100644 index 00000000..0c674572 --- /dev/null +++ b/score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/dynamic_config_session.h @@ -0,0 +1,59 @@ +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef DYNAMIC_CONFIG_SESSION_H +#define DYNAMIC_CONFIG_SESSION_H + +#include "unix_domain/unix_domain_server.h" +#include +namespace score +{ +namespace logging +{ +namespace daemon +{ + +class ConfigSession final : public score::platform::internal::UnixDomainServer::ISession +{ + public: + template + ConfigSession(score::platform::internal::UnixDomainServer::SessionHandle handle, Handler&& handler) + : handle_(std::move(handle)), handler_(std::forward(handler)) + { + } + + ~ConfigSession() override = default; + + private: + // Not called from production code. + // LCOV_EXCL_START + bool Tick() override + { + return false; + } + // LCOV_EXCL_STOP + void OnCommand(const std::string& command) override final + { + auto response = handler_(command); + handle_.PassMessage(response); + } + + score::platform::internal::UnixDomainServer::SessionHandle handle_; + std::function handler_; +}; + +} // namespace daemon +} // namespace logging +} // namespace score + +#endif // DYNAMIC_CONFIG_SESSION_H diff --git a/score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/dynamic_config_session_factory.h b/score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/dynamic_config_session_factory.h new file mode 100644 index 00000000..261b1c59 --- /dev/null +++ b/score/datarouter/src/configuration/dynamic_config/dynamic_config_impl/dynamic_config_session_factory.h @@ -0,0 +1,42 @@ +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef DYNAMIC_CONFIG_SESSION_FACTORY_H +#define DYNAMIC_CONFIG_SESSION_FACTORY_H + +#include "config_session_factory.hpp" +#include "dynamic_config_session.h" + +namespace score +{ +namespace logging +{ +namespace daemon +{ + +class DynamicConfigSessionFactory : public ConfigSessionFactory +{ + public: + template + std::unique_ptr CreateConcreteSession(score::platform::internal::UnixDomainServer::SessionHandle handle, + Handler&& handler) + { + return std::make_unique(std::move(handle), std::forward(handler)); + } +}; + +} // namespace daemon +} // namespace logging +} // namespace score + +#endif // DYNAMIC_CONFIG_SESSION_FACTORY_H diff --git a/score/datarouter/src/file_transfer/file_transfer_impl/BUILD b/score/datarouter/src/file_transfer/file_transfer_impl/BUILD new file mode 100644 index 00000000..dd77e4d3 --- /dev/null +++ b/score/datarouter/src/file_transfer/file_transfer_impl/BUILD @@ -0,0 +1,64 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") + +cc_library( + name = "file_transfer_stream_handler_factory", + hdrs = [ + "file_transfer_stream_handler_factory.h", + ], + features = COMPILER_WARNING_FEATURES, + visibility = [ + "//score/datarouter/test:__subpackages__", + ], + deps = [ + ":file_transfer_stream_handler", + "//score/datarouter/src/file_transfer:file_transfer_handler_factory", + "@score_logging//score/datarouter:logparser", + ], +) + +[ + cc_library( + name = "file_transfer_stream_handler" + name, + testonly = test_only, + srcs = [ + "filetransfer_stream.cpp", + ], + hdrs = [ + "filetransfer_stream.h", + ], + features = COMPILER_WARNING_FEATURES, + visibility = [ + "@score_logging//score/datarouter:__pkg__", + ], + deps = [ + "@score_baselibs//score/mw/log", + "@score_baselibs//score/os:stat", + "@score_baselibs//score/os:stdio", + "@score_baselibs//score/os/utils:thread", + "@score_logging//score/datarouter:dltprotocol", + "@score_logging//score/datarouter:dltserver_common", + "@score_logging//score/datarouter:logparser", + udp_dep, + "//score/datarouter/dlt_filetransfer_trigger_lib:filetransfer_message_types", + "@score_baselibs//score/language/futurecpp", + ], + ) + for name, udp_dep, test_only in [ + ("", "@score_logging//score/datarouter:udp_stream_output", False), + ("_testing", "@score_logging//score/datarouter:udpoutput_mock", True), + ] +] diff --git a/score/datarouter/src/file_transfer/file_transfer_impl/file_transfer_stream_handler_factory.h b/score/datarouter/src/file_transfer/file_transfer_impl/file_transfer_stream_handler_factory.h new file mode 100644 index 00000000..842a882f --- /dev/null +++ b/score/datarouter/src/file_transfer/file_transfer_impl/file_transfer_stream_handler_factory.h @@ -0,0 +1,76 @@ +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef PAS_LOGGING_FILE_TRANSFER_STREAM_HANDLER_FACTORY_H +#define PAS_LOGGING_FILE_TRANSFER_STREAM_HANDLER_FACTORY_H + +#include "logparser/logparser.h" +#include "score/datarouter/src/file_transfer/file_transfer_handler_factory.hpp" +#include "score/datarouter/src/file_transfer/file_transfer_impl/filetransfer_stream.h" + +namespace score +{ +namespace logging +{ +namespace dltserver +{ + +// implementation of the IOutput interface. +class Output : public FileTransferStreamHandler::IOutput +{ + public: + ~Output() = default; + void SendFtVerbose(score::cpp::span data, + mw::log::LogLevel loglevel, + DltidT app_id, + DltidT ctx_id, + uint8_t nor, + uint32_t time_tmsp) override + { + // The implementation for this method is not agreed currently. + // To be discussed: Ticket-211317 + std::ignore = data; + std::ignore = loglevel; + std::ignore = app_id; + std::ignore = ctx_id; + std::ignore = nor; + std::ignore = time_tmsp; + } + bool IsOutputEnabled() const noexcept override + { + return true; + } +}; + +/** + * @brief Concrete factory that creates FileTransferStreamHandler instances. + */ +class FileTransferStreamHandlerFactory : public FileTransferHandlerFactory +{ + public: + explicit FileTransferStreamHandlerFactory(Output& output) : output_(output) {} + + std::unique_ptr CreateConcreteHandler() + { + return std::make_unique(output_); + } + + private: + Output& output_; +}; + +} // namespace dltserver +} // namespace logging +} // namespace score + +#endif // PAS_LOGGING_FILE_TRANSFER_STREAM_HANDLER_FACTORY_H diff --git a/score/datarouter/src/file_transfer/file_transfer_impl/filetransfer_stream.cpp b/score/datarouter/src/file_transfer/file_transfer_impl/filetransfer_stream.cpp new file mode 100644 index 00000000..ac13771c --- /dev/null +++ b/score/datarouter/src/file_transfer/file_transfer_impl/filetransfer_stream.cpp @@ -0,0 +1,364 @@ +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "filetransfer_stream.h" +#include "dlt/dlt_headers.h" +#include "score/os/stat.h" +#include "score/os/stdio.h" +#include "score/os/utils/thread.h" +#include "score/mw/log/logging.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace score +{ +namespace logging +{ +namespace dltserver +{ + +FileTransferStreamHandler::FileTransferStreamHandler(IOutput& output) + : LogParser::TypeHandler(), exit_requested_{false}, serialno_(0), fsize_(0), packagecount_(0), output_(output) +{ + filetransfer_thread_ = score::cpp::jthread([this] { + this->ProcessFileTransfer(); + }); + score::os::set_thread_name(filetransfer_thread_, "file_transfer"); +} + +/* +Deviation from Rule A15-5-1: +- All user-provided class destructors, deallocation functions, move constructors, +- move assignment operators and swap functions shall not exit with an exception. +- A noexcept exception specification shall be added to these functions as appropriate. +Justification: +- Ensure that filetransfer_thread is not running after destruction of FileTransferStreamHandler +- checking filetransfer_thread.joinable() should be enough to avoid exception from join(). +- in this case join() could throw exception only if something goes wrong on OS level. +- this should be fine, moreover it could happen only on system shutdown stage +- and does not affect normal runtime +*/ +// coverity[autosar_cpp14_a15_5_1_violation] see above +FileTransferStreamHandler::~FileTransferStreamHandler() noexcept +{ + exit_requested_.store(true); + + if (filetransfer_thread_.joinable()) + { + filetransfer_thread_.join(); + } +} +// Suppress "AUTOSAR C++14 A3-1-1", the rule states: " It shall be possible to include any header file in multiple +// translation units without violating the One Definition Rule." +// False positive. Its defined in .cpp file and only declared in .h file +// coverity[autosar_cpp14_a3_1_1_violation : FALSE] +void FileTransferStreamHandler::Handle(TimestampT /* timestamp */, const char* data, BufsizeT size) +{ + if (!output_.IsOutputEnabled()) + { + return; + } + score::logging::FileTransferEntry entry{}; + using S = ::score::common::visitor::logging_serializer; + S::deserialize(data, size, entry); + std::unique_lock lock(filetransfer_mutex_); + container_.push(entry); + score::mw::log::LogInfo() << "Requested file transfer: " << entry.file_name << ", delete: " << entry.delete_file; +} + +void FileTransferStreamHandler::ProcessFileTransfer() +{ + auto read_from_queue = [this]() { + std::shared_lock lock(filetransfer_mutex_); + appid_ = container_.front().appid; + ctxid_ = container_.front().ctxid; + return container_.front().file_name; + }; + auto container_not_empty = [this]() { + std::shared_lock lock(filetransfer_mutex_); + return (!container_.empty()); + }; + while (!exit_requested_.load()) + { + if (container_not_empty()) + { + readfile_ = read_from_queue(); + if (LogFileHeader()) + { + LogFileData(); + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } +} + +bool FileTransferStreamHandler::ReadFileHeaderInfo(const std::string& filename) +{ + struct score::os::StatBuffer statbuf{}; + if (::score::os::Stat::instance().stat(filename.c_str(), statbuf).has_value()) + { + auto get_file_serial_number = [](struct score::os::StatBuffer st, const std::string& file) { + uint32_t hash = 0; + if (file.empty()) + { + // This check ensures robustness in GetFileSerialNumber, + // but it cannot be triggered in practice because it's only called + // after a successful stat() on a valid file. If stat() fails (e.g., empty path), + // the function exits early before reaching this point. + // LCOV_EXCL_START + return hash; + // LCOV_EXCL_STOP + } + hash = static_cast(st.st_ino); + hash = hash << (sizeof(hash) * 8U) / 2U; + hash |= static_cast(st.st_size); + hash ^= static_cast(st.ctime); + for (std::string::const_iterator it = file.cbegin(); it != file.cend(); ++it) + { + hash = 53 * hash + static_cast(*it); + } + return hash; + }; + + auto get_file_size = [](struct score::os::StatBuffer st) { + return static_cast(st.st_size); + }; + + auto get_file_creation_date = [](struct score::os::StatBuffer st) { + struct tm tm_buf{}; + struct tm* ts = localtime_r(&st.ctime, &tm_buf); + if (ts != nullptr) + { + std::ostringstream oss; + oss << std::put_time(ts, "%c"); + return oss.str(); + } + // This fallback path is only executed if `localtime_r` returns nullptr, + // which can only happen on internal runtime failure (e.g., invalid time data). + // However, since `localtime_r` is a C library function, it is not virtual and cannot be overridden + // directly. The project uses `std::localtime_r` (from ) instead of the Time wrapper interface + // (score::os::Time). As a result, Google Mock cannot intercept the call, and this branch cannot be covered in + // tests. To cover it, a redesign would be needed to wrap all system time calls through mockable interfaces. + // LCOV_EXCL_START + return std::string(""); + // LCOV_EXCL_STOP + }; + + auto getpackages_count = [](const std::string&, uint32_t fsize) { + uint32_t packages = 1U; + if (fsize < kBufferSize) + { + return packages; + } + else + { + packages = fsize / kBufferSize; + if (fsize % kBufferSize == 0) + { + return packages; + } + else + { + return packages + 1U; + } + } + }; + + serialno_ = get_file_serial_number(statbuf, filename); + fsize_ = get_file_size(statbuf); + creationdate_ = get_file_creation_date(statbuf); + packagecount_ = getpackages_count(filename, fsize_); + return true; + } + return false; +} + +score::cpp::span CastDataSpanToConst(score::cpp::span data) +{ + return score::cpp::span{ + /* + Deviation from Rule M5-2-8: + - Rule M5-2-8 (required, implementation, automated) + An object with integer type or pointer to void type shall not be converted + to an object with pointer type. + Justification: + - This is safe since we convert void data object to it's raw. + */ + // coverity[autosar_cpp14_m5_2_8_violation] + const_cast(static_cast(static_cast(data.data()))), + data.size()}; +} + +bool FileTransferStreamHandler::LogFileHeader() +{ + if (ReadFileHeaderInfo(readfile_) && !exit_requested_.load()) + { + std::array buffer{}; + auto data_span = score::cpp::span{buffer.data(), buffer.size()}; + const auto result = PackageFileHeader(data_span, serialno_, readfile_, fsize_, creationdate_, packagecount_); + if (result.has_value()) + { + TimestampT time_stamp = TimestampT::clock::now(); + uint32_t tmsp = std::chrono::duration_cast(time_stamp.time_since_epoch()).count(); + const auto& [data_output, number_of_args] = result.value(); + output_.SendFtVerbose( + CastDataSpanToConst(data_output), mw::log::LogLevel::kInfo, appid_, ctxid_, number_of_args, tmsp); + return true; + } + } + LogFileError(kDltFiletransferErrorFileHead); + return false; +} + +void FileTransferStreamHandler::LogFileData() +{ + FILE* file = nullptr; + auto ret_fopen = score::os::Stdio::instance().fopen(readfile_.c_str(), "rb"); + if (ret_fopen.has_value()) + { + file = ret_fopen.value(); + } + if (file != nullptr && !exit_requested_.load()) + { + std::array buffer{}; + for (uint32_t pkgno = 1U; pkgno <= packagecount_; pkgno++) + { + buffer.fill(0); + auto data_span = score::cpp::span{buffer.data(), buffer.size()}; + const auto result = PackageFileData(data_span, file, serialno_, pkgno); + if (not result.has_value()) + { + // This line is not covered because `PackageFileData` returns std::nullopt + // only when the provided buffer is too small. Since the production code + // uses a fixed-size buffer (`kDatapkgsize`) that is always large enough, + // this condition cannot be triggered as kDatapkgsize is hardcoded. + // LCOV_EXCL_START + score::os::Stdio::instance().fclose(file); + LogFileError(kDltFiletransferErrorFileData, "Unable to format data package"); + return; + // LCOV_EXCL_STOP + } + else + { + TimestampT time_stamp = TimestampT::clock::now(); + const auto& [data_packet, number_of_args] = result.value(); + uint32_t tmsp = std::chrono::duration_cast(time_stamp.time_since_epoch()).count(); + output_.SendFtVerbose( + CastDataSpanToConst(data_packet), mw::log::LogLevel::kInfo, appid_, ctxid_, number_of_args, tmsp); + } + } + score::os::Stdio::instance().fclose(file); + LogFileEnd(); + } + else + { + // This fallback is only triggered if `fopen` fails or `PackageFileData` returns std::nullopt. + // In production, a fixed-size buffer (`kDatapkgsize`) is always large enough for packaging, + // so `PackageFileData` will not fail under normal test conditions. + // Covering this would require artificial failure injection or a redesign for test hooks. + // LCOV_EXCL_START + LogFileError(kDltFiletransferErrorFileData); + // LCOV_EXCL_STOP + } +} + +void FileTransferStreamHandler::LogFileEnd() +{ + if (!exit_requested_.load()) + { + std::array buffer{}; + auto data_span = score::cpp::span{buffer.data(), buffer.size()}; + auto remove_from_file_queue = [this]() { + std::unique_lock lock(filetransfer_mutex_); + if (!container_.empty()) + { + if (0U != container_.front().delete_file) + { + std::remove(readfile_.c_str()); + } + container_.pop(); + } + else + { + // This error log is only triggered if LogFileEnd() is called when the container is already empty. + // Under normal usage (after a successful handle + transfer), the container is not empty- is not good. + // because it has dynamic content and could be empty (misuse or race conditions ). + // LCOV_EXCL_START + std::perror(" Cannot remove file from empty Container !!! "); + // LCOV_EXCL_STOP + } + }; + const auto result = PackageFileEnd(data_span, serialno_); + if (result.has_value()) + { + const auto [data_output, number_of_args] = result.value(); + TimestampT time_stamp = TimestampT::clock::now(); + uint32_t tmsp = std::chrono::duration_cast(time_stamp.time_since_epoch()).count(); + output_.SendFtVerbose( + CastDataSpanToConst(data_output), mw::log::LogLevel::kInfo, appid_, ctxid_, number_of_args, tmsp); + } + remove_from_file_queue(); + } +} + +void FileTransferStreamHandler::LogFileError(int16_t errorcode, std::string error_msg) +{ + if (!exit_requested_.load()) + { + std::array buffer{}; + buffer.fill(0); + auto remove_from_file_queue = [this]() { + std::unique_lock lock(filetransfer_mutex_); + if (!container_.empty()) + { + if (0U != container_.front().delete_file) + { + std::remove(readfile_.c_str()); + } + container_.pop(); + } + else + { + // This error log is only triggered if LogFileEnd() is called when the container is already empty. + // Under normal usage (after a successful handle + transfer), the container is not empty- is not good. + // because it has dynamic content and could be empty (misuse or race conditions ). + // condition, which should not happen by design. + // LCOV_EXCL_START + std::perror(" Cannot remove file from empty Container !!! "); + // LCOV_EXCL_STOP + } + }; + auto data_span = score::cpp::span{buffer.data(), buffer.size()}; + const auto result = PackageFileError( + data_span, errorcode, serialno_, readfile_, fsize_, creationdate_, packagecount_, error_msg); + if (result.has_value()) + { + TimestampT time_stamp = TimestampT::clock::now(); + uint32_t tmsp = std::chrono::duration_cast(time_stamp.time_since_epoch()).count(); + const auto& [data_output, number_of_args] = result.value(); + output_.SendFtVerbose( + CastDataSpanToConst(data_output), mw::log::LogLevel::kError, appid_, ctxid_, number_of_args, tmsp); + } + remove_from_file_queue(); + } +} + +} // namespace dltserver +} // namespace logging +} // namespace score diff --git a/score/datarouter/src/file_transfer/file_transfer_impl/filetransfer_stream.h b/score/datarouter/src/file_transfer/file_transfer_impl/filetransfer_stream.h new file mode 100644 index 00000000..c4598808 --- /dev/null +++ b/score/datarouter/src/file_transfer/file_transfer_impl/filetransfer_stream.h @@ -0,0 +1,83 @@ +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_DATAROUTER_SRC_FILE_TRANSFER_FILE_TRANSFER_IMPL_FILETRANSFER_STREAM_H +#define SCORE_DATAROUTER_SRC_FILE_TRANSFER_FILE_TRANSFER_IMPL_FILETRANSFER_STREAM_H + +#include "daemon/dltserver_common.h" +#include "daemon/udp_stream_output.h" +#include "logparser/logparser.h" + +#include "score/mw/log/log_level.h" +#include "score/datarouter/dlt_filetransfer_trigger_lib/filetransfer_message_trace.h" + +#include + +#include +#include +#include +#include + +using namespace score::platform::internal; + +namespace score +{ +namespace logging +{ +namespace dltserver +{ + +class FileTransferStreamHandler : public LogParser::TypeHandler +{ + public: + class IOutput + { + public: + virtual void SendFtVerbose(score::cpp::span data, + mw::log::LogLevel loglevel, + DltidT app_id, + DltidT ctx_id, + uint8_t nor, + uint32_t time_tmsp) = 0; + virtual bool IsOutputEnabled() const noexcept = 0; + + virtual ~IOutput() = default; + }; + explicit FileTransferStreamHandler(IOutput& output); + ~FileTransferStreamHandler() noexcept; + virtual void Handle(TimestampT timestamp, const char* data, BufsizeT size) override; + + private: + using DltDurationT = std::chrono::duration>; + void ProcessFileTransfer(); + bool ReadFileHeaderInfo(const std::string& filename); + bool LogFileHeader(); + void LogFileData(); + void LogFileEnd(); + void LogFileError(int16_t errorcode, std::string error_msg = ""); + score::cpp::jthread filetransfer_thread_; + std::atomic_bool exit_requested_; + std::shared_timed_mutex filetransfer_mutex_; + std::queue<::score::logging::FileTransferEntry> container_; + std::string readfile_, creationdate_; + DltidT appid_; + DltidT ctxid_; + std::uint32_t serialno_, fsize_, packagecount_; + IOutput& output_; +}; + +} // namespace dltserver +} // namespace logging +} // namespace score + +#endif // SCORE_DATAROUTER_SRC_FILE_TRANSFER_FILE_TRANSFER_IMPL_FILETRANSFER_STREAM_H From 1cfa72c77bfcb7d00782dcf60b1c9e9da2644cbb Mon Sep 17 00:00:00 2001 From: vaishnavi yendole Date: Tue, 28 Jul 2026 15:43:13 +0530 Subject: [PATCH 2/2] fix(datarouter): Add missing logging.h include for file_transfer feature When file_transfer=True, the datarouter_feature_config.h includes filetransfer_stream.h which only has log_level.h. This was missing the LogError and LogInfo declarations that dlt_log_server.cpp uses. When file_transfer=False, the stub header provided logging.h transitively, masking the missing include. This fix adds a direct include of score/mw/log/logging.h to make the source file self-sufficient regardless of feature flag state. Tested with file_transfer=True/False and enable_dynamic_configuration=True/False. --- score/datarouter/src/daemon/dlt_log_server.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/score/datarouter/src/daemon/dlt_log_server.cpp b/score/datarouter/src/daemon/dlt_log_server.cpp index 8d3145da..05acf9a9 100644 --- a/score/datarouter/src/daemon/dlt_log_server.cpp +++ b/score/datarouter/src/daemon/dlt_log_server.cpp @@ -16,6 +16,7 @@ #include "score/datarouter/include/daemon/configurator_commands.h" #include "score/datarouter/include/daemon/diagnostic_job_parser.h" #include "score/datarouter/include/daemon/i_diagnostic_job_handler.h" +#include "score/mw/log/logging.h" #include #include