Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions score/datarouter/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ cc_library(
":unixdomain_common",
"//score/datarouter/src/configuration/dynamic_config:i_session",
"@score_baselibs//score/os:pthread",
"@score_baselibs//score/os:stat",
"@score_baselibs//score/os:sys_poll",
"@score_baselibs//score/quality/compiler_warnings",
],
Expand All @@ -138,6 +139,7 @@ cc_library(
":unixdomain_client",
"//score/datarouter/src/configuration/dynamic_config:i_session",
"@score_baselibs//score/os:pthread",
"@score_baselibs//score/os:stat",
"@score_baselibs//score/os:sys_poll",
"@score_baselibs//score/quality/compiler_warnings",
],
Expand Down Expand Up @@ -647,6 +649,23 @@ cc_library(
]
]

cc_library(
name = "socket_config",
srcs = ["src/daemon/socket_config.cpp"],
hdrs = ["include/daemon/socket_config.h"],
features = COMPILER_WARNING_FEATURES,
strip_include_prefix = "include",
visibility = [
"//score/datarouter:__subpackages__",
"//score/mw/log/detail/data_router:__subpackages__",
],
deps = [
":unixdomain_common",
"@score_baselibs//score/language/futurecpp",
"@score_baselibs//score/os:stdlib",
],
)

