Skip to content
4 changes: 4 additions & 0 deletions SilKit/IntegrationTests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ add_silkit_test_to_executable(SilKitIntegrationTests
SOURCES ITest_SimTask.cpp
)

add_silkit_test_to_executable(SilKitIntegrationTests
SOURCES ITest_Parameters.cpp
)

add_silkit_test_to_executable(SilKitFunctionalTests
SOURCES FTest_WallClockCoupling.cpp
)
Expand Down
15 changes: 15 additions & 0 deletions SilKit/IntegrationTests/Hourglass/MockCapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,21 @@ extern "C"
return globalCapi->SilKit_Participant_GetLogger(outLogger, participant);
}

SilKit_ReturnCode SilKitCALL SilKit_Participant_GetParticipantName(char* outParticipantName,
size_t* inOutParticipantNameSize,
SilKit_Participant* participant)
{
return globalCapi->SilKit_Participant_GetParticipantName(outParticipantName, inOutParticipantNameSize,
participant);
}

SilKit_ReturnCode SilKitCALL SilKit_Participant_GetRegistryUri(char* outRegistryUri,
size_t* inOutRegistryUriSize,
SilKit_Participant* participant)
{
return globalCapi->SilKit_Participant_GetRegistryUri(outRegistryUri, inOutRegistryUriSize, participant);
}

// ParticipantConfiguration

