connection between 2 systems and bug fixes (#14)

This commit is contained in:
tompzf
2026-07-03 14:53:48 +02:00
committed by GitHub
parent 0fb5660d27
commit 46842200f1
284 changed files with 35200 additions and 8265 deletions

View File

@@ -60,12 +60,22 @@ MAKE_ERROR_MSG(-134, CONFIG_SERVICE_ACCESS_ERROR, "Configuration service is not
MAKE_ERROR_MSG(-135, COMMUNICATION_CONTROL_SERVICE_ACCESS_ERROR, "Communication control service is not accessible.", "The communication control service service could not be accessed.")
MAKE_ERROR_MSG(-136, APP_CONTROL_SERVICE_ACCESS_ERROR, "Application control service is not accessible.", "The application control service could not be accessed.")
MAKE_ERROR_MSG(-170, CANNOT_FIND_OBJECT, "The object cannot be found.", "A search for an object with supplied name was not successful.")
MAKE_ERROR_MSG(-180, CANNOT_LOAD_SETTINGS, "The system settings cannot be loaded.", "For a specific instance, the system settings cannot be loaded.")
MAKE_ERROR_MSG(-180, CANNOT_SAVE_SETTINGS, "The system settings cannot be saved.", "For a specific instance, the system settings cannot be saved.")
MAKE_ERROR_MSG(-181, PROCESS_LISTENER_CONFIG_ERROR, "The listener configuration contains errors.", "The listener configuration contains errors and cannot be processed.")
MAKE_ERROR_MSG(-182, PROCESS_CONNECTION_CONFIG_ERROR, "The connection configuration contains errors.", "The connection configuration contains errors and cannot be processed.")
MAKE_ERROR_MSG(-183, ADD_LISTENER_ERROR, "Failed to add a listener to the system settings.", "The listener configuration could not be added to the system settings. This might be caused by a duplicate listener configuration.")
MAKE_ERROR_MSG(-184, REMOVE_LISTENER_ERROR, "Failed to remove a listener from the system settings.", "The listener configuration could not be removed from the system settings. This might be caused by a missing listener configuration.")
MAKE_ERROR_MSG(-185, SHOW_LISTENER_ERROR, "Failed to request the listener configuration from the system settings.", "The listener configuration could not be requested. This might be caused by a missing listener configuration.")
MAKE_ERROR_MSG(-186, ADD_CONNECTION_ERROR, "Failed to add a connection to the system settings.", "The connection configuration could not be added to the system settings. This might be caused by a duplicate connection configuration.")
MAKE_ERROR_MSG(-187, REMOVE_CONNECTION_ERROR, "Failed to remove a connection from the system settings.", "The connection configuration could not be removed from the system settings. This might be caused by a missing connection configuration.")
MAKE_ERROR_MSG(-188, SHOW_CONNECTION_ERROR, "Failed to request the connection configuration from the system settings.", "The connection configuration could not be requested. This might be caused by a missing connection configuration.")
////////// LOCAL APP CONTROL ERROR CODES ////////////
MAKE_ERROR_MSG(-204, APP_CONTROL_STARTUP_ERROR, "Cannot start application control.", "Application control start was initiated, but returned an error.")
MAKE_ERROR_MSG(-205, APP_CONTROL_START_LOOP_FAIELD, "Starting the running loop failed.", "Failed to enter the processing loop for a server application.")
MAKE_ERROR_MSG(-205, APP_CONTROL_START_LOOP_FAILED, "Starting the running loop failed.", "Failed to enter the processing loop for a server application.")
MAKE_ERROR_MSG(-206, APP_CONTROL_DUPLICATE_INSTANCE, "Another process with specified instance is already running.", "Another core process initiated the application control with the same instance. Only one core process per instance is allowed.")
MAKE_ERROR_MSG(-210, APP_CONTROL_INVALID_ISOLATION_CONFIG, "An invalid isolation configuration was supplied.", "The application control configuration section contains an invalid isolation configuration.")
MAKE_ERROR_MSG(-218, SETTING_FILE_VERSION_INVALID, "Settings file has an invalid version.", "Settings file contains an invalid/incompatible version number.")

View File

@@ -25,7 +25,7 @@ add_executable(sdv_control
"startup_shutdown.h"
"startup_shutdown.cpp"
"context.h"
"print_table.h" "start_stop_service.cpp" "start_stop_service.h" "installation.h" "installation.cpp")
"print_table.h" "start_stop_service.cpp" "start_stop_service.h" "installation.h" "installation.cpp" "connection_config.h" "connection_config.cpp")
target_link_libraries(sdv_control ${CMAKE_DL_LIBS})

View File

@@ -0,0 +1,471 @@
/********************************************************************************
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
*
* 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
*
* Contributors:
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#include "connection_config.h"
#include "../../global/cmdlnparser/cmdlnparser.h"
#include <support/toml.h>
#include <interfaces/app.h>
#include "../error_msg.h"
#include <charconv>
void ListenerHelp(const SContext& rsContext)
{
// First argument should be "LISTENER"
if (rsContext.seqCmdLine.size() < 1)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: missing listener command..." << std::endl;
return;
}
if (iequals(rsContext.seqCmdLine[0], "LISTENER"))
{
CCommandLine::PrintHelpText(std::cout,
"Usage: sdv_control LISTENER ADD <name> <provider> <parameters...> [options...]\n"
" sdv_control LISTENER REMOVE <name> [options...]\n"
" sdv_control LISTENER SHOW <name> [options...]\n\n"
"Configure the system to add (or update) or remove a listener. The command doesn't check for valid parameters. A "
"server restart is required for the new listener settings to take effect.\n\n"
"A list of actively configured listeners can be requested by executing \"sdv_control LIST LISTENERS\"\n\n"
"Note: if not explicitly added, a default listener will added to the list for the communication between isolated "
"applications and the core system.\n\n");
return;
}
if (!rsContext.bSilent)
std::cerr << "ERROR: invalid listener command..." << std::endl;
}
void ConnectionHelp(const SContext& rsContext)
{
// First argument should be "CONNECTION"
if (rsContext.seqCmdLine.size() < 1)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: missing connection command..." << std::endl;
return;
}
if (iequals(rsContext.seqCmdLine[0], "CONNECTION"))
{
CCommandLine::PrintHelpText(std::cout,
"Usage: sdv_control CONNECTION ADD <name> <provider> <parameters...> [options...]\n"
" sdv_control CONNECTION REMOVE <name> [options...]\n"
" sdv_control CONNECTION SHOW <name> [options...]\n\n"
"Configure the system to add (or update) or remove a connection. The command doesn't check for valid parameters. A "
"server restart is required for the new connection settings to take effect.\n\n"
"A list of actively configured connections can be requested by executing \"sdv_control LIST CONNECTIONS\"\n\n"
"Note: if not explicitly added, a default connetion will be added to the list for the communication between external "
"applications and the core system.\n\n"
"Options:\n"
" --insert_before<string> With ADD, Insert the connection before an existing connection with the supplied name.\n\n");
return;
}
if (!rsContext.bSilent)
std::cerr << "ERROR: invalid connection command..." << std::endl;
}
int ConfigureListener(const SContext& rsContext)
{
// First argument should be "CONNECTION"
if (rsContext.seqCmdLine.size() < 2)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listener command... " << std::endl;
return CMDLN_ARG_ERR;
}
if (!iequals(rsContext.seqCmdLine[0], "LISTENER"))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command: " << rsContext.seqCmdLine[0] << std::endl;
return CMDLN_ARG_ERR;
}
// Which list command is requested
enum class ECommand { unknown, add, remove, show } eCommand = ECommand::unknown;
if (iequals(rsContext.seqCmdLine[1], "ADD")) eCommand = ECommand::add;
else if (iequals(rsContext.seqCmdLine[1], "REMOVE")) eCommand = ECommand::remove;
else if (iequals(rsContext.seqCmdLine[1], "SHOW")) eCommand = ECommand::show;
else
{
if (!rsContext.bSilent)
{
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid listener command." << std::endl;
ListenerHelp(rsContext);
}
return CMDLN_ARG_ERR;
}
if (rsContext.seqCmdLine.size() < 3)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listener name... " << std::endl;
return CMDLN_ARG_ERR;
}
// Get the name
std::string ssListener = rsContext.seqCmdLine[2];
switch (eCommand)
{
case ECommand::remove:
return RemoveListener(ssListener, rsContext);
case ECommand::show:
return ShowListenerConfig(ssListener, rsContext);
case ECommand::add:
default:
break;
}
// For add, check for provider and parameters
if (rsContext.seqCmdLine.size() < 4)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listener provider... " << std::endl;
return CMDLN_ARG_ERR;
}
std::string ssProvider = rsContext.seqCmdLine[3];
sdv::toml::CTOMLParser parser;
parser.AddValue("Provider.Name", ssProvider);
// Check for parameters
// Parameters have the format "param=value". It is possible that parameters have additional sub-tables. Then the format is:
// "table.param=value".
sdv::toml::CNodeCollection ipc_channel_table = parser.AddTable("IpcChannel");
for (size_t nIndex = 4; nIndex < rsContext.seqCmdLine.size(); nIndex++)
{
std::string ssRawParam = rsContext.seqCmdLine[nIndex];
// Search for the equal sign
size_t nEqualPos = ssRawParam.find_first_of('=');
std::string ssParamName = ssRawParam.substr(0, nEqualPos);
while (!ssParamName.empty() && std::isspace(ssParamName.back()))
ssParamName.pop_back();
if (ssParamName.empty() || nEqualPos == std::string::npos)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid listener parameter: " << ssRawParam << std::endl;
return CMDLN_ARG_ERR;
}
sdv::any_t anyValue;
size_t nValuePos = nEqualPos + 1;
while (nValuePos < ssRawParam.size() && std::isspace(ssRawParam[nValuePos]))
nValuePos++;
if (nValuePos < ssRawParam.size())
{
std::string ssValue = ssRawParam.substr(nValuePos);
if (!ssValue.empty() && ssValue.find_first_not_of("-0123456789") == std::string::npos)
{
int64_t iValue = 0;
if (std::from_chars(ssValue.data(), ssValue.data() + ssValue.size(), iValue).ec == std::errc())
anyValue = iValue;
else
anyValue = ssValue;
}
else
anyValue = ssValue;
}
ipc_channel_table.AddValue(ssParamName, anyValue);
}
return AddListener(ssListener, parser.GetTOML(), rsContext);
}
int AddListener(const std::string& rssListener, const std::string& rssConfig, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Add the listener
if (!pAppConnections->AddListenerConfig(rssListener, rssConfig))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << ADD_LISTENER_ERROR_MSG << std::endl;
return ADD_LISTENER_ERROR;
}
// Save the settings.
if (!pAppSettingsPersist->SaveSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_SAVE_SETTINGS_MSG << std::endl;
return CANNOT_SAVE_SETTINGS;
}
return NO_ERROR;
}
int RemoveListener(const std::string& rssListener, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Remove the listener
if (!pAppConnections->RemoveListenerConfig(rssListener))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << REMOVE_LISTENER_ERROR_MSG << std::endl;
return REMOVE_LISTENER_ERROR;
}
// Save the settings.
if (!pAppSettingsPersist->SaveSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_SAVE_SETTINGS_MSG << std::endl;
return CANNOT_SAVE_SETTINGS;
}
return NO_ERROR;
}
int ShowListenerConfig(const std::string& rssListener, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Remove the listener
std::string ssConfig = pAppConnections->GetListenerConfig(rssListener);
if (ssConfig.empty())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << SHOW_LISTENER_ERROR_MSG << std::endl;
return SHOW_LISTENER_ERROR;
}
std::cout << ssConfig << std::endl;
return NO_ERROR;
}
int ConfigureConnection(const SContext& rsContext)
{
// First argument should be "CONNECTION"
if (rsContext.seqCmdLine.size() < 2)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing connection command... " << std::endl;
return CMDLN_ARG_ERR;
}
if (!iequals(rsContext.seqCmdLine[0], "CONNECTION"))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command: " << rsContext.seqCmdLine[0] << std::endl;
return CMDLN_ARG_ERR;
}
// Which list command is requested
enum class ECommand { unknown, add, remove, show } eCommand = ECommand::unknown;
if (iequals(rsContext.seqCmdLine[1], "ADD")) eCommand = ECommand::add;
else if (iequals(rsContext.seqCmdLine[1], "REMOVE")) eCommand = ECommand::remove;
else if (iequals(rsContext.seqCmdLine[1], "SHOW")) eCommand = ECommand::show;
else
{
if (!rsContext.bSilent)
{
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid connection command." << std::endl;
ConnectionHelp(rsContext);
}
return CMDLN_ARG_ERR;
}
if (rsContext.seqCmdLine.size() < 3)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing connection name... " << std::endl;
return CMDLN_ARG_ERR;
}
// Get the name
std::string ssConnection = rsContext.seqCmdLine[2];
switch (eCommand)
{
case ECommand::remove:
return RemoveConnection(ssConnection, rsContext);
case ECommand::show:
return ShowConnectionConfig(ssConnection, rsContext);
case ECommand::add:
default:
break;
}
// For add, check for provider and parameters
if (rsContext.seqCmdLine.size() < 4)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing connection provider... " << std::endl;
return CMDLN_ARG_ERR;
}
std::string ssProvider = rsContext.seqCmdLine[3];
sdv::toml::CTOMLParser parser;
parser.AddValue("Provider.Name", ssProvider);
// Check for parameters
// Parameters have the format "param=value". It is possible that parameters have additional sub-tables. Then the format is:
// "table.param=value".
sdv::toml::CNodeCollection ipc_channel_table = parser.AddTable("IpcChannel");
for (size_t nIndex = 4; nIndex < rsContext.seqCmdLine.size(); nIndex++)
{
std::string ssRawParam = rsContext.seqCmdLine[nIndex];
// Search for the equal sign
size_t nEqualPos = ssRawParam.find_first_of('=');
std::string ssParamName = ssRawParam.substr(0, nEqualPos);
while (!ssParamName.empty() && std::isspace(ssParamName.back()))
ssParamName.pop_back();
if (ssParamName.empty() || nEqualPos == std::string::npos)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid listener parameter: " << ssRawParam << std::endl;
return CMDLN_ARG_ERR;
}
sdv::any_t anyValue;
size_t nValuePos = nEqualPos + 1;
while (nValuePos < ssRawParam.size() && std::isspace(ssRawParam[nValuePos]))
nValuePos++;
if (nValuePos < ssRawParam.size())
{
std::string ssValue = ssRawParam.substr(nValuePos);
if (!ssValue.empty() && ssValue.find_first_not_of("-0123456789") == std::string::npos)
{
int64_t iValue = 0;
if (std::from_chars(ssValue.data(), ssValue.data() + ssValue.size(), iValue).ec == std::errc())
anyValue = iValue;
else
anyValue = ssValue;
}
else
anyValue = ssValue;
}
ipc_channel_table.AddValue(ssParamName, anyValue);
}
return AddConnection(ssConnection, parser.GetTOML(), rsContext);
}
int AddConnection(const std::string& rssConnection, const std::string& rssConfig, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Add the connection
if (!pAppConnections->AddConnectionConfig(rssConnection, rssConfig, rsContext.ssInsertBeforeConnection))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << ADD_CONNECTION_ERROR_MSG << std::endl;
return ADD_CONNECTION_ERROR;
}
// Save the settings.
if (!pAppSettingsPersist->SaveSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_SAVE_SETTINGS_MSG << std::endl;
return CANNOT_SAVE_SETTINGS;
}
return NO_ERROR;
}
int RemoveConnection(const std::string& rssConnection, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Remove the connection
if (!pAppConnections->RemoveConnectionConfig(rssConnection))
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << REMOVE_CONNECTION_ERROR_MSG << std::endl;
return REMOVE_CONNECTION_ERROR;
}
// Save the settings.
if (!pAppSettingsPersist->SaveSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_SAVE_SETTINGS_MSG << std::endl;
return CANNOT_SAVE_SETTINGS;
}
return NO_ERROR;
}
int ShowConnectionConfig(const std::string& rssConnection, const SContext& rsContext)
{
// Load the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
// Remove the connection
std::string ssConfig = pAppConnections->GetConnectionConfig(rssConnection);
if (ssConfig.empty())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << SHOW_CONNECTION_ERROR_MSG << std::endl;
return SHOW_CONNECTION_ERROR;
}
std::cout << ssConfig << std::endl;
return NO_ERROR;
}

View File

@@ -0,0 +1,98 @@
/********************************************************************************
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
*
* 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
*
* Contributors:
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#ifndef CONNECTION_CONFIG_H
#define CONNECTION_CONFIG_H
#include "context.h"
#include <support/sequence.h>
#include <support/string.h>
/**
* @brief Help for configuring listeners.
* @param[in] rsContext Reference to the context.
*/
void ListenerHelp(const SContext& rsContext);
/**
* @brief Help for configuring connections.
* @param[in] rsContext Reference to the context.
*/
void ConnectionHelp(const SContext& rsContext);
/**
* @brief Configure the listener.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int ConfigureListener(const SContext& rsContext);
/**
* @brief Add a listener to the system settings.
* @param[in] rssListener Reference to the string containing the listener configuration name.
* @param[in] rssConfig Reference to the string containing the listener configuration.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int AddListener(const std::string& rssListener, const std::string& rssConfig, const SContext& rsContext);
/**
* @brief Remove a listener from the system settings.
* @param[in] rssListener Reference to the string containing the listener configuration name.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int RemoveListener(const std::string& rssListener, const SContext& rsContext);
/**
* @brief Show a listener configuration.
* @param[in] rssListener Reference to the string containing the listener configuration name.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int ShowListenerConfig(const std::string& rssListener, const SContext& rsContext);
/**
* @brief Configure the connection.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int ConfigureConnection(const SContext& rsContext);
/**
* @brief Add a connection to the system settings.
* @param[in] rssConnection Reference to the string containing the connection configuration name.
* @param[in] rssConfig Reference to the string containing the connection configuration.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int AddConnection(const std::string& rssConnection, const std::string& rssConfig, const SContext& rsContext);
/**
* @brief Remove a connection from the system settings.
* @param[in] rssConnection Reference to the string containing the connection configuration name.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int RemoveConnection(const std::string& rssConnection, const SContext& rsContext);
/**
* @brief Show a connection configuration.
* @param[in] rssConnection Reference to the string containing the connection configuration name.
* @param[in] rsContext Reference to the context.
* @return The application exit code. 0 is no error.
*/
int ShowConnectionConfig(const std::string& rssConnection, const SContext& rsContext);
#endif // !defined CONNECTION_CONFIG_H

View File

@@ -33,6 +33,7 @@ struct SContext
bool bListShort = false; ///< Print only a shortened list with one column.
sdv::sequence<sdv::u8string> seqCmdLine; ///< The commands provided on the command line.
std::filesystem::path pathInstallDir; ///< Optional installation directory.
std::string ssInsertBeforeConnection; ///< Insert before the provided connection
};
#include <cctype> // std::tolower

