mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-08-30 04:15:10 +00:00
connection between 2 systems and bug fixes (#14)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
@@ -18,7 +19,7 @@
|
||||
#include <support/pssup.h>
|
||||
#include <interfaces/app.h>
|
||||
|
||||
CRepositoryProxy::CRepositoryProxy(CClient& rClient, sdv::com::TConnectionID tConnection,
|
||||
CRepositoryProxy::CRepositoryProxy(CClientConnect& rClient, sdv::com::TConnectionID tConnection,
|
||||
sdv::IInterfaceAccess* pRepositoryProxy) :
|
||||
m_rClient(rClient), m_tConnection(tConnection), m_ptrRepositoryProxy(pRepositoryProxy)
|
||||
{}
|
||||
@@ -26,120 +27,131 @@ CRepositoryProxy::CRepositoryProxy(CClient& rClient, sdv::com::TConnectionID tCo
|
||||
void CRepositoryProxy::DestroyObject()
|
||||
{
|
||||
// Call the client to disconnect the connection and destroy the object.
|
||||
m_rClient.Disconnect(m_tConnection);
|
||||
m_rClient.Disconnect();
|
||||
}
|
||||
|
||||
bool CClient::OnInitialize()
|
||||
sdv::com::TConnectionID CRepositoryProxy::GetConnectionID() const
|
||||
{
|
||||
return true;
|
||||
return m_tConnection;
|
||||
}
|
||||
|
||||
void CClient::OnShutdown()
|
||||
{
|
||||
sdv::com::IConnectionControl* pConnectionControl = sdv::core::GetObject<sdv::com::IConnectionControl>("CommunicationControl");
|
||||
if (!pConnectionControl)
|
||||
SDV_LOG_ERROR("Failed to get communication control!");
|
||||
|
||||
// Disconnect from all repositories
|
||||
std::unique_lock<std::mutex> lock(m_mtxRepositoryProxies);
|
||||
auto mapRepositoryProxiesCopy = std::move(m_mapRepositoryProxies);
|
||||
lock.unlock();
|
||||
if (pConnectionControl)
|
||||
{
|
||||
for (const auto& rvtRepository : mapRepositoryProxiesCopy)
|
||||
pConnectionControl->RemoveConnection(rvtRepository.first);
|
||||
}
|
||||
}
|
||||
|
||||
sdv::IInterfaceAccess* CClient::Connect(const sdv::u8string& ssConnectString)
|
||||
bool CClientConnect::OnInitialize()
|
||||
{
|
||||
const sdv::app::IAppContext* pContext = sdv::core::GetCore<sdv::app::IAppContext>();
|
||||
if (!pContext)
|
||||
{
|
||||
SDV_LOG_ERROR("Failed to get application context!");
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
sdv::com::IConnectionControl* pConnectionControl = sdv::core::GetObject<sdv::com::IConnectionControl>("CommunicationControl");
|
||||
if (!pConnectionControl)
|
||||
{
|
||||
SDV_LOG_ERROR("Failed to get communication control!");
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
sdv::ipc::IChannelAccess* pChannelAccess = nullptr;
|
||||
std::string ssConfig;
|
||||
try
|
||||
// Check for a provider. Without provider there is no object to use for listening.
|
||||
if (m_ssProvider.empty())
|
||||
{
|
||||
// Determine whether the service is running as server or as client.
|
||||
sdv::toml::CTOMLParser config(ssConnectString);
|
||||
std::string ssType = config.GetDirect("Client.Type").GetValue();
|
||||
if (ssType.empty()) ssType = "Local";
|
||||
if (ssType == "Local")
|
||||
{
|
||||
uint32_t uiInstanceID = config.GetDirect("Client.Instance").GetValue();
|
||||
pChannelAccess = sdv::core::GetObject<sdv::ipc::IChannelAccess>("LocalChannelControl");
|
||||
if (!pChannelAccess)
|
||||
{
|
||||
SDV_LOG_ERROR("No local channel control or channel control not configured as client!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ssConfig = std::string(R"code([IpcChannel]
|
||||
Name = "LISTENER_)code") + std::to_string(uiInstanceID ? uiInstanceID : pContext->GetInstanceID()) + R"code("
|
||||
)code";
|
||||
|
||||
}
|
||||
else if (ssType == "Remote")
|
||||
{
|
||||
std::string ssInterface = config.GetDirect("Client.Interface").GetValue();
|
||||
uint32_t uiPort = config.GetDirect("Client.Interface").GetValue();
|
||||
if (ssInterface.empty() || !uiPort)
|
||||
{
|
||||
SDV_LOG_ERROR("Missing interface or port number to initialize a remote client!");
|
||||
return nullptr;
|
||||
}
|
||||
pChannelAccess = sdv::core::GetObject<sdv::ipc::IChannelAccess>("RemoteChannelControl");
|
||||
if (!pChannelAccess)
|
||||
{
|
||||
SDV_LOG_ERROR("No remote channel control or channel control not configured as client!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ssConfig = R"code([IpcChannel]
|
||||
Interface = ")code" + ssInterface + R"code(
|
||||
Port = ")code" + std::to_string(uiPort) + R"code(
|
||||
)code";
|
||||
}
|
||||
else
|
||||
{
|
||||
SDV_LOG_ERROR("Invalid or missing listener configuration for listener service!");
|
||||
SetObjectIntoConfigErrorState();
|
||||
return nullptr;
|
||||
}
|
||||
SDV_LOG_ERROR("Missing provider name for creating a client object!");
|
||||
return false;
|
||||
}
|
||||
catch (const sdv::toml::XTOMLParseException& rexcept)
|
||||
sdv::ipc::IChannelAccess* pChannelAccess = sdv::core::GetObject<sdv::ipc::IChannelAccess>(m_ssProvider);
|
||||
if (!pChannelAccess)
|
||||
{
|
||||
SDV_LOG_ERROR("Invalid service configuration for listener service: ", rexcept.what(), "!");
|
||||
SetObjectIntoConfigErrorState();
|
||||
return nullptr;
|
||||
SDV_LOG_ERROR("Cannot instantiate provider '", m_ssProvider, "' for the creation of a client object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// The connection will be established in the Connect function.
|
||||
return true;
|
||||
}
|
||||
|
||||
void CClientConnect::OnShutdown()
|
||||
{
|
||||
sdv::com::IConnectionControl* pConnectionControl = sdv::core::GetObject<sdv::com::IConnectionControl>("CommunicationControl");
|
||||
if (!pConnectionControl)
|
||||
SDV_LOG_ERROR("Failed to get communication control!");
|
||||
|
||||
// Disconnect
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
bool CClientConnect::Connect()
|
||||
{
|
||||
sdv::u8string ssProvider;
|
||||
sdv::u8string ssConfig;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mtx);
|
||||
ssProvider = m_ssProvider;
|
||||
ssConfig = BuildObjectConfig();
|
||||
}
|
||||
|
||||
const sdv::app::IAppContext* pContext = sdv::core::GetCore<sdv::app::IAppContext>();
|
||||
if (!pContext)
|
||||
{
|
||||
SDV_LOG_ERROR("Failed to get application context!");
|
||||
return false;
|
||||
}
|
||||
sdv::com::IConnectionControl* pConnectionControl = sdv::core::GetObject<sdv::com::IConnectionControl>("CommunicationControl");
|
||||
if (!pConnectionControl)
|
||||
{
|
||||
SDV_LOG_ERROR("Failed to get communication control!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for a provider. Without provider there is no object to use for listening.
|
||||
if (ssProvider.empty())
|
||||
{
|
||||
SDV_LOG_ERROR("Missing provider name for creating a client object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
sdv::ipc::IChannelAccess* pChannelAccess = sdv::core::GetObject<sdv::ipc::IChannelAccess>(ssProvider);
|
||||
if (!pChannelAccess)
|
||||
{
|
||||
SDV_LOG_ERROR("Cannot instantiate provider '", m_ssProvider, "' for the creation of a client object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the repository
|
||||
sdv::TInterfaceAccessPtr ptrRespository = sdv::core::GetObject("RepositoryService");
|
||||
if (!ptrRespository)
|
||||
{
|
||||
SDV_LOG_ERROR("Failed to get repository service!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add a dependency of the provider to this service (to prevent the provider to be terminated while the service is still
|
||||
// running).
|
||||
sdv::core::IObjectDependency* pObjectDependency = ptrRespository.GetInterface<sdv::core::IObjectDependency>();
|
||||
if (!pObjectDependency)
|
||||
{
|
||||
SDV_LOG_ERROR("Failed to get the object dependency interface!");
|
||||
return false;
|
||||
}
|
||||
|
||||
pObjectDependency->AddObjectDependency(Self().ssName, ssProvider);
|
||||
|
||||
|
||||
// First access the listener channel. This allows us to access the channel creation interface.
|
||||
|
||||
// TODO: Use named mutex to prevent multiple connections at the same time.
|
||||
// Connect to the channel.
|
||||
sdv::TObjectPtr ptrListenerEndpoint = pChannelAccess->Access(ssConfig);
|
||||
|
||||
|
||||
// Assign the endpoint to the communication service.
|
||||
sdv::IInterfaceAccess* pListenerProxy = nullptr;
|
||||
sdv::com::TConnectionID tListenerConnection = pConnectionControl->AssignClientEndpoint(ptrListenerEndpoint, 5000,
|
||||
pListenerProxy);
|
||||
sdv::com::TConnectionID tListenerConnection =
|
||||
pConnectionControl->AssignClientEndpoint(ptrListenerEndpoint, 5000, pListenerProxy);
|
||||
ptrListenerEndpoint.Clear(); // Lifetime has been taken over by communication control.
|
||||
if (!tListenerConnection || !pListenerProxy)
|
||||
{
|
||||
SDV_LOG_ERROR("Could not assign the client endpoint!");
|
||||
if (tListenerConnection != sdv::com::TConnectionID{}) pConnectionControl->RemoveConnection(tListenerConnection);
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
sdv::TInterfaceAccessPtr ptrListenerProxy(pListenerProxy);
|
||||
|
||||
@@ -149,9 +161,26 @@ Port = ")code" + std::to_string(uiPort) + R"code(
|
||||
{
|
||||
SDV_LOG_ERROR("Could not get the channel creation interface!");
|
||||
if (tListenerConnection != sdv::com::TConnectionID{}) pConnectionControl->RemoveConnection(tListenerConnection);
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
sdv::u8string ssConnectionString = pRequestChannel->RequestChannel("");
|
||||
|
||||
sdv::u8string ssRequestConfig;
|
||||
|
||||
// Tunnel providers need the full object config so the private channel
|
||||
// can preserve provider-specific fields such as the tunnel name.
|
||||
// For shared memory we keep the legacy behavior and let the provider
|
||||
// create its own private channel details.
|
||||
if (ssProvider == "unix_domain_sockets_tunnel")
|
||||
{
|
||||
ssRequestConfig = ssConfig;
|
||||
}
|
||||
else
|
||||
{
|
||||
ssRequestConfig.clear();
|
||||
}
|
||||
|
||||
sdv::u8string ssConnectionString = pRequestChannel->RequestChannel(ssRequestConfig);
|
||||
|
||||
|
||||
// Disconnect from the listener
|
||||
if (tListenerConnection != sdv::com::TConnectionID{}) pConnectionControl->RemoveConnection(tListenerConnection);
|
||||
@@ -159,7 +188,7 @@ Port = ")code" + std::to_string(uiPort) + R"code(
|
||||
if (ssConnectionString.empty())
|
||||
{
|
||||
SDV_LOG_ERROR("Could not get the private channel connection information!");
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Use named mutex to prevent multiple connections at the same time.
|
||||
@@ -174,30 +203,64 @@ Port = ")code" + std::to_string(uiPort) + R"code(
|
||||
{
|
||||
SDV_LOG_ERROR("Could not assign the client endpoint to the private channel!");
|
||||
if (tPrivateConnection != sdv::com::TConnectionID{}) pConnectionControl->RemoveConnection(tPrivateConnection);
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a remote repository object
|
||||
std::unique_lock<std::mutex> lock(m_mtxRepositoryProxies);
|
||||
m_mapRepositoryProxies.try_emplace(tPrivateConnection, *this, tPrivateConnection, pPrivateProxy);
|
||||
m_ptrRemoteRepo = std::make_shared<CRepositoryProxy>(*this, tPrivateConnection, pPrivateProxy);
|
||||
|
||||
return pPrivateProxy;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CClient::Disconnect(sdv::com::TConnectionID tConnectionID)
|
||||
bool CClientConnect::Disconnect()
|
||||
{
|
||||
// Find the connection, disconnect and remove the connection from the repository list.
|
||||
std::unique_lock<std::mutex> lock(m_mtxRepositoryProxies);
|
||||
auto itRepository = m_mapRepositoryProxies.find(tConnectionID);
|
||||
if (itRepository == m_mapRepositoryProxies.end()) return;
|
||||
std::unique_lock<std::mutex> lock(m_mtx);
|
||||
|
||||
if (!m_ptrRemoteRepo) return false;
|
||||
|
||||
// Whatever happens, the connection will be removed
|
||||
std::shared_ptr<CRepositoryProxy> ptrRemoteRepoLocal = std::move(m_ptrRemoteRepo);
|
||||
|
||||
// Disconnect
|
||||
sdv::com::IConnectionControl* pConnectionControl = sdv::core::GetObject<sdv::com::IConnectionControl>("CommunicationControl");
|
||||
if (!pConnectionControl)
|
||||
{
|
||||
SDV_LOG_ERROR("Failed to get communication control!");
|
||||
else
|
||||
pConnectionControl->RemoveConnection(itRepository->first);
|
||||
return false;
|
||||
}
|
||||
pConnectionControl->RemoveConnection(ptrRemoteRepoLocal->GetConnectionID());
|
||||
|
||||
// Remove entry
|
||||
m_mapRepositoryProxies.erase(itRepository);
|
||||
// Get the repository
|
||||
sdv::TInterfaceAccessPtr ptrRespository = sdv::core::GetObject("RepositoryService");
|
||||
if (!ptrRespository)
|
||||
{
|
||||
SDV_LOG_ERROR("Failed to get repository service!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add a dependency of the provider to this service (to prevent the provider to be terminated while the service is still
|
||||
// running).
|
||||
sdv::core::IObjectDependency* pObjectDependency = ptrRespository.GetInterface<sdv::core::IObjectDependency>();
|
||||
if (!pObjectDependency)
|
||||
{
|
||||
SDV_LOG_ERROR("Failed to get the object dependency interface!");
|
||||
return false;
|
||||
}
|
||||
pObjectDependency->RemoveObjectDependency("ClientConnectService", m_ssProvider);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CClientConnect::IsConnected() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mtx);
|
||||
|
||||
return m_ptrRemoteRepo ? true : false;
|
||||
}
|
||||
|
||||
sdv::IInterfaceAccess* CClientConnect::GetRemoteRepository()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mtx);
|
||||
|
||||
return m_ptrRemoteRepo ? m_ptrRemoteRepo.get() : nullptr;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <interfaces/com.h>
|
||||
|
||||
// Forward declaration.
|
||||
class CClient;
|
||||
class CClientConnect;
|
||||
|
||||
/**
|
||||
* @brief Class managing the connection and providing access to the server repository through a proxy.
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
* @param[in] tConnection The connection ID to the server.
|
||||
* @param[in] pRepositoryProxy Proxy to the server repository.
|
||||
*/
|
||||
CRepositoryProxy(CClient& rClient, sdv::com::TConnectionID tConnection, sdv::IInterfaceAccess* pRepositoryProxy);
|
||||
CRepositoryProxy(CClientConnect& rClient, sdv::com::TConnectionID tConnection, sdv::IInterfaceAccess* pRepositoryProxy);
|
||||
|
||||
/**
|
||||
* @brief Do not allow a copy constructor.
|
||||
@@ -59,8 +59,14 @@ public:
|
||||
*/
|
||||
virtual void DestroyObject() override;
|
||||
|
||||
/**
|
||||
* @brief Get the connection ID for this connection.
|
||||
* @return The connection ID.
|
||||
*/
|
||||
sdv::com::TConnectionID GetConnectionID() const;
|
||||
|
||||
private:
|
||||
CClient& m_rClient; ///< Reference to the client object.
|
||||
CClientConnect& m_rClient; ///< Reference to the client object.
|
||||
sdv::com::TConnectionID m_tConnection = {}; ///< Connection ID.
|
||||
sdv::TInterfaceAccessPtr m_ptrRepositoryProxy; ///< Smart pointer to the remote repository.
|
||||
};
|
||||
@@ -68,7 +74,7 @@ private:
|
||||
/**
|
||||
* @brief Client object
|
||||
*/
|
||||
class CClient : public sdv::CSdvObject, public sdv::com::IClientConnect
|
||||
class CClientConnect : public sdv::CSdvObject, public sdv::com::IClientConnect
|
||||
{
|
||||
public:
|
||||
// Interface map
|
||||
@@ -78,8 +84,15 @@ public:
|
||||
|
||||
// Object declaration
|
||||
DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::system_object)
|
||||
DECLARE_OBJECT_CLASS_NAME("ConnectionService")
|
||||
DECLARE_OBJECT_SINGLETON()
|
||||
DECLARE_OBJECT_CLASS_NAME("ClientConnectService")
|
||||
DECLARE_OBJECT_DEPENDENCIES("CommunicationControl")
|
||||
|
||||
// Parameter map
|
||||
BEGIN_SDV_PARAM_MAP()
|
||||
SDV_PARAM_ENABLE_LOCKING()
|
||||
SDV_PARAM_GROUP("Provider")
|
||||
SDV_PARAM_ENTRY(m_ssProvider, "Name", "", "", "Provider name to create a connection for.")
|
||||
END_SDV_PARAM_MAP()
|
||||
|
||||
/**
|
||||
* @brief Initialization event, called after object configuration was loaded. Overload of sdv::CSdvObject::OnInitialize.
|
||||
@@ -93,40 +106,40 @@ public:
|
||||
virtual void OnShutdown() override;
|
||||
|
||||
/**
|
||||
* @brief Connect to a remote system using the connection string to contact the system. Overload of
|
||||
* sdv::com::IClientConnect::Connect.
|
||||
* @remarks After a successful connection, the ConnectClient utility is not needed any more.
|
||||
* @param[in] ssConnectString Optional connection string to use for connection. If not provided, the connection will
|
||||
* automatically get the connection ID from the app-control service (default). The connection string for a local
|
||||
* connection can be of the form:
|
||||
* @code
|
||||
* [Client]
|
||||
* Type = "Local"
|
||||
* Instance = 1234 # Optional: only use when connecting to a system with a different instance ID.
|
||||
* @endcode
|
||||
* And the following can be used for a remote connection:
|
||||
* @code
|
||||
* [Client]
|
||||
* Type = "Remote"
|
||||
* Interface = "127.0.0.1"
|
||||
* Port = 2000
|
||||
* @endcode
|
||||
* @return Returns an interface to the repository of the remote system or a NULL pointer if not found.
|
||||
* @brief Connect to a remote system. Overload of IClientConnect::Connect.
|
||||
* @return Returns whether connect was successful.
|
||||
*/
|
||||
virtual sdv::IInterfaceAccess* Connect(const sdv::u8string& ssConnectString) override;
|
||||
virtual bool Connect() override;
|
||||
|
||||
/**
|
||||
* @brief Disconnect and remove the remote repository object.
|
||||
* @param[in] tConnectionID The ID of the connection.
|
||||
* @brief Disconnect from a connected system. Overload of IClientConnect::Disconnect.
|
||||
* @return Returns whether disconnect was successful.
|
||||
*/
|
||||
void Disconnect(sdv::com::TConnectionID tConnectionID);
|
||||
bool Disconnect() override;
|
||||
|
||||
/**
|
||||
* @brief State of the current connection. Overload of IClientConnect::IsConnected.
|
||||
* @return Returns whether an active connection exists.
|
||||
* @return The connect state.
|
||||
*/
|
||||
bool IsConnected() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the remote repository that is available after connection. Overload of IClientConnect::GetRemoteRepository.
|
||||
* @remarks For main, isolated and external applications, the remote repository will be automatically linked to the
|
||||
* local repository. Hence a requests for the repository is not needed. For all other applications, access must be
|
||||
* explicitly acquired through this interface.
|
||||
* @return Interface to the remote repository if a successful connection is established. The interface is valid until
|
||||
* disconnect is called or the client connection service is terminated.
|
||||
*/
|
||||
sdv::IInterfaceAccess* GetRemoteRepository() override;
|
||||
|
||||
private:
|
||||
std::mutex m_mtxRepositoryProxies; ///< Protect access to the remnote repository map.
|
||||
std::map<sdv::com::TConnectionID, CRepositoryProxy> m_mapRepositoryProxies; ///< map of remote repositories.
|
||||
mutable std::mutex m_mtx; ///< Protect against multiple parallel connection activities.
|
||||
sdv::u8string m_ssProvider; ///< Name of the provider to use for the listening.
|
||||
std::shared_ptr<CRepositoryProxy> m_ptrRemoteRepo; ///< Interface to the remote repository.
|
||||
};
|
||||
|
||||
DEFINE_SDV_OBJECT(CClient)
|
||||
|
||||
DEFINE_SDV_OBJECT(CClientConnect)
|
||||
|
||||
#endif // !defined CLIENT_H
|
||||
@@ -16,11 +16,12 @@
|
||||
#include <interfaces/com.h>
|
||||
#include <interfaces/app.h>
|
||||
#include <support/pssup.h>
|
||||
#include <support/local_service_access.h>
|
||||
|
||||
CChannelBroker::CChannelBroker(CListener& rListener) : m_rListener(rListener)
|
||||
{}
|
||||
|
||||
sdv::u8string CChannelBroker::RequestChannel(/*in*/ const sdv::u8string& /*ssConfig*/)
|
||||
sdv::u8string CChannelBroker::RequestChannel(/*in*/ const sdv::u8string& ssConfig)
|
||||
{
|
||||
// Get the communication control
|
||||
sdv::com::IConnectionControl* pConnectionControl = sdv::core::GetObject<sdv::com::IConnectionControl>("CommunicationControl");
|
||||
@@ -39,26 +40,30 @@ sdv::u8string CChannelBroker::RequestChannel(/*in*/ const sdv::u8string& /*ssCon
|
||||
}
|
||||
|
||||
// Get the channel control.
|
||||
sdv::ipc::ICreateEndpoint* pEndpoint = nullptr;
|
||||
if (m_rListener.IsLocalListener())
|
||||
pEndpoint = sdv::core::GetObject<sdv::ipc::ICreateEndpoint>("LocalChannelControl");
|
||||
else
|
||||
pEndpoint = sdv::core::GetObject<sdv::ipc::ICreateEndpoint>("RemoteChannelControl");
|
||||
sdv::ipc::ICreateEndpoint* pEndpoint = sdv::core::GetObject<sdv::ipc::ICreateEndpoint>(m_rListener.GetProviderName());
|
||||
if (!pEndpoint)
|
||||
{
|
||||
SDV_LOG_ERROR("No local channel control!");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Create the endpoint
|
||||
sdv::ipc::SChannelEndpoint sEndpoint = pEndpoint->CreateEndpoint(sdv::u8string());
|
||||
// Forward protocol-specific configuration to the provider when creating the private channel.
|
||||
SDV_LOG_INFO("[IPC_CONNECT][Listener] RequestChannel input config:\n", ssConfig);
|
||||
|
||||
sdv::ipc::SChannelEndpoint sEndpoint = pEndpoint->CreateEndpoint(ssConfig);
|
||||
if (!sEndpoint.pConnection)
|
||||
{
|
||||
SDV_LOG_ERROR("Could not create the endpoint for channel request!");
|
||||
return sdv::u8string();
|
||||
return {};
|
||||
}
|
||||
|
||||
SDV_LOG_INFO("[IPC_CONNECT][Listener] RequestChannel produced connect string: ", sEndpoint.ssConnectString);
|
||||
|
||||
sdv::TObjectPtr ptrEndpoint(sEndpoint.pConnection); // Does automatic destruction if failure happens.
|
||||
|
||||
// Restrict access permissions
|
||||
sdv::core::CAccessPermission permission = sdv::core::RestrictAccessPermission(sdv::core::EAccessPermission::local_access);
|
||||
|
||||
// Assign the endpoint to the communication service.
|
||||
sdv::com::TConnectionID tConnection = pConnectionControl->AssignServerEndpoint(ptrEndpoint, ptrRespository, 100, false);
|
||||
ptrEndpoint.Clear(); // Lifetime taken over by communication control.
|
||||
@@ -93,49 +98,21 @@ bool CListener::OnInitialize()
|
||||
return false;
|
||||
}
|
||||
|
||||
sdv::ipc::ICreateEndpoint* pEndpoint = nullptr;
|
||||
std::string ssConfig;
|
||||
if (m_ssType == "Local")
|
||||
// Check for a provider. Without provider there is no object to use for listening.
|
||||
if (m_ssProvider.empty())
|
||||
{
|
||||
m_bLocalListener = true;
|
||||
pEndpoint = sdv::core::GetObject<sdv::ipc::ICreateEndpoint>("LocalChannelControl");
|
||||
if (!pEndpoint)
|
||||
{
|
||||
SDV_LOG_ERROR("No local channel control!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Request the instance ID from the app control
|
||||
ssConfig = std::string(R"code([IpcChannel]
|
||||
Name = "LISTENER_)code") + std::to_string(m_uiInstanceID ? m_uiInstanceID : pContext->GetInstanceID()) + R"code("
|
||||
Size = 2048
|
||||
)code";
|
||||
}
|
||||
else if (m_ssType == "Remote")
|
||||
{
|
||||
m_bLocalListener = false;
|
||||
if (m_ssInterface.empty() || !m_uiPort)
|
||||
{
|
||||
SDV_LOG_ERROR("Missing interface or port number to initialize a remote listener!");
|
||||
return false;
|
||||
}
|
||||
pEndpoint = sdv::core::GetObject<sdv::ipc::ICreateEndpoint>("RemoteChannelControl");
|
||||
if (!pEndpoint)
|
||||
{
|
||||
SDV_LOG_ERROR("No remote channel control!");
|
||||
return false;
|
||||
}
|
||||
|
||||
ssConfig = R"code([IpcChannel]
|
||||
Interface = ")code" + m_ssInterface + R"code(
|
||||
Port = ")code" + std::to_string(m_uiPort) + R"code(
|
||||
)code";
|
||||
}
|
||||
else
|
||||
{
|
||||
SDV_LOG_ERROR("Invalid or missing listener configuration for listener service!");
|
||||
SDV_LOG_ERROR("Missing provider name for creating a listener object!");
|
||||
return false;
|
||||
}
|
||||
sdv::ipc::ICreateEndpoint* pEndpoint = sdv::core::GetObject<sdv::ipc::ICreateEndpoint>(m_ssProvider);
|
||||
if (!pEndpoint)
|
||||
{
|
||||
SDV_LOG_ERROR("Cannot instantiate provider '", m_ssProvider, "' for the creation of a listener object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the IpcChannel information from the the configuration
|
||||
auto ssConfig = BuildObjectConfig();
|
||||
|
||||
// Create the endpoint
|
||||
sdv::ipc::SChannelEndpoint sEndpoint = pEndpoint->CreateEndpoint(ssConfig);
|
||||
@@ -146,6 +123,24 @@ Port = ")code" + std::to_string(m_uiPort) + R"code(
|
||||
}
|
||||
sdv::TObjectPtr ptrEndpoint(sEndpoint.pConnection); // Does automatic destruction if failure happens.
|
||||
|
||||
// Get the repository
|
||||
sdv::TInterfaceAccessPtr ptrRespository = sdv::core::GetObject("RepositoryService");
|
||||
if (!ptrRespository)
|
||||
{
|
||||
SDV_LOG_ERROR("Failed to get repository service!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add a dependency of the provider to this service (to prevent the provider to be terminated while the service is still
|
||||
// running).
|
||||
sdv::core::IObjectDependency* pObjectDependency = ptrRespository.GetInterface<sdv::core::IObjectDependency>();
|
||||
if (!pObjectDependency)
|
||||
{
|
||||
SDV_LOG_ERROR("Failed to get the object dependency interface!");
|
||||
return false;
|
||||
}
|
||||
pObjectDependency->AddObjectDependency(Self().ssName, m_ssProvider);
|
||||
|
||||
// Assign the endpoint to the communication service.
|
||||
m_tConnection = pConnectionControl->AssignServerEndpoint(ptrEndpoint, &m_broker, 100, true);
|
||||
ptrEndpoint.Clear(); // Lifetime taken over by communication control.
|
||||
@@ -173,9 +168,8 @@ void CListener::OnShutdown()
|
||||
m_ptrConnection.Clear();
|
||||
}
|
||||
|
||||
bool CListener::IsLocalListener() const
|
||||
|
||||
const sdv::u8string& CListener::GetProviderName()
|
||||
{
|
||||
return m_bLocalListener;
|
||||
return m_ssProvider;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -52,6 +52,25 @@ private:
|
||||
|
||||
/**
|
||||
* @brief Listener object
|
||||
* @details the lister is instantiated using the following parameter information
|
||||
* @code
|
||||
* # Provider to use for listening
|
||||
* [Provider]
|
||||
* Name = ""
|
||||
*
|
||||
* # Additional channel information for the listener (needed for unique listener identification)
|
||||
* [IpcChannel]
|
||||
* xyz = ""
|
||||
* @endcode
|
||||
*
|
||||
* For example for shared memory:
|
||||
* @code
|
||||
* [Provider]
|
||||
* Name = "DefaultSharedMemory"
|
||||
* [IpcChannel]
|
||||
* Name = "LISTENER_1234"
|
||||
* Size = 10240
|
||||
* @endcode
|
||||
*/
|
||||
class CListener : public sdv::CSdvObject
|
||||
{
|
||||
@@ -63,34 +82,18 @@ public:
|
||||
|
||||
// Object declaration
|
||||
DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::system_object)
|
||||
DECLARE_OBJECT_CLASS_NAME("ConnectionListenerService")
|
||||
DECLARE_OBJECT_CLASS_NAME("ListenerConnectService")
|
||||
DECLARE_OBJECT_DEPENDENCIES("CommunicationControl")
|
||||
|
||||
// Parameter map
|
||||
BEGIN_SDV_PARAM_MAP()
|
||||
SDV_PARAM_ENABLE_LOCKING()
|
||||
SDV_PARAM_GROUP("Listener")
|
||||
SDV_PARAM_ENTRY(m_ssType, "Type", "Local", "", "The type of listener \"Local\" or \"Remote\".")
|
||||
SDV_PARAM_ENTRY(m_uiInstanceID, "Instance", 0, "", "The instance ID to listen for.")
|
||||
SDV_PARAM_ENTRY(m_ssInterface, "Interface", "", "", "Interface identification.")
|
||||
SDV_PARAM_ENTRY(m_uiPort, "Port", 0, "", "Port number for connection.")
|
||||
SDV_PARAM_GROUP("Provider")
|
||||
SDV_PARAM_ENTRY(m_ssProvider, "Name", "", "", "Provider name to create a listener for.")
|
||||
END_SDV_PARAM_MAP()
|
||||
|
||||
/**
|
||||
* @brief Initialization event, called after object configuration was loaded. Overload of sdv::CSdvObject::OnInitialize.
|
||||
* @details The object configuration contains the information needed to start the listener. The following configuration is
|
||||
* available for the local listener:
|
||||
* @code
|
||||
* [Listener]
|
||||
* Type = "Local"
|
||||
* Instance = 1000 # Normally not used; system instance ID is used automatically.
|
||||
* @endcode
|
||||
* And the following is available for a remote listener:
|
||||
* @code
|
||||
* [Listener]
|
||||
* Type = "Remote"
|
||||
* Interface = "127.0.0.1"
|
||||
* Port = 2000
|
||||
* @endcode
|
||||
* @return Returns 'true' when the initialization was successful, 'false' when not.
|
||||
*/
|
||||
virtual bool OnInitialize() override;
|
||||
@@ -101,19 +104,15 @@ public:
|
||||
virtual void OnShutdown() override;
|
||||
|
||||
/**
|
||||
* @brief When set, the listener is configured to be a local listener. Otherwise the listerner is configured as remote listener.
|
||||
* @return Boolean set when local lostener.
|
||||
* @brief Get the provider name used by this listener.
|
||||
* @return Reference to the provider name.
|
||||
*/
|
||||
bool IsLocalListener() const;
|
||||
const sdv::u8string& GetProviderName();
|
||||
|
||||
private:
|
||||
sdv::u8string m_ssType; ///< Listener type: "Local" or "Remote"
|
||||
uint32_t m_uiInstanceID = 0; ///< Instance ID to listen for.
|
||||
std::string m_ssInterface; ///< Interface string for remote listener.
|
||||
uint32_t m_uiPort = 0; ///< Port for remote listener.
|
||||
sdv::u8string m_ssProvider; ///< Name of the provider to use for the listening.
|
||||
sdv::TObjectPtr m_ptrConnection; ///< The connection object.
|
||||
CChannelBroker m_broker; ///< Channel broker, used to request new channels
|
||||
bool m_bLocalListener = true; ///< When set, the listener is a local listener; otherwise a remote listener.
|
||||
sdv::com::TConnectionID m_tConnection = {}; ///< Channel connection ID.
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user