Precommit (#1)

* first commit

* cleanup
This commit is contained in:
tompzf
2025-11-04 13:28:06 +01:00
committed by GitHub
parent dba45dc636
commit 6ed4b1534e
898 changed files with 256340 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
# Include cross-compilation toolchain file
include(../../cross-compile-tools.cmake)
# Define project
project(service_component_isolation VERSION 1.0 LANGUAGES CXX)
# Define target
add_library(ipc_com SHARED
"com_ctrl.h"
"com_ctrl.cpp"
"com_channel.h"
"com_channel.cpp"
"marshall_object.h"
"marshall_object.cpp"
#"scheduler.cpp"
)
if(UNIX)
target_link_libraries(ipc_com rt ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
else()
target_link_libraries(ipc_com ${CMAKE_THREAD_LIBS_INIT})
target_link_options(ipc_com PRIVATE)
endif()
target_include_directories(ipc_com PRIVATE ./include)
set_target_properties(ipc_com PROPERTIES PREFIX "")
set_target_properties(ipc_com PROPERTIES SUFFIX ".sdv")
# Build dependencies
add_dependencies(ipc_com CompileCoreIDL)
add_dependencies(ipc_com core_ps)
# Appending the service in the service list
set(SDV_Service_List ${SDV_Service_List} ipc_com PARENT_SCOPE)

View File

@@ -0,0 +1,321 @@
#include "com_channel.h"
#include "com_ctrl.h"
#include "marshall_object.h"
#include <support/pssup.h>
#include <support/serdes.h>
#include <support/local_service_access.h>
#include <interfaces/serdes/core_ps_serdes.h>
#include "../../global/scheduler/scheduler.cpp"
CChannelConnector::CChannelConnector(CCommunicationControl& rcontrol, uint32_t uiIndex, sdv::IInterfaceAccess* pChannelEndpoint) :
m_rcontrol(rcontrol), m_ptrChannelEndpoint(pChannelEndpoint),
m_pDataSend(m_ptrChannelEndpoint.GetInterface<sdv::ipc::IDataSend>())
{
m_tConnectionID.uiIdent = uiIndex;
m_tConnectionID.uiControl = static_cast<uint32_t>(rand());
}
CChannelConnector::~CChannelConnector()
{
// Finalize the scheduled calls.
m_scheduler.WaitForExecution();
// Remove all calls from the queue
std::unique_lock<std::mutex> lock(m_mtxCalls);
while (m_mapCalls.size())
{
SCallEntry& rsEntry = m_mapCalls.begin()->second;
m_mapCalls.erase(m_mapCalls.begin());
lock.unlock();
// Cancel the processing
rsEntry.bCancel = true;
rsEntry.cvWaitForResult.notify_all();
// Handle next call.
lock.lock();
}
lock.unlock();
// Disconnect
sdv::ipc::IConnect* pConnection = m_ptrChannelEndpoint.GetInterface<sdv::ipc::IConnect>();
if (pConnection)
{
if (m_uiConnectionStatusCookie) pConnection->UnregisterStatusEventCallback(m_uiConnectionStatusCookie);
pConnection->Disconnect();
}
}
bool CChannelConnector::ServerConnect(sdv::IInterfaceAccess* pObject, bool bAllowReconnect)
{
if (!m_ptrChannelEndpoint || !m_pDataSend) return false; // No channel
if (!pObject) return false; // No object
if (m_ptrInitialMarshallObject) return false; // Has already a marshall object.
m_bAllowReconnect = bAllowReconnect;
m_eEndpointType = EEndpointType::server;
m_ptrInitialMarshallObject = m_rcontrol.GetOrCreateStub(pObject);
if (!m_ptrInitialMarshallObject) return false;
// Establish connection...
sdv::ipc::IConnect* pConnection = m_ptrChannelEndpoint.GetInterface<sdv::ipc::IConnect>();
if (!pConnection) return false;
m_uiConnectionStatusCookie = pConnection->RegisterStatusEventCallback(this);
return m_uiConnectionStatusCookie != 0 && pConnection->AsyncConnect(this);
}
sdv::IInterfaceAccess* CChannelConnector::ClientConnect(uint32_t uiTimeoutMs)
{
if (!m_ptrChannelEndpoint || !m_pDataSend) return nullptr; // No channel
if (!uiTimeoutMs) return nullptr; // No timeout
if (m_ptrInitialMarshallObject) return nullptr; // Has already a marshall object.
m_eEndpointType = EEndpointType::client;
// Get or create the proxy
m_ptrInitialMarshallObject = GetOrCreateProxy(sdv::GetInterfaceId<sdv::IInterfaceAccess>(), sdv::ps::TMarshallID{});
if (!m_ptrInitialMarshallObject)
{
SDV_LOG_ERROR("Could not get or create proxy object!");
return nullptr;
}
// Establish connection...
sdv::ipc::IConnect* pConnection = m_ptrChannelEndpoint.GetInterface<sdv::ipc::IConnect>();
if (pConnection) m_uiConnectionStatusCookie = pConnection->RegisterStatusEventCallback(this);
if (!pConnection || m_uiConnectionStatusCookie == 0 || !pConnection->AsyncConnect(this) ||
!pConnection->WaitForConnection(uiTimeoutMs))
{
SDV_LOG_ERROR("Could not establish a connection!");
m_ptrInitialMarshallObject.reset();
return nullptr;
}
return m_ptrInitialMarshallObject->GetProxy().get<sdv::IInterfaceAccess>();
}
bool CChannelConnector::IsConnected() const
{
return m_eConnectStatus == sdv::ipc::EConnectStatus::connected;
}
void CChannelConnector::SetStatus(/*in*/ sdv::ipc::EConnectStatus eConnectStatus)
{
auto eConnectStatusTemp = m_eConnectStatus;
m_eConnectStatus = eConnectStatus;
switch (m_eConnectStatus)
{
case sdv::ipc::EConnectStatus::disconnected:
case sdv::ipc::EConnectStatus::disconnected_forced:
// Invalidate the proxy objects.
for (auto& rvtProxyObject : m_mapProxyObjects)
rvtProxyObject.second.reset();
if (m_eEndpointType == EEndpointType::server)
{
// Report information (but only once)
if (sdv::app::ConsoleIsVerbose() && eConnectStatusTemp != sdv::ipc::EConnectStatus::disconnected)
std::cout << "Client disconnected (ID#" << m_tConnectionID.uiIdent << ")" << std::endl;
// Remove the connection if reconnection is not enabled (normal case).
if (!m_bAllowReconnect)
m_rcontrol.RemoveConnection(m_tConnectionID);
}
break;
case sdv::ipc::EConnectStatus::connected:
if (m_eEndpointType == EEndpointType::server)
{
// Report information
if (sdv::app::ConsoleIsVerbose())
std::cout << "Client connected (ID#" << m_tConnectionID.uiIdent << ")" << std::endl;
}
break;
default:
break;
}
}
void CChannelConnector::ReceiveData(/*inout*/ sdv::sequence<sdv::pointer<uint8_t>>& seqData)
{
// Schedule the data reception
std::mutex mtxSyncData;
std::condition_variable cvSyncData;
bool bSyncData = false;
bool bResult = m_scheduler.Schedule([&]()
{
// Copy the data to keep validity
std::unique_lock<std::mutex> lock(mtxSyncData);
sdv::sequence<sdv::pointer<uint8_t>> seqDataCopy = std::move(seqData);
lock.unlock();
bSyncData = true;
cvSyncData.notify_all();
// Call the receive function
DecoupledReceiveData(seqDataCopy);
});
std::unique_lock<std::mutex> lockSyncData(mtxSyncData);
while (bResult && !bSyncData) cvSyncData.wait_for(lockSyncData, std::chrono::milliseconds(10));
lockSyncData.unlock();
// TODO: Handle a schedule failure - send back a resource depletion.
}
void CChannelConnector::DecoupledReceiveData(/*inout*/ sdv::sequence<sdv::pointer<uint8_t>>& seqData)
{
// The first data pointer in the sequence contains the address header
if (seqData.size() < 1) return;
sdv::pointer<uint8_t> rptrAddress = std::move(seqData.front());
seqData.erase(seqData.begin());
// The data should be at least the size of the header.
if (rptrAddress.size() < sizeof(sdv::ps::SMarshallAddress)) return; // Invalid size
// Deserialize the address portion of the header
// The first byte in the data pointer determines the endianness
sdv::EEndian eSourceEndianess = static_cast<sdv::EEndian>(rptrAddress[0]);
// Deserialize the address structure
sdv::ps::SMarshallAddress sAddress{};
if (eSourceEndianess == sdv::EEndian::big_endian)
{
sdv::deserializer<sdv::EEndian::big_endian> desInput;
desInput.attach(rptrAddress, 0); // Do not check checksum...
serdes::CSerdes<sdv::ps::SMarshallAddress>::Deserialize(desInput, sAddress);
} else
{
sdv::deserializer<sdv::EEndian::little_endian> desInput;
desInput.attach(rptrAddress, 0); // Do not check checksum...
serdes::CSerdes<sdv::ps::SMarshallAddress>::Deserialize(desInput, sAddress);
}
// If the data should be interprated as input data, the data should go into a stub object.
// If the data should be interprated as output data, the data is returning from the call and should go into the proxy object.
if (sAddress.eInterpret == sdv::ps::EMarshallDataInterpret::input_data)
{
// A proxy ID should be present in any case - if not, this is a serious error, since it is not possible to inform the
// caller.
if (!sAddress.tProxyID) return;
// In case the stub ID is not provided, the stub ID is the ID of the initial marshall object
sdv::ps::TMarshallID tStubID = sAddress.tStubID;
if (!tStubID) tStubID = m_ptrInitialMarshallObject->GetMarshallID();
// Store the channel context (used to marshall interfaces over the same connector)
m_rcontrol.SetConnectorContext(this);
// Call the stub function
sdv::sequence<sdv::pointer<uint8_t>> seqResult;
try
{
seqResult = m_rcontrol.CallStub(tStubID, seqData);
}
catch (...)
{
// Should not occur.
std::cout << "Exception occurred..." << std::endl;
}
// Store the address struct into the result sequence
sAddress.eInterpret = sdv::ps::EMarshallDataInterpret::output_data;
if (eSourceEndianess == sdv::EEndian::big_endian)
{
sdv::serializer<sdv::EEndian::big_endian> serOutput;
serdes::CSerdes<sdv::ps::SMarshallAddress>::Serialize(serOutput, sAddress);
seqResult.insert(seqResult.begin(), serOutput.buffer());
} else
{
sdv::serializer<sdv::EEndian::little_endian> serOutput;
serdes::CSerdes<sdv::ps::SMarshallAddress>::Serialize(serOutput, sAddress);
seqResult.insert(seqResult.begin(), serOutput.buffer());
}
// Send the result back
m_pDataSend->SendData(seqResult);
} else
{
// Look for the call entry
std::unique_lock<std::mutex> lockCallMap(m_mtxCalls);
auto itCall = m_mapCalls.find(sAddress.uiCallIndex);
if (itCall == m_mapCalls.end()) return;
SCallEntry& rsCallEntry = itCall->second;
m_mapCalls.erase(itCall);
lockCallMap.unlock();
// Update the result
std::unique_lock<std::mutex> lockCall(rsCallEntry.mtxWaitForResult);
rsCallEntry.seqResult = seqData;
lockCall.unlock();
rsCallEntry.cvWaitForResult.notify_all();
}
}
sdv::sequence<sdv::pointer<uint8_t>> CChannelConnector::MakeCall(sdv::ps::TMarshallID tProxyID, sdv::ps::TMarshallID tStubID,
sdv::sequence<sdv::pointer<uint8_t>>& rseqInputData)
{
if (!m_pDataSend) throw sdv::ps::XMarshallNotInitialized();
// Create an address structure
sdv::ps::SMarshallAddress sAddress{};
sAddress.eEndian = sdv::GetPlatformEndianess();
sAddress.uiVersion = SDVFrameworkInterfaceVersion;
sAddress.tProxyID = tProxyID;
sAddress.tStubID = tStubID;
sAddress.uiCallIndex = m_rcontrol.CreateUniqueCallIndex();
sAddress.eInterpret = sdv::ps::EMarshallDataInterpret::input_data;
// Create an additional stream for the address struct.
sdv::serializer serAddress;
serdes::CSerdes<sdv::ps::SMarshallAddress>::Serialize(serAddress, sAddress);
rseqInputData.insert(rseqInputData.begin(), serAddress.buffer());
// Add a call entry to be able to receive the result.
std::unique_lock<std::mutex> lock(m_mtxCalls);
SCallEntry sResult;
m_mapCalls.try_emplace(sAddress.uiCallIndex, sResult);
lock.unlock();
// Store the channel context (used to marshall interfaces over the same connector)
m_rcontrol.SetConnectorContext(this);
// Send the data
try
{
if (!m_pDataSend->SendData(rseqInputData)) throw sdv::ps::XMarshallExcept();
}
catch (const sdv::ps::XMarshallExcept& /*rexcept*/)
{
// Exception occurred. Remove the call und rethrow.
lock.lock();
m_mapCalls.erase(sAddress.uiCallIndex);
lock.unlock();
throw;
}
// Wait for the result
if (sResult.bCancel) throw sdv::ps::XMarshallTimeout();
std::unique_lock<std::mutex> lockResult(sResult.mtxWaitForResult);
sResult.cvWaitForResult.wait(lockResult);
if (sResult.bCancel) throw sdv::ps::XMarshallTimeout();
return sResult.seqResult;
}
std::shared_ptr<CMarshallObject> CChannelConnector::GetOrCreateProxy(sdv::interface_id id, sdv::ps::TMarshallID tStubID)
{
std::unique_lock<std::recursive_mutex> lock(m_mtxMarshallObjects);
// Check for an existing proxy.
auto itMarshallObject = m_mapProxyObjects.find(tStubID);
if (itMarshallObject != m_mapProxyObjects.end())
return itMarshallObject->second;
// Proxy doesn't exist; create a new proxy.
auto ptrMarshallObject = m_rcontrol.CreateProxy(id, tStubID, *this);
if (!ptrMarshallObject)return {};
m_mapProxyObjects[tStubID] = ptrMarshallObject;
return ptrMarshallObject;
}
sdv::com::TConnectionID CChannelConnector::GetConnectionID() const
{
return m_tConnectionID;
}

View File

@@ -0,0 +1,139 @@
#ifndef COM_CHANNEL_H
#define COM_CHANNEL_H
#include <support/pssup.h>
#include <interfaces/ipc.h>
#include "../../global/scheduler/scheduler.h"
// Forward declaration
class CCommunicationControl;
class CMarshallObject;
/**
* @brief Communication channel connector (endpoint).
*/
class CChannelConnector : public sdv::IInterfaceAccess, public sdv::ipc::IConnectEventCallback,
public sdv::ipc::IDataReceiveCallback
{
public:
/**
* @brief Constructor for establishing the server connection.
* @param[in] rcontrol Reference to the communication control class.
* @param[in] uiIndex The current index of this connection (used to create the connection ID).
* @param[in] pChannelEndpoint Interface pointer to the channel.
*/
CChannelConnector(CCommunicationControl& rcontrol, uint32_t uiIndex, sdv::IInterfaceAccess* pChannelEndpoint);
/**
* @brief Destructor
*/
~CChannelConnector();
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(sdv::ipc::IDataReceiveCallback)
SDV_INTERFACE_ENTRY(sdv::ipc::IConnectEventCallback)
END_SDV_INTERFACE_MAP()
/**
* @brief Connect as server (attaching the channel to the target object using a stub).
* @param[in] pObject Pointer to the object to attach.
* @param[in] bAllowReconnect Allow a disconnect and re-connect (disconnect doesn't trigger a channel removal).
* @return Returns 'true' when the attachment succeeds; 'false' when not.
*/
bool ServerConnect(sdv::IInterfaceAccess* pObject, bool bAllowReconnect);
/**
* @brief Connect as client (connecting to an existing server and creating a proxy).
* @param[in] uiTimeoutMs The timeout time trying to connect.
* @return Returns a pointer to the proxy object representing the object at the other end of the channel. Or NULL when a
* timeout occurred.
*/
sdv::IInterfaceAccess* ClientConnect(uint32_t uiTimeoutMs);
/**
* @brief Is the communication channel currently connected?
* @return Returns whether the connector has an active connection.
*/
bool IsConnected() const;
/**
* @brief Set the current status. Overload of sdv::ipc::IConnectEventCallback::SetStatus.
* @param[in] eConnectStatus The connection status.
*/
virtual void SetStatus(/*in*/ sdv::ipc::EConnectStatus eConnectStatus) override;
/**
* @brief Callback to be called by the IPC connection when receiving a data packet. Overload of
* sdv::ipc::IDataReceiveCallback::ReceiveData.
* @param[inout] seqData Sequence of data buffers to received. The sequence might be changed to optimize the communication
* without having to copy the data.
*/
virtual void ReceiveData(/*inout*/ sdv::sequence<sdv::pointer<uint8_t>>& seqData) override;
/**
* @brief Decoupled receive callback to be called by the scheduler when receiving a data packet.
* @param[inout] seqData Sequence of data buffers to received. The sequence might be changed to optimize the communication
* without having to copy the data.
*/
void DecoupledReceiveData(/*inout*/ sdv::sequence<sdv::pointer<uint8_t>>& seqData);
/**
* @brief Sends data consisting of multiple data chunks via the IPC connection.
* @param[in] tProxyID Marshall ID of the proxy (source).
* @param[in] tStubID Marshall ID of the stub (target).
* @param[in] rseqInputData Sequence of data buffers to be sent. May be altered during processing to add/change the sequence content
* without having to copy the data.
* @return Returns the results of the call or throws a marshall exception.
*/
sdv::sequence<sdv::pointer<uint8_t>> MakeCall(sdv::ps::TMarshallID tProxyID, sdv::ps::TMarshallID tStubID,
sdv::sequence<sdv::pointer<uint8_t>>& rseqInputData);
/**
* @brief Get a proxy for the interface connection to the stub.
* @param[in] id The ID of the interface this object marshalls the calls for.
* @param[in] tStubID The stub ID this proxy is communicating to.
* @return Returns a shared pointer to the proxy object.
*/
std::shared_ptr<CMarshallObject> GetOrCreateProxy(sdv::interface_id id, sdv::ps::TMarshallID tStubID);
/**
* @brief Get the connection ID of this connector.
* @return The connection ID.
*/
sdv::com::TConnectionID GetConnectionID() const;
private:
/**
* @brief Endpoint type the channel connector
*/
enum class EEndpointType {server, client};
/**
* @brief Call entry structure that is defined for a call to wait for the result.
*/
struct SCallEntry
{
sdv::sequence<sdv::pointer<uint8_t>> seqResult; ///< The result data.
std::mutex mtxWaitForResult; ///< Mutex to protect result processing.
std::condition_variable cvWaitForResult; ///< Condition variable to trigger result processing.
bool bCancel = false; ///< Cancel processing when set.
};
CCommunicationControl& m_rcontrol; ///< Reference to the communication control class.
sdv::TObjectPtr m_ptrChannelEndpoint; ///< Managed pointer to the channel endpoint.
uint64_t m_uiConnectionStatusCookie = 0; ///< Connection status cookie (received after registration).
std::shared_ptr<CMarshallObject> m_ptrInitialMarshallObject; ///< Initial marshall object used after a connect event.
sdv::ipc::EConnectStatus m_eConnectStatus = sdv::ipc::EConnectStatus::uninitialized; ///< Current connection status.
bool m_bAllowReconnect = false; ///< When set, allow reconnection of the server.
EEndpointType m_eEndpointType = EEndpointType::client; ///< Endpoint type of this connector.
std::recursive_mutex m_mtxMarshallObjects; ///< Synchronize access to the marshall object vector.
std::map<sdv::ps::TMarshallID, std::shared_ptr<CMarshallObject>> m_mapProxyObjects; ///< Map of stub IDs to proxy objects
sdv::com::TConnectionID m_tConnectionID{}; ///< Connection ID for this connector.
sdv::ipc::IDataSend* m_pDataSend = nullptr; ///< Pointer to the send interface.
std::mutex m_mtxCalls; ///< Call map protection.
std::map<uint64_t, SCallEntry&> m_mapCalls; ///< call map.
CTaskScheduler m_scheduler; ///< Scheduler to process incoming calls.
};
#endif // !defined COM_CHANNEL_H

View File

@@ -0,0 +1,322 @@
#include "com_ctrl.h"
#include <interfaces/ipc.h>
#include <support/toml.h>
#include "com_channel.h"
#include "marshall_object.h"
thread_local CChannelConnector* CCommunicationControl::m_pConnectorContext = nullptr;
CCommunicationControl::CCommunicationControl()
{
std::srand(static_cast<unsigned int>(std::time(nullptr)));
}
CCommunicationControl::~CCommunicationControl()
{}
void CCommunicationControl::Initialize(const sdv::u8string& /*ssObjectConfig*/)
{
m_eObjectStatus = sdv::EObjectStatus::initialized;
}
sdv::EObjectStatus CCommunicationControl::GetStatus() const
{
return m_eObjectStatus;
}
void CCommunicationControl::SetOperationMode(sdv::EOperationMode eMode)
{
switch (eMode)
{
case sdv::EOperationMode::configuring:
if (m_eObjectStatus == sdv::EObjectStatus::running || m_eObjectStatus == sdv::EObjectStatus::initialized)
m_eObjectStatus = sdv::EObjectStatus::configuring;
break;
case sdv::EOperationMode::running:
if (m_eObjectStatus == sdv::EObjectStatus::configuring || m_eObjectStatus == sdv::EObjectStatus::initialized)
m_eObjectStatus = sdv::EObjectStatus::running;
break;
default:
break;
}
}
void CCommunicationControl::Shutdown()
{
m_eObjectStatus = sdv::EObjectStatus::shutdown_in_progress;
// Wait for threads to terminate... in case one is still running
// (use a copy to prevent circular access)
std::unique_lock<std::mutex> lock(m_mtxChannels);
auto vecInitialConnectMon = std::move(m_vecInitialConnectMon);
lock.unlock();
for (std::thread& rthread : vecInitialConnectMon)
{
if (rthread.joinable())
rthread.join();
}
vecInitialConnectMon.clear();
// Clear the channels and remove the stub objects (use a copy to prevent circular access)
lock.lock();
auto vecChannels = std::move(m_vecChannels);
auto mapStubObjects = std::move(m_mapStubObjects);
lock.unlock();
vecChannels.clear();
mapStubObjects.clear();
m_eObjectStatus = sdv::EObjectStatus::destruction_pending;
}
sdv::com::TConnectionID CCommunicationControl::CreateServerConnection(/*in*/ sdv::com::EChannelType eChannelType,
/*in*/ sdv::IInterfaceAccess* pObject, /*in*/ uint32_t uiTimeoutMs, /*out*/ sdv::u8string& ssConnectionString)
{
std::string ssChannelServer;
switch (eChannelType)
{
case sdv::com::EChannelType::local_channel:
ssChannelServer = "LocalChannelControl";
break;
case sdv::com::EChannelType::remote_channel:
ssChannelServer = "RemoteChannelControl";
break;
default:
return {};
}
// Create the channel endpoint
sdv::ipc::ICreateEndpoint* pEndpoint = sdv::core::GetObject<sdv::ipc::ICreateEndpoint>(ssChannelServer);
if (!pEndpoint)
{
SDV_LOG_ERROR("No channel control!");
return {};
}
// Create a standard endpoint
sdv::ipc::SChannelEndpoint sEndpoint = pEndpoint->CreateEndpoint("");
if (!sEndpoint.pConnection)
{
SDV_LOG_ERROR("Could not create the endpoint!");
return {};
}
// Manage the channel endpoint object
sdv::TObjectPtr ptrChannelEndpoint(sEndpoint.pConnection);
// Manage the endpoint connection object.
sdv::com::TConnectionID tConnectionID = AssignServerEndpoint(ptrChannelEndpoint, pObject, uiTimeoutMs, false);
if (!tConnectionID.uiControl) return {};
ssConnectionString = sEndpoint.ssConnectString;
return tConnectionID;
}
sdv::com::TConnectionID CCommunicationControl::CreateClientConnection(/*in*/ const sdv::u8string& ssConnectionString,
/*in*/ uint32_t uiTimeoutMs, /*out*/ sdv::IInterfaceAccess*& pProxy)
{
pProxy = nullptr;
// The channel connection string contains the nme of the provider
sdv::toml::CTOMLParser parser(ssConnectionString);
if (!parser.IsValid()) return {};
std::string ssProvider = parser.GetDirect("Provider.Name").GetValue();
// Get the channel access interface
sdv::ipc::IChannelAccess* pChannelAccess = sdv::core::GetObject<sdv::ipc::IChannelAccess>(ssProvider);
if (!pChannelAccess)
{
SDV_LOG_ERROR("No channel control!");
return {};
}
// Create the endpoint and establish the channel
sdv::TObjectPtr ptrChannelEndpoint(pChannelAccess->Access(ssConnectionString));
return AssignClientEndpoint(ptrChannelEndpoint, uiTimeoutMs, pProxy);
}
sdv::com::TConnectionID CCommunicationControl::AssignServerEndpoint(/*in*/ sdv::IInterfaceAccess* pChannelEndpoint,
/*in*/ sdv::IInterfaceAccess* pObject, /*in*/ uint32_t uiTimeoutMs, /*in*/ bool bAllowReconnect)
{
if (!pChannelEndpoint || !pObject || !(uiTimeoutMs || bAllowReconnect)) return {};
// Create a communication channel object
std::unique_lock<std::mutex> lock(m_mtxChannels);
auto ptrCommunication = std::make_shared<CChannelConnector>(*this, static_cast<uint32_t>(m_vecChannels.size()), pChannelEndpoint);
// Ignore cppcheck warning; normally the returned pointer should always have a value at this stage (otherwise an
// exception was triggered).
// cppcheck-suppress knownConditionTrueFalse
if (!ptrCommunication)
{
SDV_LOG_ERROR("Failed to allocate SDV communication channel!");
return {};
}
// Start the connection
if (!ptrCommunication->ServerConnect(pObject, bAllowReconnect)) return {};
// Add the channel to the vector
m_vecChannels.push_back(ptrCommunication);
//// If reconnect is not allowed and if not already connected, start the monitor...
//if (!bAllowReconnect && !ptrCommunication->IsConnected())
// m_vecInitialConnectMon.emplace_back([&]()
// {
// auto ptrLocalChannel = ptrCommunication;
// auto tpStart = std::chrono::high_resolution_clock::now();
// while (!ptrLocalChannel->IsConnected())
// {
// std::this_thread::sleep_for(std::chrono::milliseconds(10));
// if (std::chrono::duration_cast<std::chrono::milliseconds>(
// std::chrono::high_resolution_clock::now() - tpStart).count() >
// uiTimeoutMs) break;
// }
// if (!ptrLocalChannel->IsConnected())
// RemoveChannelConnector(ptrLocalChannel.get());
// });
// Done!
return ptrCommunication->GetConnectionID();
}
sdv::com::TConnectionID CCommunicationControl::AssignClientEndpoint(/*in*/ sdv::IInterfaceAccess* pChannelEndpoint,
/*in*/ uint32_t uiTimeoutMs, /*out*/ sdv::IInterfaceAccess*& pProxy)
{
pProxy = nullptr;
// Create a communication channel object
std::unique_lock<std::mutex> lock(m_mtxChannels);
auto ptrCommunication =
std::make_shared<CChannelConnector>(*this, static_cast<uint32_t>(m_vecChannels.size()), pChannelEndpoint);
// Ignore cppcheck warning; normally the returned pointer should always have a value at this stage (otherwise an
// exception was triggered).
// cppcheck-suppress knownConditionTrueFalse
if (!ptrCommunication)
{
SDV_LOG_ERROR("Failed to allocate SDV communication channel!");
return {};
}
// Start the connection
pProxy = ptrCommunication->ClientConnect(uiTimeoutMs);
if (!pProxy)
{
SDV_LOG_ERROR("Could not connect client!");
return {};
}
// Add the channel to the vector
m_vecChannels.push_back(ptrCommunication);
return ptrCommunication->GetConnectionID();
}
void CCommunicationControl::RemoveConnection(/*in*/ const sdv::com::TConnectionID& tConnectionID)
{
// Clear the vector entry.
std::unique_lock<std::mutex> lock(m_mtxChannels);
std::shared_ptr<CChannelConnector> ptrChannelsCopy;
if (tConnectionID.uiIdent < m_vecChannels.size())
{
ptrChannelsCopy = m_vecChannels[tConnectionID.uiIdent]; // Keep the channel alive while clearing the vector entry.
m_vecChannels[tConnectionID.uiIdent].reset(); // Only clear the pointer; do not remove the entry (this would mix up IDs).
}
lock.unlock();
// Clear the channel.
ptrChannelsCopy.reset();
}
sdv::interface_t CCommunicationControl::GetProxy(/*in*/ const sdv::ps::TMarshallID& tStubID, /*in*/ sdv::interface_id id)
{
if (!m_pConnectorContext) return {};
// Get the proxy
std::shared_ptr<CMarshallObject> ptrProxy = m_pConnectorContext->GetOrCreateProxy(id, tStubID);
if (!ptrProxy) return {};
return ptrProxy->GetProxy();
}
sdv::ps::TMarshallID CCommunicationControl::GetStub(/*in*/ sdv::interface_t ifc)
{
// Get the stub
auto ptrStub = GetOrCreateStub(ifc);
if (!ptrStub) return {};
return ptrStub->GetMarshallID();
}
std::shared_ptr<CMarshallObject> CCommunicationControl::CreateProxy(sdv::interface_id id, sdv::ps::TMarshallID tStubID,
CChannelConnector& rConnector)
{
std::unique_lock<std::recursive_mutex> lock(m_mtxObjects);
// Create the marshall object.
size_t nIndex = m_vecMarshallObjects.size();
auto ptrMarshallObject = std::make_shared<CMarshallObject>(*this);
// Ignore cppcheck warning; normally the returned pointer should always have a value at this stage (otherwise an
// exception was triggered).
// cppcheck-suppress knownConditionTrueFalse
if (!ptrMarshallObject)
return {};
m_vecMarshallObjects.push_back(ptrMarshallObject);
if (!ptrMarshallObject->InitializeAsProxy(static_cast<uint32_t>(nIndex), id, tStubID, rConnector))
ptrMarshallObject.reset();
if (!ptrMarshallObject) return {};
return ptrMarshallObject;
}
std::shared_ptr<CMarshallObject> CCommunicationControl::GetOrCreateStub(sdv::interface_t ifc)
{
if (!ifc) return {};
std::unique_lock<std::recursive_mutex> lock(m_mtxObjects);
// TODO: Check the proxy list if the interface is a proxy object. If so, get the corresponding stub ID instead of creating
// another stub object.
// If not existing, add an empty object in the map.
auto itMarshallObject = m_mapStubObjects.find(ifc);
if (itMarshallObject == m_mapStubObjects.end())
{
auto prMarshallObject = m_mapStubObjects.try_emplace(ifc, std::make_shared<CMarshallObject>(*this));
if (!prMarshallObject.second) return {};
itMarshallObject = prMarshallObject.first;
size_t nIndex = m_vecMarshallObjects.size();
m_vecMarshallObjects.push_back(itMarshallObject->second);
if (!itMarshallObject->second->InitializeAsStub(static_cast<uint32_t>(nIndex), ifc))
itMarshallObject->second.reset();
}
return itMarshallObject->second;
}
uint64_t CCommunicationControl::CreateUniqueCallIndex()
{
// Return the next call count.
return m_uiCurrentCallCnt++;
}
void CCommunicationControl::SetConnectorContext(CChannelConnector* pConnectorContext)
{
// Store the current channel for this thread (needed during the proxy creation).
m_pConnectorContext = pConnectorContext;
}
sdv::sequence<sdv::pointer<uint8_t>> CCommunicationControl::CallStub(sdv::ps::TMarshallID tStubID,
sdv::sequence<sdv::pointer<uint8_t>>& seqInputData)
{
// Find stub and call the function
std::unique_lock<std::recursive_mutex> lock(m_mtxObjects);
if (tStubID.uiIdent >= m_vecMarshallObjects.size()) throw sdv::ps::XMarshallIntegrity();
auto ptrMarshallObject = m_vecMarshallObjects[tStubID.uiIdent].lock();
lock.unlock();
// Check for a valid object
if (!ptrMarshallObject) throw sdv::ps::XMarshallIntegrity();
if (ptrMarshallObject->GetMarshallID() != tStubID) throw sdv::ps::XMarshallIntegrity();
// Make the call
return ptrMarshallObject->Call(seqInputData);
}

View File

@@ -0,0 +1,209 @@
#ifndef COM_CTRL_H
#define COM_CTRL_H
#include <support/pssup.h>
#include <support/component_impl.h>
#include <interfaces/com.h>
// Forward declaration
class CChannelConnector;
class CMarshallObject;
/**
* @brief Test object simulating an component isolation service implementation for channel implementation testing
*/
class CCommunicationControl : public sdv::CSdvObject, public sdv::IObjectControl, public sdv::com::IConnectionControl,
public sdv::ps::IMarshallAccess
{
public:
/**
* @brief Constructor.
*/
CCommunicationControl();
/**
* @brief Destructor added to cleanly stop service in case process is stopped (without shutdown via repository service)
*/
virtual ~CCommunicationControl() override;
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(sdv::ps::IMarshallAccess)
SDV_INTERFACE_ENTRY(sdv::com::IConnectionControl)
SDV_INTERFACE_ENTRY(sdv::IObjectControl)
END_SDV_INTERFACE_MAP()
// Component declarations
DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::SystemObject)
DECLARE_OBJECT_SINGLETON()
DECLARE_OBJECT_CLASS_NAME("CommunicationControl")
/**
* @brief Initialize the object. Overload of sdv::IObjectControl::Initialize.
* @param[in] ssObjectConfig Optional configuration string.
*/
virtual void Initialize(const sdv::u8string& ssObjectConfig) override;
/**
* @brief Get the current status of the object. Overload of sdv::IObjectControl::GetStatus.
* @return Return the current status of the object.
*/
virtual sdv::EObjectStatus GetStatus() const override;
/**
* @brief Set the component operation mode. Overload of sdv::IObjectControl::SetOperationMode.
* @param[in] eMode The operation mode, the component should run in.
*/
void SetOperationMode(sdv::EOperationMode eMode) override;
/**
* @brief Shutdown called before the object is destroyed. Overload of sdv::IObjectControl::Shutdown.
*/
virtual void Shutdown() override;
/**
* @brief Create an IPC channel endpoint and use it for SDV communication. Overload of
* sdv::com::IConnectionControl::CreateServerConnection.
* @remarks The channel will be destroyed automatically when a timeout occurs (no initial connection took place within the
* specified time).
* @remarks The function doesn't wait until a connection has been made, but returns straight after the channel creation.
* @param[in] eChannelType Type of channel to create. Must be local or remote.
* @param[in] pObject Initial object to start the communication with.
* @param[in] uiTimeoutMs Timeout for waiting for a connection.
* @param[out] ssConnectionString String describing the connection details to connect to this channel.
* @return Channel connection ID if successful or 0 if not.
*/
virtual sdv::com::TConnectionID CreateServerConnection(/*in*/ sdv::com::EChannelType eChannelType,
/*in*/ sdv::IInterfaceAccess* pObject, /*in*/ uint32_t uiTimeoutMs, /*out*/ sdv::u8string& ssConnectionString) override;
/**
* @brief Connect to an SDV channel (an IPC channel managed by the channel control and waiting for an initial connection.
* Overload of sdv::com::IConnectionControl::CreateClientConnection.
* @remarks The connection will be destroyed automatically when a timeout occurs (no initial connection took place within
* the specified time).
* @param[in] ssConnectionString The string describing the connection details.
* @param[in] uiTimeoutMs Timeout for waiting for a connection.
* @param[out] pProxy Pointer to the object representing the remote object (a proxy to the remote object). Or nullptr
* when a timeout occurred.
* @return Channel connection ID if successful or 0 if not.
*/
virtual sdv::com::TConnectionID CreateClientConnection(/*in*/ const sdv::u8string& ssConnectionString,
/*in*/ uint32_t uiTimeoutMs, /*out*/ sdv::IInterfaceAccess*& pProxy) override;
/**
* @brief Assign and take over an already initialized IPC channel server endpoint for use with SDV communication. Overload of
* sdv::com::IConnectionControl::AssignServerEndpoint.
* @remarks The channel will be destroyed automatically when a timeout occurs (no initial connection took place within the
* specified time) unless the flag bAllowReconnect has been set.
* @remarks The channel uses the interface sdv::IObjectLifetime to control the lifetime of the channel. If IObjectLifetime is
* not available, IObjectDestroy will be used.
* @remarks The function doesn't wait until a connection has been made, but returns straight after the assignment.
* @param[in] pChannelEndpoint Pointer to the channel endpoint to be assigned.
* @param[in] pObject Initial object to start the communication with.
* @param[in] uiTimeoutMs Timeout for waiting for an initial connection. Not used when the bAllowReconnect flag has been set.
* @param[in] bAllowReconnect When set, the channel is allowed to be disconnected and reconnected again.
* @return Channel connection ID if successful or 0 if not.
*/
virtual sdv::com::TConnectionID AssignServerEndpoint(/*in*/ sdv::IInterfaceAccess* pChannelEndpoint,
/*in*/ sdv::IInterfaceAccess* pObject, /*in*/ uint32_t uiTimeoutMs, /*in*/ bool bAllowReconnect) override;
/**
* @brief Assign and take over an already initialized IPC channel client endpoint for use with SDV communication. Overload of
* sdv::com::IConnectionControl::AssignClientEndpoint.
* @remarks The connection will be destroyed automatically when a timeout occurs (no initial connection took place
* within the specified time).
* @remarks The channel uses the interface sdv::IObjectLifetime to control the lifetime of the channel. If
* IObjectLifetime is not available, IObjectDestroy will be used.
* @param[in] pChannelEndpoint Pointer to the channel endpoint to be assigned.
* @param[in] uiTimeoutMs Timeout for waiting for an initial connection. Not used when the bAllowReconnect flag has
* been set.
* @param[out] pProxy Pointer to the object representing the remote object (a proxy to the remote object). Or nullptr
* when a timeout occurred.
* @return Channel connection ID if successful or 0 if not.
*/
virtual sdv::com::TConnectionID AssignClientEndpoint(/*in*/ sdv::IInterfaceAccess* pChannelEndpoint,
/*in*/ uint32_t uiTimeoutMs, /*out*/ sdv::IInterfaceAccess*& pProxy) override;
/**
* @brief Remove a connection with the provided connection ID. Overload of sdv::com::IConnectionControl::RemoveConnection.
* @param[in] tConnectionID The connection ID of the connection to remove.
*/
virtual void RemoveConnection(/*in*/ const sdv::com::TConnectionID& tConnectionID) override;
/**
* @brief Get a proxy for the interface connection to the stub. Overload of sdv::ps::IMarshallAcess::GetProxy.
* @param[in] tStubID Reference to the ID of the stub to connect to.
* @param[in] id The interface ID to get the proxy for.
* @return Returns the interface to the proxy object.
*/
virtual sdv::interface_t GetProxy(/*in*/ const sdv::ps::TMarshallID& tStubID, /*in*/ sdv::interface_id id) override;
/**
* @brief Get a stub for the interface with the supplied ID. Overload of sdv::ps::IMarshallAcess::GetStub.
* @param[in] ifc The interface to get the stub for..
* @return Returns the Stub ID that is assigned to the interface. Or an empty ID when no stub could be found.
*/
virtual sdv::ps::TMarshallID GetStub(/*in*/ sdv::interface_t ifc) override;
/**
* @brief Create a proxy for the interface connection to the stub.
* @remarks Unlike stubs, which are unique for the process they run in, proxy objects are unique within the channel they are
* used - using the identification of the stub ID of the process the call. The proxy object is not stored here; just created.
* @param[in] id The ID of the interface this object marshalls the calls for.
* @param[in] tStubID The stub ID this proxy is communicating to.
* @param[in] rConnector Reference to channel connector.
* @return Returns a shared pointer to the proxy object.
*/
std::shared_ptr<CMarshallObject> CreateProxy(sdv::interface_id id, sdv::ps::TMarshallID tStubID,
CChannelConnector& rConnector);
/**
* @brief Get a stub for the interface with the supplied ID. Overload of sdv::ps::IMarshallAcess::GetStub.
* @param[in] ifc The interface to get the stub for..
* @return Returns the Stub ID that is assigned to the interface. Or an empty ID when no stub could be found.
*/
std::shared_ptr<CMarshallObject> GetOrCreateStub(sdv::interface_t ifc);
/**
* @brief To identify the send and receive packets belonging to one call, the call is identified with a unique index, which
* is created here.
* @return The unique call index.
*/
uint64_t CreateUniqueCallIndex();
/**
* @brief Set the channel connector context for the current thread. This is used to marshall interfaces over the same connector.
* @param[in] pConnectorContext Pointer to the connector currently being used.
*/
void SetConnectorContext(CChannelConnector* pConnectorContext);
/**
* @brief Call the stub function.
* @remarks This function call is synchronous and does not return until the call has been finalized or a timeout
* exception has occurred.
* @remarks The sequence contains all data to make the call. It is important that the data in the sequence is
* complete and in the correct order.
* @param[in] tStubID ID of the stub to call.
* @param[inout] seqInputData Reference to sequence of input data pointers. The first data pointer contains the
* marshalling header. The second contains the parameters (if available) and the others contain raw data pointers
* (if available). The call is allowed to change the sequence to be able to add additional information during the
* communication without having to copy the existing data.
* @return Sequence of output data pointers. The first data pointer contains the marshalling header. The second
* contains the return value and parameters (if available) and the others contain raw data pointers (if available).
*/
sdv::sequence<sdv::pointer<uint8_t>> CallStub(sdv::ps::TMarshallID tStubID, sdv::sequence<sdv::pointer<uint8_t>>& seqInputData);
private:
sdv::EObjectStatus m_eObjectStatus = sdv::EObjectStatus::initialization_pending; ///< Object status.
std::mutex m_mtxChannels; ///< Protect the channel map.
std::vector<std::shared_ptr<CChannelConnector>> m_vecChannels; ///< Channel vector.
std::vector<std::thread> m_vecInitialConnectMon; ///< Initial connection monitor.
std::recursive_mutex m_mtxObjects; ///< Protect object vectors.
std::vector<std::weak_ptr<CMarshallObject>> m_vecMarshallObjects; ///< Vector with marshall objects; lifetime is handled by channel.
std::map<sdv::interface_t, std::shared_ptr<CMarshallObject>> m_mapStubObjects; ///< Map of interfaces to stub objects
std::atomic_uint64_t m_uiCurrentCallCnt = 0; ///< The current call count.
thread_local static CChannelConnector* m_pConnectorContext; ///< The current connector; variable local to each thread.
};
DEFINE_SDV_OBJECT(CCommunicationControl)
#endif // !defined COM_CTRL_H

View File

@@ -0,0 +1,176 @@
#include "marshall_object.h"
#include "com_ctrl.h"
#include <support/serdes.h>
#include "com_channel.h"
CMarshallObject::CMarshallObject(CCommunicationControl& rcontrol) : m_rcontrol(rcontrol)
{}
CMarshallObject::~CMarshallObject()
{
}
bool CMarshallObject::IsValid() const
{
return m_tMarshallID.uiControl ? true : false;
}
void CMarshallObject::Reset()
{
m_eType = EType::unknown;
m_tMarshallID = { 0, 0, 0, 0 };
m_pMarshall = nullptr;
m_tStubID = {};
m_ifcProxy = {};
m_pConnector = nullptr;
}
sdv::interface_t CMarshallObject::InitializeAsProxy(uint32_t uiProxyIndex, sdv::interface_id id,
sdv::ps::TMarshallID tStubID, CChannelConnector& rConnector)
{
m_eType = EType::proxy;
// Create marshall ID from index and a random number.
sdv::ps::TMarshallID tMarshallID = { 0, GetProcessID(), uiProxyIndex, static_cast<uint32_t>(rand()) };
// Get the stub creation interface from the repository
sdv::core::IRepositoryMarshallCreate* pMarshallCreate =
sdv::core::GetObject<sdv::core::IRepositoryMarshallCreate>("RepositoryService");
if (!pMarshallCreate)
{
Reset();
return {};
}
m_ptrMarshallObject = pMarshallCreate->CreateProxyObject(id);
if (!m_ptrMarshallObject)
{
Reset();
return {};
}
// Set the proxy ID and control value
sdv::ps::IMarshallObjectIdent* pObjectIdent = m_ptrMarshallObject.GetInterface<sdv::ps::IMarshallObjectIdent>();
if (!pObjectIdent)
{
Reset();
return {};
}
pObjectIdent->SetIdentification(tMarshallID);
// Set the connecting stub ID for this proxy and get the target interface that the proxy provides.
sdv::ps::IProxyControl* pProxyControl = m_ptrMarshallObject.GetInterface<sdv::ps::IProxyControl>();
if (!pProxyControl)
{
Reset();
return {};
}
m_tStubID = tStubID;
m_ifcProxy = pProxyControl->GetTargetInterface();
if (!m_ifcProxy)
{
Reset();
return {};
}
// Get the IMarshallLink on the proxy object interface to link to the proxy and connect to IDataSend...
sdv::ps::IMarshallLink* pMarshallLink = m_ptrMarshallObject.GetInterface<sdv::ps::IMarshallLink>();
if (!pMarshallLink)
{
Reset();
return {};
}
pMarshallLink->Link(this);
// Store the channel.
m_pConnector = &rConnector;
// Store the ID...
m_tMarshallID = tMarshallID;
return m_ifcProxy;
}
bool CMarshallObject::InitializeAsStub(uint32_t uiStubIndex, sdv::interface_t ifc)
{
if (!ifc) return false;
m_eType = EType::stub;
// Create marshall ID from index and a random number.
sdv::ps::TMarshallID tMarshallID = { 0, GetProcessID(), uiStubIndex, static_cast<uint32_t>(rand()) };
// Get the stub creation interface from the repository
sdv::core::IRepositoryMarshallCreate* pMarshallCreate =
sdv::core::GetObject<sdv::core::IRepositoryMarshallCreate>("RepositoryService");
if (!pMarshallCreate)
{
Reset();
return false;
}
m_ptrMarshallObject = pMarshallCreate->CreateStubObject(ifc.id());
if (!m_ptrMarshallObject)
{
Reset();
return false;
}
// Set the stub ID and control value
sdv::ps::IMarshallObjectIdent* pObjectIdent = m_ptrMarshallObject.GetInterface<sdv::ps::IMarshallObjectIdent>();
if (!pObjectIdent)
{
Reset();
return {};
}
pObjectIdent->SetIdentification(tMarshallID);
// Link the object to the stub.
sdv::ps::IStubLink* psStubLink = m_ptrMarshallObject.GetInterface<sdv::ps::IStubLink>();
if (!psStubLink)
{
Reset();
return false;
}
psStubLink->Link(ifc);
// Get the marshall interface
m_pMarshall = m_ptrMarshallObject.GetInterface<sdv::ps::IMarshall>();
if (!m_pMarshall)
{
Reset();
return false;
}
// Everything is successful. Store the ID...
m_tMarshallID = tMarshallID;
return true;
}
sdv::ps::TMarshallID CMarshallObject::GetMarshallID() const
{
return m_tMarshallID;
}
sdv::interface_t CMarshallObject::GetProxy()
{
return m_ifcProxy;
}
sdv::sequence<sdv::pointer<uint8_t>> CMarshallObject::Call(/*inout*/ sdv::sequence<sdv::pointer<uint8_t>>& seqInputData)
{
// Differentiate between proxy and stub processing
if (m_eType == EType::proxy)
{
// Make the call through the connector.
if (!m_pConnector) throw sdv::ps::XMarshallNotInitialized();
return m_pConnector->MakeCall(m_tMarshallID, m_tStubID, seqInputData);
}
else
{
// Make the call through the stored marshall object.
if (!m_pMarshall) throw sdv::ps::XMarshallNotInitialized();
return m_pMarshall->Call(seqInputData);
}
}

View File

@@ -0,0 +1,117 @@
#ifndef MARSHALL_OBJECT_H
#define MARSHALL_OBJECT_H
#include <interfaces/ipc.h>
#include <support/component_impl.h>
#include <support/interface_ptr.h>
#include <interfaces/core_ps.h>
// Forward declarations
class CCommunicationControl;
class CChannelConnector;
inline sdv::process::TProcessID GetProcessID()
{
static sdv::process::TProcessID tProcessID = 0;
if (!tProcessID)
{
const sdv::process::IProcessInfo* pProcessInfo = sdv::core::GetObject<sdv::process::IProcessInfo>("ProcessControlService");
if (!pProcessInfo) return 0;
tProcessID = pProcessInfo->GetProcessID();
}
return tProcessID;
}
/**
* @brief Storage class for a proxy or a stub object.
*/
class CMarshallObject : public sdv::ps::IMarshall
{
public:
/**
* @brief Constructor
* @param[in] rcontrol Reference to the communication control class.
*/
CMarshallObject(CCommunicationControl& rcontrol);
/**
* @brief Destructor
*/
~CMarshallObject();
/**
* @brief Is this a valid marshal object?
* @return Returns whether the marshal object is valid.
*/
bool IsValid() const;
/**
* @brief Reset the marshal object.
*/
void Reset();
/**
* @brief Initialize the marshall object as proxy.
* @param[in] uiProxyIndex The index of this proxy; becoming part of the Proxy ID.
* @param[in] id The ID of the interface this object marshalls the calls for.
* @param[in] tStubID The stub ID this proxy is communicating to.
* @param[in] rConnector Reference to channel connector.
* @return Returns a pointer to proxy interface or empty when the initialization failed.
*/
sdv::interface_t InitializeAsProxy(uint32_t uiProxyIndex, sdv::interface_id id, sdv::ps::TMarshallID tStubID,
CChannelConnector& rConnector);
/**
* @brief Initialize the marshall object as stub.
* @param[in] uiStubIndex The index of this stub; becoming part of the Stub ID.
* @param[in] ifc Interface to the object to be marshalled to.
* @return Returns 'true' when initialization was successful; 'false' when not.
*/
bool InitializeAsStub(uint32_t uiStubIndex, sdv::interface_t ifc);
/**
* @brief Return the proxy/stub ID.
* @details The marshall ID consist of an index to easily access the marshalling details and a control value to increase higher
* security. The control value is a randomly generated value used in the communication to check whether the marshall object ID
* is valid. Both index and control value must be known by the caller for the call to succeed. If one is wrong, the call won't
* be made.
* @return The ID of this marshall object.
*/
sdv::ps::TMarshallID GetMarshallID() const;
/**
* @brief Return the proxy to the interface.
* @return Proxy interface.
*/
sdv::interface_t GetProxy();
/**
* @brief Marshall a function call. Ovverload of sdv::ps::IMarshall::Call.
* @remarks This function call is synchronous and does not return until the call has been finalized or a timeout
* exception has occurred.
* @remarks The sequence contains all data to make the call. It is important that the data in the sequence is
* complete and in the correct order.
* @param[inout] seqInputData Reference to sequence of input data pointers. The first data pointer contains the
* marshalling header. The second contains the parameters (if available) and the others contain raw data pointers
* (if available). The call is allowed to change the sequence to be able to add additional information during the
* communication without having to copy the existing data.
* @return Sequence of output data pointers. The first data pointer contains the marshalling header. The second
* contains the return value and parameters (if available) and the others contain raw data pointers (if available).
*/
virtual sdv::sequence<sdv::pointer<uint8_t>> Call(/*inout*/ sdv::sequence<sdv::pointer<uint8_t>>& seqInputData) override;
private:
/// Marshall object type
enum class EType {unknown, proxy, stub};
CCommunicationControl& m_rcontrol; ///< Reference to the communication control class.
EType m_eType = EType::unknown; ///< Type of object.
sdv::ps::TMarshallID m_tMarshallID = {}; ///< The ID of this marshall object.
sdv::ps::IMarshall* m_pMarshall = nullptr; ///< The marshall object pointer (only used for a stub).
sdv::TObjectPtr m_ptrMarshallObject; ///< The marshall object.
sdv::ps::TMarshallID m_tStubID = {}; ///< Stub ID (only used for a proxy).
sdv::interface_t m_ifcProxy = {}; ///< Proxy interface (only used for a proxy).
CChannelConnector* m_pConnector = nullptr; ///< Pointer to the connector (only used for a proxy).
};
#endif // !defined MARSHALL_OBJECT_H