View File

@@ -88,7 +88,7 @@ int Install(const SContext& rsContext)
ssName = rsContext.seqCmdLine[1];
// Try to connect
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)

View File

@@ -14,8 +14,10 @@
#include "list_elements.h"
#include "print_table.h"
#include <interfaces/config.h>
#include <interfaces/app.h>
#include <support/sdv_core.h>
#include <support/local_service_access.h>
#include <support/toml.h>
#include "../../global/cmdlnparser/cmdlnparser.h"
#include "../../global/exec_dir_helper.h"
#include "../../global/flags.h"
@@ -38,13 +40,14 @@ void ListHelp(const SContext& rsContext)
}
// Which list command help is requested
enum class EListCommand { unknown, modules, classes, components, installations, connections } eListCommand = EListCommand::unknown;
enum class EListCommand { unknown, modules, classes, components, installations, listeners, connections } eListCommand = EListCommand::unknown;
if (rsContext.seqCmdLine.size() >= 2)
{
if (iequals(rsContext.seqCmdLine[1], "MODULES")) eListCommand = EListCommand::modules;
else if (iequals(rsContext.seqCmdLine[1], "CLASSES")) eListCommand = EListCommand::classes;
else if (iequals(rsContext.seqCmdLine[1], "COMPONENTS")) eListCommand = EListCommand::components;
else if (iequals(rsContext.seqCmdLine[1], "INSTALLATIONS")) eListCommand = EListCommand::installations;
else if (iequals(rsContext.seqCmdLine[1], "LISTENERS")) eListCommand = EListCommand::listeners;
else if (iequals(rsContext.seqCmdLine[1], "CONNECTIONS")) eListCommand = EListCommand::connections;
}
@@ -65,20 +68,24 @@ void ListHelp(const SContext& rsContext)
case EListCommand::installations:
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST INSTALLATIONS [options...]\n\nShow a list of all installations.\n");
break;
case EListCommand::listeners:
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST LISTENERS [options...]\n\nShow a list of all configured listeners.\n");
break;
case EListCommand::connections:
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST CONNECTIONS [options...]\n\nShow a list of all connected applications.\n");
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST CONNECTIONS [options...]\n\nShow a list of all configured connections.\n");
break;
default:
CCommandLine::PrintHelpText(std::cout, R"code(Usage: sdv_control LIST <list_command> [options...]
CCommandLine::PrintHelpText(std::cout, R"text(Usage: sdv_control LIST <list_command> [options...]
Supported listing commands:
LIST MODULES Show a list of loaded server modules.
LIST CLASSES Show a list of available component classes.
LIST COMPONENTS Show a list of instantiated server components
LIST INSTALLATIONS Show a list of installations.
LIST LISTENERS Show a list of current listeners.
LIST CONNECTIONS Show a list of current connections.
)code");
)text");
break;
}
std::cout << "Options:\n";
@@ -103,33 +110,39 @@ int ListElements(const SContext& rsContext, std::ostream& rstream /*= std::cout*
return CMDLN_ARG_ERR;
}
// Which list command help is requested
enum class EListCommand { unknown, modules, classes, components, installations, connections } eListCommand = EListCommand::unknown;
// Which list command is requested
enum class EListCommand { unknown, modules, classes, components, installations, listeners, connections } eListCommand = EListCommand::unknown;
if (rsContext.seqCmdLine.size() >= 2)
{
if (iequals(rsContext.seqCmdLine[1], "MODULES")) eListCommand = EListCommand::modules;
else if (iequals(rsContext.seqCmdLine[1], "CLASSES")) eListCommand = EListCommand::classes;
else if (iequals(rsContext.seqCmdLine[1], "COMPONENTS")) eListCommand = EListCommand::components;
else if (iequals(rsContext.seqCmdLine[1], "INSTALLATIONS")) eListCommand = EListCommand::installations;
else if (iequals(rsContext.seqCmdLine[1], "LISTENERS")) eListCommand = EListCommand::listeners;
else if (iequals(rsContext.seqCmdLine[1], "CONNECTIONS")) eListCommand = EListCommand::connections;
}
else
{
if (!rsContext.bSilent)
{
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listing command.." << std::endl << std::endl;
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listing command." << std::endl;
ListHelp(rsContext);
}
return CMDLN_ARG_ERR;
}
// Try to connect
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
if (!ptrRepository)
// Try to connect (except when listing the listeners and connections... they can be read from the settings).
sdv::TObjectPtr ptrRepository;
if (eListCommand != EListCommand::listeners && eListCommand != EListCommand::connections)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << "." << std::endl;
return CONNECT_SDV_SERVER_ERROR;
ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << "."
<< std::endl;
return CONNECT_SDV_SERVER_ERROR;
}
}
int iRet = -100;
@@ -147,12 +160,16 @@ int ListElements(const SContext& rsContext, std::ostream& rstream /*= std::cout*
case EListCommand::installations:
iRet = ListInstallations(rsContext, ptrRepository, rstream);
break;
case EListCommand::listeners:
iRet = ListListeners(rsContext, rstream);
break;
case EListCommand::connections:
iRet = ListConnections(rsContext, ptrRepository, rstream);
iRet = ListConnections(rsContext, rstream);
break;
default:
break;
}
rstream << std::endl;
return iRet;
}
@@ -388,8 +405,107 @@ int ListInstallations(const SContext& rsContext, const sdv::TObjectPtr& rptrRepo
return NO_ERROR;
}
int ListConnections(const SContext& /*rsContext*/, const sdv::TObjectPtr& /*rptrRepository*/, std::ostream& /*rstream = std::cout */ )
std::string BuildParameters(const sdv::toml::CNodeCollection& rtable, const std::string& ssPrefix = std::string())
{
std::cout << "ERROR: " << NOT_IMPLEMENTED_MSG << " :-(" << std::endl;
return NOT_IMPLEMENTED;
std::string ssParams;
for (uint32_t uiIndex = 0; uiIndex < rtable.GetCount(); uiIndex++)
{
sdv::toml::CNode node = rtable.Get(uiIndex);
if (!node) continue;
std::string ssNodeText;
if (node.GetType() == sdv::toml::ENodeType::node_table)
{
sdv::toml::CNodeCollection tableChild(node);
if (!tableChild) continue;
ssNodeText = BuildParameters(tableChild, static_cast<std::string>(tableChild.GetName()) + ".");
}
else if (node.GetType() == sdv::toml::ENodeType::node_array)
{
// TODO...
}
else
ssNodeText = ssPrefix + node.GetName() + "=" + node.GetValueAsString();
// Add the text
if (!ssParams.empty())
ssParams += ", ";
ssParams += ssNodeText;
}
return ssParams;
}
int ListListeners(const SContext& rsContext, std::ostream& rstream /*= std::cout */ )
{
std::vector<std::array<std::string, 3>> vecListenerList;
vecListenerList.push_back({"Listener", "Provider", "Parameters"});
// Request the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
auto seqListeners = pAppConnections->GetListeners();
for (const sdv::u8string& rssListener : seqListeners)
{
std::string ssListener = rssListener;
auto ssConfig = pAppConnections->GetListenerConfig(rssListener);
sdv::toml::CTOMLParser parser(ssConfig);
if (!parser)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << PROCESS_LISTENER_CONFIG_ERROR_MSG << std::endl;
return PROCESS_LISTENER_CONFIG_ERROR;
}
std::string ssProvider = parser.GetDirect("Provider.Name").GetValueAsString();
std::string ssParams = BuildParameters(parser.GetDirect("IpcChannel"));
vecListenerList.push_back({ssListener, ssProvider, ssParams});
}
PrintTable(vecListenerList, rstream, rsContext.bListNoHdr);
if (vecListenerList.size() < 2)
rstream << " No listeners configured!" << std::endl;
return NO_ERROR;
}
int ListConnections(const SContext& rsContext, std::ostream& rstream /*= std::cout */ )
{
std::vector<std::array<std::string, 3>> vecConnectionList;
vecConnectionList.push_back({"Connection", "Provider", "Parameters"});
// Request the settings.
auto ptrAppService = sdv::core::GetObject("AppSettingsService");
sdv::app::IAppSettingsPersist* pAppSettingsPersist = ptrAppService.GetInterface<sdv::app::IAppSettingsPersist>();
sdv::app::IAppConnections* pAppConnections = ptrAppService.GetInterface<sdv::app::IAppConnections>();
if (!pAppSettingsPersist || !pAppConnections || !pAppSettingsPersist->LoadSettings())
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << CANNOT_LOAD_SETTINGS_MSG << std::endl;
return CANNOT_LOAD_SETTINGS;
}
auto seqConnections = pAppConnections->GetConnections();
for (const sdv::u8string& rssConnection : seqConnections)
{
std::string ssConnection = rssConnection;
auto ssConfig = pAppConnections->GetConnectionConfig(rssConnection);
sdv::toml::CTOMLParser parser(ssConfig);
if (!parser)
{
if (!rsContext.bSilent)
std::cerr << "ERROR: " << PROCESS_CONNECTION_CONFIG_ERROR_MSG << std::endl;
return PROCESS_CONNECTION_CONFIG_ERROR;
}
std::string ssProvider = parser.GetDirect("Provider.Name").GetValueAsString();
std::string ssParams = BuildParameters(parser.GetDirect("IpcChannel"));
vecConnectionList.push_back({ssConnection, ssProvider, ssParams});
}
PrintTable(vecConnectionList, rstream, rsContext.bListNoHdr);
if (vecConnectionList.size() < 2)
rstream << " No connections configured!" << std::endl;
return NO_ERROR;
}