SilKit_ReturnCode SilKitCALL SilKit_ParticipantConfiguration_FromString(
Expand Down
6 changes: 6 additions & 0 deletions SilKit/IntegrationTests/Hourglass/MockCapi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,12 @@ class MockCapi
MOCK_METHOD(SilKit_ReturnCode, SilKit_Participant_GetLogger,
(SilKit_Logger * *outLogger, SilKit_Participant* participant));

MOCK_METHOD(SilKit_ReturnCode, SilKit_Participant_GetParticipantName,
(char* outParticipantName, size_t* inOutParticipantNameSize, SilKit_Participant* participant));

MOCK_METHOD(SilKit_ReturnCode, SilKit_Participant_GetRegistryUri,
(char* outRegistryUri, size_t* inOutRegistryUriSize, SilKit_Participant* participant));

// ParticipantConfiguration

MOCK_METHOD(SilKit_ReturnCode, SilKit_ParticipantConfiguration_FromString,
Expand Down
56 changes: 56 additions & 0 deletions SilKit/IntegrationTests/ITest_Parameters.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-FileCopyrightText: 2026 Vector Informatik GmbH
//
// SPDX-License-Identifier: MIT

#include <sstream>
#include <string>

#include "gtest/gtest.h"

#include "silkit/SilKit.hpp"
#include "silkit/vendor/CreateSilKitRegistry.hpp"

namespace {

class ITest_Parameters : public testing::Test
{
protected:
const std::string _registryUriAnyPort{"silkit://127.0.0.1:0"};
};

TEST_F(ITest_Parameters, participant_name_and_registry_uri_set_by_api)
{
const std::string participantNameByApi{"P1"};

auto emptyParticipantConfig = SilKit::Config::ParticipantConfigurationFromString("");
auto registry = SilKit::Vendor::Vector::CreateSilKitRegistry(emptyParticipantConfig);
auto registryUriByApi = registry->StartListening(_registryUriAnyPort);

auto participant = SilKit::CreateParticipant(emptyParticipantConfig, participantNameByApi, registryUriByApi);

EXPECT_EQ(participant->GetParticipantName(), participantNameByApi);
EXPECT_EQ(participant->GetRegistryUri(), registryUriByApi);
}

TEST_F(ITest_Parameters, participant_name_and_registry_uri_set_by_configuration)
{
const std::string participantNameByApi{"P2"};
const std::string registryUriByApi{"silkit://127.0.0.42:0"};
const std::string participantNameByConfig{"P1"};

auto emptyParticipantConfig = SilKit::Config::ParticipantConfigurationFromString("");
auto registry = SilKit::Vendor::Vector::CreateSilKitRegistry(emptyParticipantConfig);
auto registryUriByConfig = registry->StartListening(_registryUriAnyPort);

std::ostringstream ss;
ss << R"({ "ParticipantName": ")" << participantNameByConfig
<< R"(", "Middleware": { "RegistryUri": ")" << registryUriByConfig << R"(" }})";

auto participantConfig = SilKit::Config::ParticipantConfigurationFromString(ss.str());
auto participant = SilKit::CreateParticipant(participantConfig, participantNameByApi, registryUriByApi);

EXPECT_EQ(participant->GetParticipantName(), participantNameByConfig);
EXPECT_EQ(participant->GetRegistryUri(), registryUriByConfig);
}

} // namespace
31 changes: 31 additions & 0 deletions SilKit/include/silkit/capi/Participant.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,37 @@ SilKitAPI SilKit_ReturnCode SilKitCALL SilKit_Participant_GetLogger(SilKit_Logge
typedef SilKit_ReturnCode(SilKitFPTR* SilKit_Participant_GetLogger_t)(SilKit_Logger** outLogger,
SilKit_Participant* participant);


/*! \brief Retrieve the participant name from a participant.
*
* \param outParticipantName A buffer to copy the null-terminated participant name to.
* Passing a nullptr is valid and indicates a size-check via inOutParticipantNameSize.
* \param inOutParticipantNameSize The required/provided size of the value including null-termination.
* \param participant The participant to query.
*/
SilKitAPI SilKit_ReturnCode SilKitCALL SilKit_Participant_GetParticipantName(char* outParticipantName,
size_t* inOutParticipantNameSize,
SilKit_Participant* participant);

typedef SilKit_ReturnCode(SilKitFPTR* SilKit_Participant_GetParticipantName_t)(char* outParticipantName,
size_t* inOutParticipantNameSize,
SilKit_Participant* participant);

/*! \brief Retrieve the registry URI from a participant.
*
* \param outRegistryUri A buffer to copy the null-terminated registry URI to.
* Passing a nullptr is valid and indicates a size-check via inOutRegistryUriSize.
* \param inOutRegistryUriSize The required/provided size of the value including null-termination.
* \param participant The participant to query.
*/
SilKitAPI SilKit_ReturnCode SilKitCALL SilKit_Participant_GetRegistryUri(char* outRegistryUri,
size_t* inOutRegistryUriSize,
SilKit_Participant* participant);

typedef SilKit_ReturnCode(SilKitFPTR* SilKit_Participant_GetRegistryUri_t)(char* outRegistryUri,
size_t* inOutRegistryUriSize,
SilKit_Participant* participant);

SILKIT_END_DECLS

#pragma pack(pop)
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH
//
// SPDX-License-Identifier: MIT

#pragma once

#include <string>
#include <vector>

#include "silkit/participant/exception.hpp"
#include "silkit/detail/impl/ThrowOnError.hpp"

namespace SilKit {
DETAIL_SILKIT_DETAIL_VN_NAMESPACE_BEGIN
namespace Impl {

using StringQueryFunction = SilKit_ReturnCode(SilKitCALL*)(char*, size_t*, SilKit_Participant*);
inline auto QueryString(SilKit_Participant* participant, StringQueryFunction stringQueryFunction) -> std::string;

inline auto GetParticipantName(SilKit_Participant* participant) -> std::string;
inline auto GetRegistryUri(SilKit_Participant* participant) -> std::string;

// ================================================================================
// Inline Implementations
// ================================================================================

auto QueryString(SilKit_Participant* participant, StringQueryFunction stringQueryFunction) -> std::string
{
std::vector<char> buffer;
size_t size = 0;

{
// Initially only get the size of the string to be queried
const auto returnCode = stringQueryFunction(nullptr, &size, participant);
ThrowOnError(returnCode);
}

while (size > buffer.size())
{
// Retry until the returned required size fits our buffer:
// the value may change between the initial size query and the copy call.
buffer.resize(size);
const auto returnCode = stringQueryFunction(buffer.data(), &size, participant);
ThrowOnError(returnCode);
}

return std::string{buffer.data()};
}

auto GetParticipantName(SilKit_Participant* participant) -> std::string
{
return QueryString(participant, &SilKit_Participant_GetParticipantName);
}

auto GetRegistryUri(SilKit_Participant* participant) -> std::string
{
return QueryString(participant, &SilKit_Participant_GetRegistryUri);
}

} // namespace Impl
DETAIL_SILKIT_DETAIL_VN_NAMESPACE_CLOSE
} // namespace SilKit
17 changes: 17 additions & 0 deletions SilKit/include/silkit/detail/impl/participant/Participant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@

#include "silkit/detail/impl/netsim/NetworkSimulator.hpp"

#include "silkit/detail/impl/participant/ParameterProvider.hpp"

namespace SilKit {
DETAIL_SILKIT_DETAIL_VN_NAMESPACE_BEGIN
namespace Impl {
Expand Down Expand Up @@ -83,6 +85,10 @@ class Participant : public SilKit::IParticipant

inline auto GetLogger() -> SilKit::Services::Logging::ILogger* override;

inline auto GetParticipantName() const -> std::string override;

inline auto GetRegistryUri() const -> std::string override;

inline auto ExperimentalCreateNetworkSimulator() -> SilKit::Experimental::NetworkSimulation::INetworkSimulator*;

inline auto ExperimentalCreateSystemController()
Expand Down Expand Up @@ -224,6 +230,17 @@ auto Participant::GetLogger() -> SilKit::Services::Logging::ILogger*
return _logger.get();
}


auto Participant::GetParticipantName() const -> std::string
{
return Impl::GetParticipantName(_participant);
}

auto Participant::GetRegistryUri() const -> std::string
{
return Impl::GetRegistryUri(_participant);
}

auto Participant::ExperimentalCreateSystemController()
-> SilKit::Experimental::Services::Orchestration::ISystemController*
{
Expand Down
7 changes: 7 additions & 0 deletions SilKit/include/silkit/participant/IParticipant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "silkit/services/rpc/RpcSpec.hpp"
#include "silkit/services/rpc/RpcDatatypes.hpp"


namespace SilKit {

/*! \brief Communication interface to be used by SIL Kit participants
Expand Down Expand Up @@ -82,6 +83,12 @@ class IParticipant

//! \brief Return the ILogger at this SIL Kit participant.
virtual auto GetLogger() -> Services::Logging::ILogger* = 0;

//! \brief Return the participant name of this SIL Kit participant.
virtual auto GetParticipantName() const -> std::string = 0;

//! \brief Return the URI of the registry this SIL Kit participant connects to.
virtual auto GetRegistryUri() const -> std::string = 0;
};

} // namespace SilKit
2 changes: 2 additions & 0 deletions SilKit/source/capi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,5 @@ add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiLin.cpp LIBS S_Si
add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiSymbols.cpp LIBS S_SilKitImpl)
add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiNetSim.cpp LIBS S_SilKitImpl I_SilKit)
add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiExceptions.cpp LIBS S_SilKitImpl)
add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiGetParameter.cpp LIBS S_SilKitImpl)

51 changes: 51 additions & 0 deletions SilKit/source/capi/CapiParticipant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,36 @@
#include "CapiImpl.hpp"
#include "TypeConversion.hpp"

#include <algorithm>
#include <memory>
#include <map>
#include <mutex>
#include <fstream>
#include <string_view>

namespace
{
auto CopyStringToOutBuffer(std::string_view value, char* outStringBuffer, size_t* inOutStringBufferSize)
-> SilKit_ReturnCode
{
// Passing outStringBuffer == nullptr performs a size-check only.
const auto requiredSize = value.size() + 1; // include '\0'

if (outStringBuffer != nullptr)
{
const auto bufferSize = *inOutStringBufferSize;
if (bufferSize > 0)
{
const auto sizeToCopy = std::min(value.size(), bufferSize - 1);
value.copy(outStringBuffer, sizeToCopy);
outStringBuffer[sizeToCopy] = '\0';
}
}

*inOutStringBufferSize = requiredSize;
return SilKit_ReturnCode_SUCCESS;
}
} // namespace

SilKit_ReturnCode SilKitCALL SilKit_Participant_Create(SilKit_Participant** outParticipant,
SilKit_ParticipantConfiguration* participantConfiguration,
Expand Down Expand Up @@ -86,6 +111,32 @@ try
}
CAPI_CATCH_EXCEPTIONS

SilKit_ReturnCode SilKitCALL SilKit_Participant_GetParticipantName(char* outParticipantName,
size_t* inOutParticipantNameSize,
SilKit_Participant* participant)
try
{
ASSERT_VALID_OUT_PARAMETER(inOutParticipantNameSize);
ASSERT_VALID_POINTER_PARAMETER(participant);

auto cppParticipant = reinterpret_cast<SilKit::IParticipant*>(participant);
return CopyStringToOutBuffer(cppParticipant->GetParticipantName(), outParticipantName, inOutParticipantNameSize);
}
CAPI_CATCH_EXCEPTIONS

SilKit_ReturnCode SilKitCALL SilKit_Participant_GetRegistryUri(char* outRegistryUri,
size_t* inOutRegistryUriSize,
SilKit_Participant* participant)
try
{
ASSERT_VALID_OUT_PARAMETER(inOutRegistryUriSize);
ASSERT_VALID_POINTER_PARAMETER(participant);

auto cppParticipant = reinterpret_cast<SilKit::IParticipant*>(participant);
return CopyStringToOutBuffer(cppParticipant->GetRegistryUri(), outRegistryUri, inOutRegistryUriSize);
}
CAPI_CATCH_EXCEPTIONS


SilKit_ReturnCode SilKitCALL SilKit_ParticipantConfiguration_FromString(
SilKit_ParticipantConfiguration** outParticipantConfiguration, const char* participantConfigurationString)
Expand Down
Loading
Loading