|
|
|
@ -1,7 +1,7 @@
|
|
|
|
|
/*
|
|
|
|
|
* mms_server.c
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2013 - 2016 Michael Zillgith
|
|
|
|
|
* Copyright 2013-2020 Michael Zillgith
|
|
|
|
|
*
|
|
|
|
|
* This file is part of libIEC61850.
|
|
|
|
|
*
|
|
|
|
@ -52,48 +52,133 @@ MmsServer_create(MmsDevice* device, TLSConfiguration tlsConfiguration)
|
|
|
|
|
{
|
|
|
|
|
MmsServer self = (MmsServer) GLOBAL_CALLOC(1, sizeof(struct sMmsServer));
|
|
|
|
|
|
|
|
|
|
self->isoServer = IsoServer_create(tlsConfiguration);
|
|
|
|
|
self->device = device;
|
|
|
|
|
self->openConnections = Map_create();
|
|
|
|
|
self->valueCaches = createValueCaches(device);
|
|
|
|
|
self->isLocked = false;
|
|
|
|
|
if (self) {
|
|
|
|
|
#if (CONFIG_MMS_THREADLESS_STACK != 1)
|
|
|
|
|
self->openConnectionsLock = Semaphore_create(1);
|
|
|
|
|
|
|
|
|
|
self->transmitBuffer = ByteBuffer_create(NULL, CONFIG_MMS_MAXIMUM_PDU_SIZE);
|
|
|
|
|
if (self->openConnectionsLock == NULL)
|
|
|
|
|
goto exit_error;
|
|
|
|
|
|
|
|
|
|
#if (CONFIG_MMS_THREADLESS_STACK != 1)
|
|
|
|
|
self->openConnectionsLock = Semaphore_create(1);
|
|
|
|
|
self->modelMutex = Semaphore_create(1);
|
|
|
|
|
|
|
|
|
|
self->modelMutex = Semaphore_create(1);
|
|
|
|
|
self->transmitBufferMutex = Semaphore_create(1);
|
|
|
|
|
if (self->modelMutex == NULL)
|
|
|
|
|
goto exit_error;
|
|
|
|
|
|
|
|
|
|
IsoServer_setUserLock(self->isoServer, self->modelMutex);
|
|
|
|
|
self->transmitBufferMutex = Semaphore_create(1);
|
|
|
|
|
|
|
|
|
|
if (self->transmitBufferMutex == NULL)
|
|
|
|
|
goto exit_error;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
self->isoServerList = LinkedList_create();
|
|
|
|
|
|
|
|
|
|
if (self->isoServerList == NULL)
|
|
|
|
|
goto exit_error;
|
|
|
|
|
|
|
|
|
|
if (tlsConfiguration) {
|
|
|
|
|
IsoServer isoServer = IsoServer_create(tlsConfiguration);
|
|
|
|
|
|
|
|
|
|
if (isoServer == NULL)
|
|
|
|
|
goto exit_error;
|
|
|
|
|
|
|
|
|
|
#if (CONFIG_MMS_THREADLESS_STACK != 1)
|
|
|
|
|
IsoServer_setUserLock(isoServer, self->modelMutex);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
LinkedList_add(self->isoServerList, isoServer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self->device = device;
|
|
|
|
|
self->openConnections = Map_create();
|
|
|
|
|
|
|
|
|
|
if (self->openConnections == NULL)
|
|
|
|
|
goto exit_error;
|
|
|
|
|
|
|
|
|
|
self->valueCaches = createValueCaches(device);
|
|
|
|
|
|
|
|
|
|
if (self->valueCaches == NULL)
|
|
|
|
|
goto exit_error;
|
|
|
|
|
|
|
|
|
|
self->isLocked = false;
|
|
|
|
|
|
|
|
|
|
self->transmitBuffer = ByteBuffer_create(NULL, CONFIG_MMS_MAXIMUM_PDU_SIZE);
|
|
|
|
|
|
|
|
|
|
if (self->transmitBuffer == NULL)
|
|
|
|
|
goto exit_error;
|
|
|
|
|
|
|
|
|
|
#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1)
|
|
|
|
|
self->fileServiceEnabled = true;
|
|
|
|
|
self->dynamicVariableListServiceEnabled = true;
|
|
|
|
|
self->journalServiceEnabled = true;
|
|
|
|
|
self->maxDataSetEntries = CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS;
|
|
|
|
|
self->maxAssociationSpecificDataSets = CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS;
|
|
|
|
|
self->maxDomainSpecificDataSets = CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS;
|
|
|
|
|
self->fileServiceEnabled = true;
|
|
|
|
|
self->dynamicVariableListServiceEnabled = true;
|
|
|
|
|
self->journalServiceEnabled = true;
|
|
|
|
|
self->maxDataSetEntries = CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS;
|
|
|
|
|
self->maxAssociationSpecificDataSets = CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS;
|
|
|
|
|
self->maxDomainSpecificDataSets = CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS;
|
|
|
|
|
#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
|
|
|
|
|
exit_error:
|
|
|
|
|
|
|
|
|
|
MmsServer_destroy(self);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
MmsServer_addAP(MmsServer self, const char* ipAddr, int tcpPort, TLSConfiguration tlsConfiguration)
|
|
|
|
|
{
|
|
|
|
|
IsoServer isoServer = IsoServer_create(tlsConfiguration);
|
|
|
|
|
|
|
|
|
|
if (isoServer) {
|
|
|
|
|
|
|
|
|
|
IsoServer_setUserLock(isoServer, self->modelMutex);
|
|
|
|
|
|
|
|
|
|
IsoServer_setLocalIpAddress(isoServer, ipAddr);
|
|
|
|
|
|
|
|
|
|
if (tcpPort != -1)
|
|
|
|
|
IsoServer_setTcpPort(isoServer, tcpPort);
|
|
|
|
|
|
|
|
|
|
if (self->authenticator)
|
|
|
|
|
IsoServer_setAuthenticator(isoServer, self->authenticator, self->authenticatorParameter);
|
|
|
|
|
|
|
|
|
|
LinkedList_add(self->isoServerList, isoServer);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MmsServer_setLocalIpAddress(MmsServer self, const char* localIpAddress)
|
|
|
|
|
{
|
|
|
|
|
IsoServer_setLocalIpAddress(self->isoServer, localIpAddress);
|
|
|
|
|
if (LinkedList_size(self->isoServerList) == 0) {
|
|
|
|
|
MmsServer_addAP(self, NULL, -1, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LinkedList elem = LinkedList_get(self->isoServerList, 0);
|
|
|
|
|
|
|
|
|
|
if (elem) {
|
|
|
|
|
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
|
|
|
|
|
|
|
|
|
|
IsoServer_setLocalIpAddress(isoServer, localIpAddress);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
MmsServer_isRunning(MmsServer self)
|
|
|
|
|
{
|
|
|
|
|
if (IsoServer_getState(self->isoServer) == ISO_SVR_STATE_RUNNING)
|
|
|
|
|
return true;
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
LinkedList elem = LinkedList_get(self->isoServerList, 0);
|
|
|
|
|
|
|
|
|
|
if (elem) {
|
|
|
|
|
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
|
|
|
|
|
|
|
|
|
|
if (IsoServer_getState(isoServer) == ISO_SVR_STATE_RUNNING)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
@ -115,7 +200,22 @@ MmsServer_setFilestoreBasepath(MmsServer self, const char* basepath)
|
|
|
|
|
void
|
|
|
|
|
MmsServer_setMaxConnections(MmsServer self, int maxConnections)
|
|
|
|
|
{
|
|
|
|
|
IsoServer_setMaxConnections(self->isoServer, maxConnections);
|
|
|
|
|
if (self->isoServerList) {
|
|
|
|
|
|
|
|
|
|
if (LinkedList_size(self->isoServerList) == 0) {
|
|
|
|
|
MmsServer_addAP(self, NULL, -1, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LinkedList elem = LinkedList_getNext(self->isoServerList);
|
|
|
|
|
|
|
|
|
|
while (elem) {
|
|
|
|
|
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
|
|
|
|
|
|
|
|
|
|
IsoServer_setMaxConnections(isoServer, maxConnections);
|
|
|
|
|
|
|
|
|
|
elem = LinkedList_getNext(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
@ -250,7 +350,21 @@ MmsServer_installVariableListChangedHandler(MmsServer self, MmsNamedVariableList
|
|
|
|
|
void
|
|
|
|
|
MmsServer_setClientAuthenticator(MmsServer self, AcseAuthenticator authenticator, void* authenticatorParameter)
|
|
|
|
|
{
|
|
|
|
|
IsoServer_setAuthenticator(self->isoServer, authenticator, authenticatorParameter);
|
|
|
|
|
self->authenticator = authenticator;
|
|
|
|
|
self->authenticatorParameter = authenticatorParameter;
|
|
|
|
|
|
|
|
|
|
if (self->isoServerList) {
|
|
|
|
|
|
|
|
|
|
LinkedList elem = LinkedList_getNext(self->isoServerList);
|
|
|
|
|
|
|
|
|
|
while (elem) {
|
|
|
|
|
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
|
|
|
|
|
|
|
|
|
|
IsoServer_setAuthenticator(isoServer, authenticator, authenticatorParameter);
|
|
|
|
|
|
|
|
|
|
elem = LinkedList_getNext(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
@ -295,26 +409,33 @@ deleteSingleCache(MmsValueCache cache)
|
|
|
|
|
void
|
|
|
|
|
MmsServer_destroy(MmsServer self)
|
|
|
|
|
{
|
|
|
|
|
IsoServer_destroy(self->isoServer);
|
|
|
|
|
if (self) {
|
|
|
|
|
LinkedList_destroyDeep(self->isoServerList, (LinkedListValueDeleteFunction) IsoServer_destroy);
|
|
|
|
|
|
|
|
|
|
Map_deleteDeep(self->openConnections, false, closeConnection);
|
|
|
|
|
Map_deleteDeep(self->valueCaches, false, (void (*) (void*)) deleteSingleCache);
|
|
|
|
|
Map_deleteDeep(self->openConnections, false, closeConnection);
|
|
|
|
|
Map_deleteDeep(self->valueCaches, false, (void (*) (void*)) deleteSingleCache);
|
|
|
|
|
|
|
|
|
|
#if (CONFIG_MMS_THREADLESS_STACK != 1)
|
|
|
|
|
Semaphore_destroy(self->openConnectionsLock);
|
|
|
|
|
#if (CONFIG_MMS_THREADLESS_STACK != 1)
|
|
|
|
|
if (self->openConnectionsLock)
|
|
|
|
|
Semaphore_destroy(self->openConnectionsLock);
|
|
|
|
|
|
|
|
|
|
Semaphore_destroy(self->modelMutex);
|
|
|
|
|
Semaphore_destroy(self->transmitBufferMutex);
|
|
|
|
|
#endif
|
|
|
|
|
if (self->modelMutex)
|
|
|
|
|
Semaphore_destroy(self->modelMutex);
|
|
|
|
|
|
|
|
|
|
ByteBuffer_destroy(self->transmitBuffer);
|
|
|
|
|
if (self->transmitBufferMutex)
|
|
|
|
|
Semaphore_destroy(self->transmitBufferMutex);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1)
|
|
|
|
|
if (self->filestoreBasepath != NULL)
|
|
|
|
|
GLOBAL_FREEMEM(self->filestoreBasepath);
|
|
|
|
|
#endif
|
|
|
|
|
if (self->transmitBuffer)
|
|
|
|
|
ByteBuffer_destroy(self->transmitBuffer);
|
|
|
|
|
|
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
|
|
|
#if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1)
|
|
|
|
|
if (self->filestoreBasepath != NULL)
|
|
|
|
|
GLOBAL_FREEMEM(self->filestoreBasepath);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MmsValue*
|
|
|
|
@ -448,44 +569,120 @@ isoConnectionIndicationHandler(IsoConnectionIndication indication,
|
|
|
|
|
|
|
|
|
|
#if (CONFIG_MMS_THREADLESS_STACK != 1) && (CONFIG_MMS_SINGLE_THREADED != 1)
|
|
|
|
|
void
|
|
|
|
|
MmsServer_startListening(MmsServer server, int tcpPort)
|
|
|
|
|
MmsServer_startListening(MmsServer self, int tcpPort)
|
|
|
|
|
{
|
|
|
|
|
IsoServer_setConnectionHandler(server->isoServer, isoConnectionIndicationHandler, (void*) server);
|
|
|
|
|
if (self->isoServerList) {
|
|
|
|
|
|
|
|
|
|
if (LinkedList_size(self->isoServerList) == 0) {
|
|
|
|
|
MmsServer_addAP(self, NULL, -1, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LinkedList elem = LinkedList_getNext(self->isoServerList);
|
|
|
|
|
|
|
|
|
|
while (elem) {
|
|
|
|
|
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
|
|
|
|
|
|
|
|
|
|
IsoServer_setConnectionHandler(isoServer, isoConnectionIndicationHandler, (void*) self);
|
|
|
|
|
|
|
|
|
|
if (tcpPort != -1)
|
|
|
|
|
IsoServer_setTcpPort(server->isoServer, tcpPort);
|
|
|
|
|
if (tcpPort != -1)
|
|
|
|
|
IsoServer_setTcpPort(isoServer, tcpPort);
|
|
|
|
|
|
|
|
|
|
IsoServer_startListening(server->isoServer);
|
|
|
|
|
IsoServer_startListening(isoServer);
|
|
|
|
|
|
|
|
|
|
elem = LinkedList_getNext(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MmsServer_stopListening(MmsServer server)
|
|
|
|
|
MmsServer_stopListening(MmsServer self)
|
|
|
|
|
{
|
|
|
|
|
IsoServer_stopListening(server->isoServer);
|
|
|
|
|
if (self->isoServerList) {
|
|
|
|
|
LinkedList elem = LinkedList_getNext(self->isoServerList);
|
|
|
|
|
|
|
|
|
|
while (elem) {
|
|
|
|
|
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
|
|
|
|
|
|
|
|
|
|
IsoServer_stopListening(isoServer);
|
|
|
|
|
|
|
|
|
|
elem = LinkedList_getNext(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* (CONFIG_MMS_THREADLESS_STACK != 1) && (CONFIG_MMS_SINGLE_THREADED != 1)*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MmsServer_startListeningThreadless(MmsServer self, int tcpPort)
|
|
|
|
|
{
|
|
|
|
|
IsoServer_setConnectionHandler(self->isoServer, isoConnectionIndicationHandler, (void*) self);
|
|
|
|
|
if (self->isoServerList) {
|
|
|
|
|
|
|
|
|
|
if (LinkedList_size(self->isoServerList) == 0) {
|
|
|
|
|
MmsServer_addAP(self, NULL, -1, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LinkedList elem = LinkedList_getNext(self->isoServerList);
|
|
|
|
|
|
|
|
|
|
while (elem) {
|
|
|
|
|
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
|
|
|
|
|
|
|
|
|
|
IsoServer_setConnectionHandler(isoServer, isoConnectionIndicationHandler, (void*) self);
|
|
|
|
|
|
|
|
|
|
if (tcpPort != -1)
|
|
|
|
|
IsoServer_setTcpPort(isoServer, tcpPort);
|
|
|
|
|
|
|
|
|
|
if (tcpPort != -1)
|
|
|
|
|
IsoServer_setTcpPort(self->isoServer, tcpPort);
|
|
|
|
|
IsoServer_startListeningThreadless(isoServer);
|
|
|
|
|
|
|
|
|
|
IsoServer_startListeningThreadless(self->isoServer);
|
|
|
|
|
elem = LinkedList_getNext(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
MmsServer_waitReady(MmsServer self, unsigned int timeoutMs)
|
|
|
|
|
{
|
|
|
|
|
return IsoServer_waitReady(self->isoServer, timeoutMs);
|
|
|
|
|
bool isFirst = true;
|
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
|
|
if (self->isoServerList) {
|
|
|
|
|
LinkedList elem = LinkedList_getNext(self->isoServerList);
|
|
|
|
|
|
|
|
|
|
while (elem) {
|
|
|
|
|
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
|
|
|
|
|
|
|
|
|
|
int serverResult;
|
|
|
|
|
|
|
|
|
|
if (isFirst) {
|
|
|
|
|
serverResult = IsoServer_waitReady(isoServer, timeoutMs);
|
|
|
|
|
isFirst = false;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
serverResult = IsoServer_waitReady(isoServer, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (serverResult > 0)
|
|
|
|
|
result += serverResult;
|
|
|
|
|
|
|
|
|
|
elem = LinkedList_getNext(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MmsServer_handleIncomingMessages(MmsServer self)
|
|
|
|
|
{
|
|
|
|
|
IsoServer_processIncomingMessages(self->isoServer);
|
|
|
|
|
if (self->isoServerList) {
|
|
|
|
|
LinkedList elem = LinkedList_getNext(self->isoServerList);
|
|
|
|
|
|
|
|
|
|
while (elem) {
|
|
|
|
|
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
|
|
|
|
|
|
|
|
|
|
IsoServer_processIncomingMessages(isoServer);
|
|
|
|
|
|
|
|
|
|
elem = LinkedList_getNext(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
@ -507,7 +704,21 @@ MmsServer_handleBackgroundTasks(MmsServer self)
|
|
|
|
|
int
|
|
|
|
|
MmsServer_getConnectionCounter(MmsServer self)
|
|
|
|
|
{
|
|
|
|
|
return IsoServer_getConnectionCounter(self->isoServer);
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
if (self->isoServerList) {
|
|
|
|
|
LinkedList elem = LinkedList_getNext(self->isoServerList);
|
|
|
|
|
|
|
|
|
|
while (elem) {
|
|
|
|
|
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
|
|
|
|
|
|
|
|
|
|
count += IsoServer_getConnectionCounter(isoServer);
|
|
|
|
|
|
|
|
|
|
elem = LinkedList_getNext(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
@ -521,6 +732,16 @@ MmsServer_callConnectionHandler(MmsServer self, MmsServerConnection connection)
|
|
|
|
|
void
|
|
|
|
|
MmsServer_stopListeningThreadless(MmsServer self)
|
|
|
|
|
{
|
|
|
|
|
IsoServer_stopListeningThreadless(self->isoServer);
|
|
|
|
|
if (self->isoServerList) {
|
|
|
|
|
LinkedList elem = LinkedList_getNext(self->isoServerList);
|
|
|
|
|
|
|
|
|
|
while (elem) {
|
|
|
|
|
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
|
|
|
|
|
|
|
|
|
|
IsoServer_stopListeningThreadless(isoServer);
|
|
|
|
|
|
|
|
|
|
elem = LinkedList_getNext(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|