View File

@@ -71,12 +71,19 @@ int ListComponents(const SContext& rsContext, const sdv::TObjectPtr& rptrReposit
int ListInstallations(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
/**
* @brief List the current connections.
* @brief List the current configured listeners.
* @param[in] rsContext Reference to the context.
* @param[in] rptrRepository Reference to the saerver repository.
* @param[in] rstream The output stream to use for printing (table only).
* @return The application exit code. 0 is no error.
*/
int ListConnections(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
int ListListeners(const SContext& rsContext, std::ostream& rstream);
/**
* @brief List the current connections.
* @param[in] rsContext Reference to the context.
* @param[in] rstream The output stream to use for printing (table only).
* @return The application exit code. 0 is no error.
*/
int ListConnections(const SContext& rsContext, std::ostream& rstream);
#endif // !defined LIST_ELEMENTS_H

View File

@@ -27,6 +27,7 @@
#include "list_elements.h"
#include "start_stop_service.h"
#include "installation.h"
#include "connection_config.h"
#include "../error_msg.h"
/**
@@ -53,12 +54,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
// NOTE EVE 27.05.2025: This task has been taken over by the process watchdog.
CProcessWatchdog watchdog;
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
SContext sContext;
bool bError = false;
@@ -67,24 +62,40 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
std::string ssArgError;
try
{
auto& rArgHelpDef = cmdln.DefineOption("?", bHelp, "Show help. Use <COMMAND> --help for specific help on the command.");
// Argument groups 1 - 10:
// STARTUP
// SHUTDOWN
// LIST
// INSTALL
// UPDATE
// UNINSTALL
// START
// STOP
// LISTENER
// CONNECTION
auto& rArgHelpDef =
cmdln.DefineOption("?", bHelp, "Show help. Use <COMMAND> --help for specific help on the command.");
rArgHelpDef.AddSubOptionName("help");
auto& rArgSilentDef = cmdln.DefineOption("s", sContext.bSilent, "Do not show any information on std::cout. Not compatible with 'verbose'.");
auto& rArgSilentDef = cmdln.DefineOption("s", sContext.bSilent, "Do not show any information on std::cout. Not compatible "
"with 'verbose'.");
rArgSilentDef.AddSubOptionName("silent");
auto& rArgVerboseDef = cmdln.DefineOption("v", sContext.bVerbose, "Provide verbose information. Not compatible with 'silent'.");
auto& rArgVerboseDef = cmdln.DefineOption("v", sContext.bVerbose, "Provide verbose information. Not compatible with "
"'silent'.");
rArgVerboseDef.AddSubOptionName("verbose");
cmdln.DefineSubOption("version", bVersion, "Show version information.");
cmdln.DefineSubOption("instance", sContext.uiInstanceID, "The instance ID of the SDV instance (default ID is 1000).");
cmdln.DefineSubOption("server_silent", sContext.bServerSilent, "Only used with STARTUP command: Server is started using "
"silent option. Not compatible with 'server_verbose'.");
"silent option. Not compatible with 'server_verbose'.", true, 1);
cmdln.DefineSubOption("server_verbose", sContext.bServerVerbose, "Only used with STARTUP command: Server is started using "
"verbose option. Not compatible with 'server_silent'.");
"verbose option. Not compatible with 'server_silent'.", true, 1);
cmdln.DefineSubOption("install_dir", sContext.pathInstallDir, "Only used with STARTUP command: Installation directory "
"(absolute or relative to the sdv_core executable).");
"(absolute or relative to the sdv_core executable).", true, 1);
cmdln.DefineSubOption("no_header", sContext.bListNoHdr, "Only used with LIST command: Do not print a header for the "
"listing table.");
"listing table.", true, 3);
cmdln.DefineSubOption("short", sContext.bListShort, "Only used with LIST command: Print only the most essential "
"information as one column.");
"information as one column.", true, 3);
cmdln.DefineSubOption(
"insert_before", sContext.ssInsertBeforeConnection, "Name of the connection to insert before.", true, 10);
cmdln.DefineDefaultArgument(sContext.seqCmdLine, "COMMAND");
cmdln.Parse(static_cast<size_t>(iArgc), rgszArgv);
@@ -98,7 +109,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!sContext.bSilent)
{
std::cout << "SDV Server Control Utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
}
@@ -113,7 +124,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
bError = true;
}
enum class ECommand { unknown, startup, shutdown, list, install, update, uninstall, start, stop } eCommand = ECommand::unknown;
enum class ECommand { unknown, startup, shutdown, list, install, update, uninstall, start, stop, listener, connection } eCommand = ECommand::unknown;
if (!sContext.seqCmdLine.empty())
{
if (iequals(sContext.seqCmdLine[0], "STARTUP")) eCommand = ECommand::startup;
@@ -124,6 +135,8 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
else if (iequals(sContext.seqCmdLine[0], "UNINSTALL")) eCommand = ECommand::uninstall;
else if (iequals(sContext.seqCmdLine[0], "START")) eCommand = ECommand::start;
else if (iequals(sContext.seqCmdLine[0], "STOP")) eCommand = ECommand::stop;
else if (iequals(sContext.seqCmdLine[0], "LISTENER")) eCommand = ECommand::listener;
else if (iequals(sContext.seqCmdLine[0], "CONNECTION")) eCommand = ECommand::connection;
else
{
if (!sContext.bSilent)
@@ -157,17 +170,25 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
case ECommand::uninstall:
InstallationHelp(sContext);
break;
case ECommand::listener:
ListenerHelp(sContext);
break;
case ECommand::connection:
ConnectionHelp(sContext);
break;
default:
cmdln.PrintHelp(std::cout, R"code(Supported commands:
STARTUP Start the core application server
SHUTDOWN Stop the core application server
LIST List module/classes/component/installation/connection information.
INSTALL Install a new application or service.
UPDATE Update an existing installation.
UNINSTALL Uninstall an installed application or service.
START Start a service (complex services only).
STOP Stop a service (complex services only).
)code");
cmdln.PrintHelp(std::cout, R"text(Supported commands:
STARTUP Start the core application server
SHUTDOWN Stop the core application server
LIST List information about modules/classes/components/installations/listeners/connections.
INSTALL Install a new application or service.
UPDATE Update an existing installation.
UNINSTALL Uninstall an installed application or service.
START Start a service (complex services and vehicle functions only).
STOP Stop a service (complex services and vehicle functions only).
LISTENER Add or remove a communication listener configuration.
CONNECTION Add or remove a connection configuration.
)text");
break;
}
}
@@ -185,11 +206,11 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (sContext.bVerbose)
std::cout << "Starting local application control.." << std::endl;
sdv::app::CAppControl appcontrol;
std::string ssAppConfig = std::string(R"code(
std::string ssAppConfig = std::string(R"toml(
[Application]
Mode = "Maintenance"
Instance = )code") + std::to_string(sContext.uiInstanceID) + R"code(
)code";
Instance = )toml") + std::to_string(sContext.uiInstanceID) + R"toml(
)toml";
if (!appcontrol.Startup(ssAppConfig))
{
if (!sContext.bSilent)
@@ -224,6 +245,12 @@ Instance = )code") + std::to_string(sContext.uiInstanceID) + R"code(
case ECommand::uninstall:
iRet = Uninstall(sContext);
break;
case ECommand::listener:
iRet = ConfigureListener(sContext);
break;
case ECommand::connection:
iRet = ConfigureConnection(sContext);
break;
default:
std::cout << "Command missing :-(" << std::endl;
break;

View File

@@ -35,8 +35,8 @@ void StartStopServiceHelp(const SContext& rsContext)
" sdv_control START <class> <name> [options...]\n\n"
"Start a complex service with the supplied object name as is defined in the configuration (first usage) or the "
"supplied class name and with object name assignment and add to the configuration (second usage).\n"
"Only complex services can be started. If the service depends on not running other services, these are started as "
"well.\n\n");
"Only vehicle functions and complex services can be started. If the service depends on not running other services, "
"these are started as well.\n\n");
return;
}
if (iequals(rsContext.seqCmdLine[0], "STOP"))
@@ -47,15 +47,14 @@ void StartStopServiceHelp(const SContext& rsContext)
" sdv_control STOP <module> [options...]\n\n"
"Stop the complex service(s) with the supplied object name (first usage), with supplied object ID (second usage), with "
"supplied class name (third usage) or contained in the module with the supplied module name (fourth usage).\n"
"Only complex services can be stopped. Dependent services are stopped as well. If one of object to be stopped is not a "
"complex service, the command fails.\n\n");
"Only vehicle functions and complex services can be stopped. Dependent services are stopped as well. If one of object "
"to be stopped is not a vehicle function or a complex service, the command fails.\n\n");
return;
}
if (!rsContext.bSilent)
std::cerr << "ERROR: invalid start/stop command..." << std::endl;
}
int StartService(const SContext& rsContext)
{
// First argument should be "START"
@@ -88,7 +87,7 @@ int StartService(const SContext& rsContext)
ssName = rsContext.seqCmdLine[1];
// Try to connect
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)
@@ -154,7 +153,7 @@ int StopService(const SContext& rsContext)
ssName = rsContext.seqCmdLine[1];
// Try to connect
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)

View File

@@ -76,9 +76,9 @@ void StartupShutdownHelp(const SContext& rsContext)
"Start the SDV server with the supplied instance ID. If no instance ID is supplied, use the default instance "
"ID #1000.\n\n"
"Options:\n"
" --server_silent Server is started using silent option. Not compatible with 'server_verbose'.\n"
" --server_verbose Server is started using verbose option. Not compatible with 'server_silent'.\n"
" --install_dir Installation directory (absolute or relative to the sdv_core executable).\n\n");
" --server_silent Server is started using silent option. Not compatible with 'server_verbose'.\n"
" --server_verbose Server is started using verbose option. Not compatible with 'server_silent'.\n"
" --install_dir<path> Installation directory (absolute or relative to the sdv_core executable).\n\n");
return;
}
if (iequals(rsContext.seqCmdLine[0], "SHUTDOWN"))
@@ -156,7 +156,7 @@ int StartupSDVServer(const SContext& rsContext)
}
// Try to connect
auto ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
auto ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)
@@ -183,7 +183,7 @@ int ShutdownSDVServer(const SContext& rsContext)
std::cout << "Connecting to the SDV #" << rsContext.uiInstanceID << " server..." << std::endl;
// Try to connect
auto ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
auto ptrRepository = sdv::com::ConnectToLocalServerRepository();
if (!ptrRepository)
{
if (!rsContext.bSilent)

View File

@@ -18,6 +18,40 @@
#include <support/app_control.h>
#include "../error_msg.h"
#ifdef _WIN32
/**
* @brief Console application control handler (CTRL+C, close, shutdown, etc.).
* @param[in] dwCtrlType The control type triggered by the system.
* @return Returns TRUE when the signal was handled.
*/
static BOOL WINAPI ControlHandler(DWORD dwCtrlType)
{
switch (dwCtrlType)
{
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
return TRUE;
break;
default:
return FALSE;
}
}
#elif defined __unix__
#include <signal.h>
/**
* @brief Signal handler to catch signal events.
* @param[in] iSigNum The signal type that was triggered.
*/
static void SignalHandler(int /*iSigNum*/)
{
// Do nothing...
}
#endif
/**
* @brief Main function of the executable.
* @param[in] iArgc Amount of arguments provided.
@@ -46,12 +80,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (thread.joinable())
thread.join();
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
bool bHelp = false;
bool bError = false;
@@ -91,7 +119,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!bSilent && !bNoBanner)
{
std::cout << "SDV core application" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
}
@@ -185,14 +213,40 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
return APP_CONTROL_STARTUP_ERROR;
}
#ifdef _WIN32
// Register the console control handler
if (!SetConsoleCtrlHandler(&ControlHandler, TRUE))
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << " - failed registering control handler." << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#elif defined __unix__
// Install our signal handler
struct sigaction sSigAction
{};
sSigAction.sa_handler = SignalHandler;
sSigAction.sa_flags = SA_RESTART;
if (sigaction(SIGINT, &sSigAction, NULL) == -1)
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << " - failed registering control handler." << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#endif
// Start the running loop
if (!appcontrol.RunLoop())
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_DUPLICATE_INSTANCE_MSG << std::endl;
return APP_CONTROL_DUPLICATE_INSTANCE;
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#ifdef _WIN32
SetConsoleCtrlHandler(&ControlHandler, FALSE);
#endif
if (bVerbose)
{
std::cout << "Shutdown request received..." << std::endl;

View File

@@ -372,7 +372,10 @@ bool CreateCoreServiceTomlFile(const std::string& resources)
std::ofstream tomlFile("sdv_core_reloc.toml");
if (tomlFile.is_open())
{
tomlFile << "# Location of the SDV binaries and configuration files\ndirectory = \"";
tomlFile << R"toml(# Location of the SDV binaries and configuration files
[CoreLocation]
Version = 100
Framework = ")toml";
tomlFile << resources;
tomlFile << "\"\n";
tomlFile.close();

View File

@@ -82,7 +82,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!bSilent)
{
std::cout << "DBC utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl;
}
if (bHelp)

View File

@@ -174,6 +174,9 @@ std::string CProxyGenerator::GetFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& r
else
sstreamExceptions << R"code(sdv::XUnknownException exception;
exception.unknown_id = except_id;
// Cpp-Check 2.7 warns about the uninitialized variable _id. This variable is allocated as inline static const and is
// assigned a value. Suppress the warning.
// cppcheck-suppress uninitvar
throw exception;)code";
for (const std::string& rssException : rvecExceptions)
{
@@ -181,6 +184,9 @@ std::string CProxyGenerator::GetFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& r
{
)code" << rssException << R"code( exception;
desOutput >> exception;
// Cpp-Check 2.7 warns about the uninitialized variable _id. This variable is allocated as inline static const and is
// assigned a value. Suppress the warning.
// cppcheck-suppress uninitvar
throw exception;
}
)code";
@@ -190,6 +196,9 @@ std::string CProxyGenerator::GetFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& r
{
sdv::XUnknownException exception;
exception.unknown_id = except_id;
// Cpp-Check 2.7 warns about the uninitialized variable _id. This variable is allocated as inline static const and is
// assigned a value. Suppress the warning.
// cppcheck-suppress uninitvar
throw exception;
}
})code";

View File

@@ -41,7 +41,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
CProcessWatchdog watchdog;
std::cout << "SDV IDL Compiler" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl;
// Create a list of UTF-8 arguments

View File

@@ -28,6 +28,7 @@
#include "token.h"
#include <fstream>
#include <filesystem>
#include <clocale>
#include <locale>
#include <codecvt>
#include <cuchar>
@@ -71,7 +72,7 @@ const std::string& CSource::GetCodeRef() const
void CSource::ReadFile(const std::filesystem::path& rpath)
{
// Set the locale to work with UTF8
std::setlocale(LC_ALL, "en_US.utf8");
::setlocale(LC_ALL, "en_US.utf8");
if (rpath.empty())
throw CCompileException("File name missing");

View File

@@ -22,6 +22,40 @@
#include <support/local_service_access.h>
#include "../error_msg.h"
#ifdef _WIN32
/**
* @brief Console application control handler (CTRL+C, close, shutdown, etc.).
* @param[in] dwCtrlType The control type triggered by the system.
* @return Returns TRUE when the signal was handled.
*/
static BOOL WINAPI ControlHandler(DWORD dwCtrlType)
{
switch (dwCtrlType)
{
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
return TRUE;
break;
default:
return FALSE;
}
}
#elif defined __unix__
#include <signal.h>
/**
* @brief Signal handler to catch signal events.
* @param[in] iSigNum The signal type that was triggered.
*/
static void SignalHandler(int /*iSigNum*/)
{
// Do nothing...
}
#endif
/**
* @brief Connect event callback wrapper. Calls shutdown request on disconnect or error.
*/
@@ -93,12 +127,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (thread.joinable())
thread.join();
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
bool bHelp = false;
bool bError = false;
@@ -126,23 +154,29 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
{
ssArgError = rsExcept.what();
bHelp = true;
bError = true;
}
if (!bSilent)
{
std::cout << "SDV isolation application" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
}
if (!ssArgError.empty() && !bSilent)
if (!ssArgError.empty() && !bSilent && !bHelp && !bVersion)
std::cerr << "ERROR: " << ssArgError << std::endl;
if (ssConfigBase64.empty())
if (bVersion || bVerbose)
{
ssArgError = "Missing app configuration.";
bHelp = true;
std::cout << "Version: " << (SDVFrameworkBuildVersion / 100) << "." << (SDVFrameworkBuildVersion % 100) << " build "
<< SDVFrameworkSubbuildVersion << " interface " << SDVFrameworkInterfaceVersion << std::endl;
}
if (!bHelp && ssConfigBase64.empty())
{
if (!bSilent && !bVersion)
std::cout << "Missing app configuration.";
bError = true;
}
if (bHelp)
@@ -153,17 +187,14 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
std::cout << std::endl;
cmdln.PrintHelp(std::cout, "The isolation application is used to isolate components from the core process. The "
"isolation aims to improve the overall stability of the system.\n");
return bError ? CMDLN_ARG_ERR : NO_ERROR;
}
return (bError && !bVersion && !bHelp) ? CMDLN_ARG_ERR : NO_ERROR;
}
if (bError) return CMDLN_ARG_ERR;
if (bError) return (bError && !bVersion && !bHelp) ? CMDLN_ARG_ERR : NO_ERROR;
// Check for encoded configuration
std::string ssIsoAppConfig = Base64DecodePlainText(ssConfigBase64);
if (bVersion || bVerbose)
std::cout << "Version: " << (SDVFrameworkBuildVersion / 100) << "." << (SDVFrameworkBuildVersion % 100) << " build " <<
SDVFrameworkSubbuildVersion << " interface " << SDVFrameworkInterfaceVersion << std::endl;
if (!bSilent)
std::cout << "Instance ID: " << uiInstanceID << std::endl;
@@ -267,7 +298,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
std::cerr << "ERROR: " << LINK_REPO_SERVICE_ERROR_MSG << std::endl;
return LINK_REPO_SERVICE_ERROR;
}
pLinkCoreRepo->LinkCoreRepository(pCoreRepo);
sdv::core::TLinkID tRepoLink = pLinkCoreRepo->LinkCoreRepository(pCoreRepo);
// Create the one object... is this a service or a utility?
std::string ssClassName = parser.GetDirect("Isolation.Class").GetValue();
@@ -332,6 +363,28 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
// The lifetime of the object is now taken over by the core or if failed, the object will be destroyed.
ptrObject.Clear();
#ifdef _WIN32
// Register the console control handler
if (!SetConsoleCtrlHandler(&ControlHandler, TRUE))
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << " - failed registering control handler." << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#elif defined __unix__
// Install our signal handler
struct sigaction sSigAction
{};
sSigAction.sa_handler = SignalHandler;
sSigAction.sa_flags = SA_RESTART;
if (sigaction(SIGINT, &sSigAction, NULL) == -1)
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << " - failed registering control handler." << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#endif
// Deactivate the configuration mode.
appcontrol.SetRunningMode();
@@ -339,10 +392,14 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!appcontrol.RunLoop())
{
if (!bSilent)
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAIELD_MSG << std::endl;
return APP_CONTROL_START_LOOP_FAIELD;
std::cerr << "ERROR: " << APP_CONTROL_START_LOOP_FAILED_MSG << std::endl;
return APP_CONTROL_START_LOOP_FAILED;
}
#ifdef _WIN32
SetConsoleCtrlHandler(&ControlHandler, FALSE);
#endif
// TODO EVE
if (appcontrol.IsConfiguring())
std::cout << "Iso app configuring... " << __LINE__ << std::endl;
@@ -358,7 +415,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
// Shutdwown
pConnect->UnregisterStateEventCallback(uiCookie);
parser.Clear();
pLinkCoreRepo->UnlinkCoreRepository();
pLinkCoreRepo->UnlinkCoreRepository(tRepoLink);
appcontrol.Shutdown();
if (!bSilent)

