- IED server: added functions ClientConnection_claimOwnerShip and ClientConnection_release to use ClientConnection outside of callbacks (LIB61850-488)

v1.6
Michael Zillgith 1 month ago
parent cd10e14790
commit 9df35ce709

@ -837,6 +837,32 @@ ClientConnection_getSecurityToken(ClientConnection self);
LIB61850_API bool
ClientConnection_abort(ClientConnection self);
/**
* \brief Claim ownership of the ClientConnection instance to store and use it outside of a callback
*
* \note The application has to call \ref ClientConnection_release when the instance is no longer used
* order to avoid memory leaks
*
* \param self the ClientConnection instance
*
* \return the connection instance when ownership is granted
*/
LIB61850_API ClientConnection
ClientConnection_claimOwnership(ClientConnection self);
/**
* \brief Release the ownership of the ClientConnection instance.
*
* This function will also destroy the ClientConnection instance when no other owners exist.
*
* \note The application should only call this function once for each call for \ref ClientConnection_claimOwnership
* for a specific ClientConnection instance. The reference must not be used after calling this function!
*
* \param self the ClientConnection instance
*/
LIB61850_API void
ClientConnection_release(ClientConnection self);
/**
* \brief User provided callback function that is invoked whenever a new client connects or an existing connection is closed
* or detected as lost.

@ -95,9 +95,6 @@ private_IedServer_getClientConnectionByHandle(IedServer self, void* serverConnec
LIB61850_INTERNAL ClientConnection
private_ClientConnection_create(void* serverConnectionHandle);
LIB61850_INTERNAL void
private_ClientConnection_destroy(ClientConnection self);
LIB61850_INTERNAL int
private_ClientConnection_getTasksCount(ClientConnection self);

@ -1,7 +1,7 @@
/*
* client_connection.c
*
* Copyright 2013-2024 Michael Zillgith
* Copyright 2013-2025 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -32,6 +32,12 @@
#include "libiec61850_platform_includes.h"
#if __STDC_VERSION__ >= 201112L
#include <stdatomic.h>
#else
#define _TLS_OWN_CNT_SEM 1
#endif
struct sClientConnection
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
@ -40,6 +46,17 @@ struct sClientConnection
int tasksCount;
void* serverConnectionHandle;
bool isValid; /* connection is still valid and has not been closed in the meantime */
#ifdef _TLS_OWN_CNT_SEM
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore ownerCountMutex;
#endif /*#if (CONFIG_MMS_THREADLESS_STACK != 1) */
int ownerCount;
#else
_Atomic(int) ownerCount;
#endif /* _TLS_OWN_CNT_SEM */
};
ClientConnection
@ -51,22 +68,32 @@ private_ClientConnection_create(void* serverConnectionHandle)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
self->tasksCountMutex = Semaphore_create(1);
#ifdef _TLS_OWN_CNT_SEM
self->ownerCount = Semaphore_create(1);
#endif
#endif
self->ownerCount = 1;
self->tasksCount = 0;
self->serverConnectionHandle = serverConnectionHandle;
self->isValid = true;
}
return self;
}
void
static void
private_ClientConnection_destroy(ClientConnection self)
{
if (self)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_destroy(self->tasksCountMutex);
#ifdef _TLS_OWN_CNT_SEM
Semaphore_destroy(self->ownerCountMutex);
#endif
#endif
GLOBAL_FREEMEM(self);
@ -128,24 +155,123 @@ private_ClientConnection_getServerConnectionHandle(ClientConnection self)
const char*
ClientConnection_getPeerAddress(ClientConnection self)
{
MmsServerConnection mmsConnection = (MmsServerConnection) self->serverConnectionHandle;
if (self->isValid)
{
MmsServerConnection mmsConnection = (MmsServerConnection) self->serverConnectionHandle;
return MmsServerConnection_getClientAddress(mmsConnection);
return MmsServerConnection_getClientAddress(mmsConnection);
}
else
{
return NULL;
}
}
const char*
ClientConnection_getLocalAddress(ClientConnection self)
{
MmsServerConnection mmsConnection = (MmsServerConnection) self->serverConnectionHandle;
if (self->isValid)
{
MmsServerConnection mmsConnection = (MmsServerConnection) self->serverConnectionHandle;
return MmsServerConnection_getLocalAddress(mmsConnection);
return MmsServerConnection_getLocalAddress(mmsConnection);
}
else
{
return NULL;
}
}
void*
ClientConnection_getSecurityToken(ClientConnection self)
{
MmsServerConnection mmsConnection = (MmsServerConnection) self->serverConnectionHandle;
if (self->isValid)
{
MmsServerConnection mmsConnection = (MmsServerConnection) self->serverConnectionHandle;
return MmsServerConnection_getSecurityToken(mmsConnection);
}
else
{
return NULL;
}
}
bool
ClientConnection_abort(ClientConnection self)
{
//TODO set only a flag and let the connection thread close the connection!?
// this could be required for thread safety
bool aborted = false;
if (self->isValid)
{
MmsServerConnection mmsConnection = (MmsServerConnection) self->serverConnectionHandle;
if (mmsConnection)
{
MmsServer mmsServer = MmsServerConnection_getServer(mmsConnection);
aborted = MmsServer_abortConnection(mmsServer, mmsConnection);
if (aborted)
{
/* remove reference to underlying connection. Instance cannot be used any longer */
self->serverConnectionHandle = NULL;
}
}
}
return aborted;
}
ClientConnection
ClientConnection_claimOwnership(ClientConnection self)
{
#ifdef _TLS_OWN_CNT_SEM
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->ownerCountMutex);
#endif
self->ownerCount++;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->ownerCountMutex);
#endif
#else
atomic_fetch_add(&(self->ownerCount), 1);
#endif
return MmsServerConnection_getSecurityToken(mmsConnection);
return self;
}
void
ClientConnection_release(ClientConnection self)
{
if (self)
{
#ifdef _TLS_OWN_CNT_SEM
int cnt;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->ownerCountMutex);
#endif
cnt = self->ownerCount;
self->ownerCount--;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->ownerCountMutex);
#endif
if (cnt == 1) {
private_ClientConnection_destroy(self);
}
#else
if (atomic_fetch_sub(&(self->ownerCount), 1) == 1)
{
private_ClientConnection_destroy(self);
}
#endif /* #ifdef _TLS_OWN_CNT_SEM */
}
}

@ -808,7 +808,7 @@ IedServer_destroy(IedServer self)
if (self->mmsMapping)
MmsMapping_destroy(self->mmsMapping);
LinkedList_destroyDeep(self->clientConnections, (LinkedListValueDeleteFunction) private_ClientConnection_destroy);
LinkedList_destroyDeep(self->clientConnections, (LinkedListValueDeleteFunction) ClientConnection_release);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_destroy(self->dataModelLock);

@ -3354,7 +3354,7 @@ mmsConnectionHandler(void* parameter, MmsServerConnection connection, MmsServerE
unselectAllSettingGroups(self, connection);
#endif
private_ClientConnection_destroy(clientConnection);
ClientConnection_release(clientConnection);
}
else if (event == MMS_SERVER_NEW_CONNECTION) {
/* call user provided handler function */

Loading…
Cancel
Save