cc_library(
name = "socketserver_config_helpers",
hdrs = [
Expand Down Expand Up @@ -762,6 +781,7 @@ cc_library(
":datarouter_lib",
":dltserver",
":persistentlogconfig",
":socket_config",
":socketserver_config_lib",
"@score_baselibs//score/concurrency:thread_pool",
"@score_baselibs//score/mw/log/configuration:nvconfigfactory",
Expand Down Expand Up @@ -792,6 +812,7 @@ cc_library(
":datarouter_testing",
":dltserver_testing",
":persistentlogconfig",
":socket_config",
":socketserver_config_lib_testing",
"@score_baselibs//score/concurrency:thread_pool",
"@score_baselibs//score/mw/log/configuration:nvconfigfactory",
Expand Down
1 change: 0 additions & 1 deletion score/datarouter/include/daemon/data_router_cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ namespace logging
{
namespace config
{
static const std::string kSocketAddress{"datarouter_socket"};
static constexpr const score::cpp::string_view kDltConfigClientName{"_dlt_config"};
} // namespace config
} // namespace logging
Expand Down
55 changes: 55 additions & 0 deletions score/datarouter/include/daemon/socket_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/********************************************************************************
* 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_DAEMON_SOCKET_CONFIG_H
#define SCORE_DATAROUTER_DAEMON_SOCKET_CONFIG_H

#include "score/os/stdlib.h"

#include <string>

namespace score {
namespace platform {
namespace internal {
class UnixDomainSockAddr;
}
} // namespace platform
} // namespace score

namespace score {
namespace logging {
namespace config {

/// \brief Socket configuration resolved from environment variables or defaults
struct SocketConfiguration {
std::string path;
bool is_abstract;
};

/// \brief Get socket configuration from environment variables or platform defaults
/// \param stdlib OS abstraction for environment variable access
/// \return Socket configuration with path and abstract mode flag
/// \note Reads DATAROUTER_SOCKET_PATH and DATAROUTER_SOCKET_MODE environment variables
/// \note Platform defaults: Linux uses abstract namespace, QNX uses file-based
SocketConfiguration GetSocketConfiguration(const score::os::Stdlib& stdlib) noexcept;

/// \brief Create configured UnixDomainSockAddr from environment or defaults
/// \param stdlib OS abstraction for environment variable access
/// \return Configured socket address ready for binding or connecting
score::platform::internal::UnixDomainSockAddr CreateSocketAddress(const score::os::Stdlib& stdlib) noexcept;

} // namespace config
} // namespace logging
} // namespace score

#endif // SCORE_DATAROUTER_DAEMON_SOCKET_CONFIG_H
3 changes: 3 additions & 0 deletions score/datarouter/include/unix_domain/unix_domain_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ struct SocketMessangerHeader // __attribute__((packed)) // TODO: deal with p
class UnixDomainSockAddr
{
public:
static constexpr std::size_t kMaxPathLength = sizeof(sockaddr_un::sun_path) - 1U;
static constexpr std::size_t kMaxAbstractPathLength = sizeof(sockaddr_un::sun_path) - 2U;

UnixDomainSockAddr(const std::string& path, bool is_abstract);
const char* GetAddressString()
{
Expand Down
89 changes: 89 additions & 0 deletions score/datarouter/src/daemon/socket_config.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/********************************************************************************
* 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 "daemon/socket_config.h"

#include "unix_domain/unix_domain_common.h"
#include <iostream>

namespace score {
namespace logging {
namespace config {

namespace {
constexpr char kEnvSocketPath[] = "DATAROUTER_SOCKET_PATH";
constexpr char kEnvSocketMode[] = "DATAROUTER_SOCKET_MODE";

#if defined(__QNX__)
constexpr char kDefaultSocketPath[] = "/var/run/datarouter.sock";
constexpr char kDefaultSocketMode[] = "file";
#else
constexpr char kDefaultSocketPath[] = "datarouter_socket";
constexpr char kDefaultSocketMode[] = "abstract";
#endif

} // namespace

SocketConfiguration GetSocketConfiguration(const score::os::Stdlib& stdlib) noexcept
{
const char* env_path = stdlib.getenv(kEnvSocketPath);
const char* env_mode = stdlib.getenv(kEnvSocketMode);

std::string path;
if (env_path != nullptr && env_path[0] != '\0')
{
path = env_path;
}
else
{
path = kDefaultSocketPath;
}

std::string mode_str;
if (env_mode != nullptr)
{
mode_str = env_mode;
}
else
{
mode_str = kDefaultSocketMode;
}

bool is_abstract = true;
if (mode_str == "file" || mode_str == "FILE")
{
is_abstract = false;
}

const std::size_t max_len = is_abstract
? score::platform::internal::UnixDomainSockAddr::kMaxAbstractPathLength
: score::platform::internal::UnixDomainSockAddr::kMaxPathLength;
if (path.length() > max_len)
{
std::cerr << "Warning: DATAROUTER_SOCKET_PATH too long (max " << max_len
<< " chars), using default: " << kDefaultSocketPath << '\n';
path = kDefaultSocketPath;
}

return SocketConfiguration{path, is_abstract};
}

score::platform::internal::UnixDomainSockAddr CreateSocketAddress(const score::os::Stdlib& stdlib) noexcept
{
auto config = GetSocketConfiguration(stdlib);
return score::platform::internal::UnixDomainSockAddr(config.path, config.is_abstract);
}

} // namespace config
} // namespace logging
} // namespace score
7 changes: 3 additions & 4 deletions score/datarouter/src/daemon/socketserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "daemon/dlt_log_server.h"
#include "daemon/message_passing_server.h"
#include "daemon/socket_config.h"
#include "daemon/socketserver_config.h"
#include "logparser/logparser.h"

Expand All @@ -31,9 +32,6 @@
#include "score/mw/log/configuration/nvconfigfactory.h"
#include "score/concurrency/thread_pool.h"

// Constants
#include "data_router_cfg.h"

#include <score/math.hpp>
#include <functional>
#include <iostream>
Expand Down Expand Up @@ -243,7 +241,8 @@ std::unique_ptr<score::platform::internal::UnixDomainServer> SocketServer::Creat
return SocketServer::CreateConfigSession(dlt_server, std::move(handle));
};

const UnixDomainSockAddr addr(score::logging::config::kSocketAddress, true);
const auto stdlib = score::os::Stdlib::Default();
const UnixDomainSockAddr addr = score::logging::config::CreateSocketAddress(*stdlib);
/*
Deviation from Rule A5-1-4:
- A lambda expression object shall not outlive any of its reference captured objects.
Expand Down
33 changes: 29 additions & 4 deletions score/datarouter/src/unix_domain/unix_domain_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "score/os/pthread.h"

#include "score/os/socket.h"
#include "score/os/stat.h"
#include "score/os/sys_poll.h"
#include "score/os/unistd.h"
#include "score/os/utils/signal_impl.h"
Expand Down Expand Up @@ -172,13 +173,27 @@ void UnixDomainServer::ServerRoutine(UnixDomainSockAddr addr)

std::int32_t UnixDomainServer::SetupServerSocket(UnixDomainSockAddr& addr)
{
const auto stat_instance = score::os::Stat::Default();
const auto unistd_instance = score::os::Unistd::Default();
if (!addr.IsAbstract())
{
const auto unlink_ret = score::os::Unistd::instance().unlink(static_cast<const char*>(addr.addr.sun_path));
if (!unlink_ret.has_value())
const char* path = static_cast<const char*>(addr.addr.sun_path);
score::os::StatBuffer st{};
if (stat_instance->stat(path, st).has_value())
{
std::perror("unlink");
std::fprintf(stderr, "address: %s\n", static_cast<const char*>(addr.addr.sun_path));
// NOLINTNEXTLINE(hicpp-signed-bitwise) S_ISSOCK is a POSIX macro
if (!S_ISSOCK(st.st_mode))
{
std::fprintf(stderr, "Error: %s exists but is not a socket, refusing to unlink\n", path);
// NOLINTNEXTLINE(score-banned-function): Suppressed here because of error handling
std::exit(EXIT_FAILURE);
}
const auto unlink_ret = unistd_instance->unlink(path);
if (!unlink_ret.has_value())
{
std::perror("unlink");
std::fprintf(stderr, "address: %s\n", path);
}
}
}
const auto socket_ret = score::os::Socket::instance().socket(score::os::Socket::Domain::kUnix, SOCK_STREAM, 0);
Expand Down Expand Up @@ -209,6 +224,16 @@ std::int32_t UnixDomainServer::SetupServerSocket(UnixDomainSockAddr& addr)
// NOLINTNEXTLINE(score-banned-function): Suppressed here because of error handling
std::exit(EXIT_FAILURE);
}
if (!addr.IsAbstract())
{
using Mode = score::os::Stat::Mode;
// Connecting requires write permission; group write supports non-root clients sharing the socket's GID.
constexpr auto kSocketPerms = Mode::kReadUser | Mode::kWriteUser | Mode::kReadGroup | Mode::kWriteGroup;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should the group have write permissions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-root clients sharing the socket GID would need write permission to connect. Do you want me to drop it?

if (!stat_instance->chmod(static_cast<const char*>(addr.addr.sun_path), kSocketPerms).has_value())
{
std::perror("chmod socket");
}
}
// Suppressed here as it is safely used, and it is among safety headers.
// NOLINTNEXTLINE(score-banned-function) see comment above
const auto listen_ret = score::os::Socket::instance().listen(server_fd, 20);
Expand Down
38 changes: 38 additions & 0 deletions score/datarouter/test/ut/ut_logging/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ test_suite(
":logparserUT",
":messagePassingServerUT",
":persistentLogConfigUT",
":socket_config_test",
":socketserverConfigUT",
":socketserverUT",
":udp_stream_output_test",
":unix_domain_common_test",
":unix_domain_server_file_socket_integration_test",
":unix_domain_server_test",
":utility_test",
],
Expand Down Expand Up @@ -287,6 +289,20 @@ cc_test(
],
)

cc_test(
name = "socket_config_test",
srcs = [
"socket_config_test.cpp",
],
features = FEAT_COMPILER_WARNINGS_AS_ERRORS,
tags = ["unit"],
deps = [
"@googletest//:gtest_main",
"@score_baselibs//score/os/mocklib:stdlib_mock",
"@score_logging//score/datarouter:socket_config",
],
)

cc_test(
name = "socketserverUT",
srcs = [
Expand Down Expand Up @@ -338,6 +354,28 @@ cc_test(
],
)

cc_test(
name = "unix_domain_server_file_socket_integration_test",
srcs = [
"unix_domain_server_file_socket_integration_test.cpp",
],
features = FEAT_COMPILER_WARNINGS_AS_ERRORS,
tags = [
"integration",
"unit",
],
deps = [
"@googletest//:gtest",
"@googletest//:gtest_main",
"@score_baselibs//score/os/mocklib:stdlib_mock",
"@score_baselibs//score/os:socket",
"@score_baselibs//score/os:stat",
"@score_baselibs//score/os:unistd",
"@score_logging//score/datarouter:socket_config",
"@score_logging//score/datarouter:unixdomain_server",
],
)

cc_test(
name = "unix_domain_server_test",
srcs = [
Expand Down
Loading
Loading