View File

@@ -32,12 +32,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
// NOTE EVE 27.05.2025: This task has been taken over by the process watchdog.
CProcessWatchdog watchdog;
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
bool bHelp = false;
bool bError = false;
@@ -67,7 +61,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!bSilent)
{
std::cout << "SDV Local Instance Shutdown Utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
}

View File

@@ -24,4 +24,5 @@
#include "../../sdv_services/core/toml_parser/character_reader_utf_8.cpp"
#include "../../sdv_services/core/toml_parser/miscellaneous.cpp"
#include "../../sdv_services/core/toml_parser/code_snippet.cpp"
#include "../../sdv_services/core/toml_parser/parser_node_indexer.cpp"

View File

@@ -12,9 +12,8 @@
********************************************************************************/
#include "environment.h"
#include <string_view>
#include "../../global/exec_dir_helper.h"
#include "../../global/cmdlnparser/cmdlnparser.cpp"
CSdvPackagerEnvironment::CSdvPackagerEnvironment() :
@@ -862,13 +861,16 @@ bool CSdvPackagerEnvironment::ProcessCommandLine(const std::vector<std::string>&
{
#ifdef _WIN32
const wchar_t* szInstallDir = _wgetenv(L"SDV_COMPONENT_INSTALL");
if (!szInstallDir) szInstallDir = _wgetenv(L"SDV_FRAMEWORK_RUNTIME");
if (szInstallDir) m_pathTargetLocation = szInstallDir;
#elif defined __unix__
const char* szInstallDir = getenv("SDV_COMPONENT_INSTALL");
if (!szInstallDir) szInstallDir = getenv("SDV_FRAMEWORK_RUNTIME");
if (szInstallDir) m_pathTargetLocation = std::filesystem::u8path(szInstallDir);
#else
#error OS not supported!
#endif
if (m_pathTargetLocation.empty()) m_pathTargetLocation = GetExecDirectory();
}
// Is the directory existing? If not, create the directory

View File

@@ -41,12 +41,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
// NOTE EVE 27.05.2025: This task has been taken over by the process watchdog.
CProcessWatchdog watchdog;
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
// Process the command line.
CSdvPackagerEnvironment environment(iArgc, rgszArgv);
@@ -54,7 +48,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!environment.Silent())
{
std::cout << "SDV Component Installation Package Utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
}
@@ -114,7 +108,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
}
// If running as server, load the settings file
if (!environment.Local() && !GetAppSettings().LoadSettingsFile())
if (!environment.Local() && !GetAppSettings().LoadSettings())
{
std::cerr << "ERROR: Failed to load the application settings file; cannot continue!" << std::endl;
return -1;

View File

@@ -450,7 +450,7 @@ bool CPackager::Configure()
m_ssArgError = CMDLN_MISSING_TARGET_MSG;
return false;
}
if (!GetAppSettings().SaveSettingsFile())
if (!GetAppSettings().SaveSettings())
{
SDV_LOG_ERROR("Failed to save application settings. Cannot configure components!");
return false;
@@ -743,7 +743,7 @@ bool CPackager::ConfigureFromManifest(const CInstallManifest& rmanifest)
auto pathConfig = GetAppSettings().GetConfigPath(CAppSettings::EConfigType::user_config);
WriteConfig(vecClasses, pathConfig, vecComponentsToAdd, true, vecAddedToConfig);
}
if (!GetAppSettings().SaveSettingsFile())
if (!GetAppSettings().SaveSettings())
{
SDV_LOG_ERROR("Failed to save application settings. Cannot configure components!");
return false;
@@ -806,11 +806,11 @@ void CPackager::WriteConfig(const std::vector<sdv::SClassInfo>& rvecAllClasses,
break;
case sdv::EObjectType::complex_service:
case sdv::EObjectType::vehicle_function:
case sdv::EObjectType::utility:
eIncompatible = bUserConfig ? ECompatibility::compatible : ECompatibility::incompatible;
break;
case sdv::EObjectType::proxy:
case sdv::EObjectType::stub:
case sdv::EObjectType::utility:
eIncompatible = ECompatibility::silent_incompatible;
break;
default:

View File

@@ -65,7 +65,7 @@ static BOOL WINAPI ControlHandler(DWORD dwCtrlType)
}
#elif defined __unix__
/**
* @brief Signal handler to catch signal eevents.
* @brief Signal handler to catch signal events.
* @param[in] iSigNum The signal type that was triggered.
*/
static void SignalHandler(int iSigNum)
@@ -97,12 +97,6 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (thread.joinable())
thread.join();
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
bool bHelp = false;
bool bVersion = false;
@@ -123,7 +117,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
}
std::cout << "SDV Server Log Monitor Utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
if (bVersion)

View File

@@ -109,7 +109,7 @@ extern "C" int main(int iArgc, const char* rgszArgv[])
if (!bSilent)
{
std::cout << "abtract device / basic services utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Copyright (C): 2022-2026 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Thomas Pfleiderer" << std::endl;
}