From 4a7982ae69d072abbb4f5c41e6ca67ee3da5e40b Mon Sep 17 00:00:00 2001 From: Kevin Jhang Date: Tue, 4 Jan 2022 10:04:12 +0800 Subject: [PATCH] Added write access handler data reference parameter --- dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs | 10 +- .../server_example_control.c | 2 +- .../server_example_password_auth.c | 2 +- .../server_example_substitution.c | 2 +- .../server_example_write_handler.c | 2 +- src/iec61850/inc/iec61850_server.h | 3 +- src/iec61850/server/mms_mapping/mms_mapping.c | 9 +- src/mms/inc_private/mms_server_internal.h | 4 + src/mms/inc_private/mms_server_libinternal.h | 2 +- src/mms/iso_mms/server/mms_server.c | 193 +++++++++++++++++- src/mms/iso_mms/server/mms_write_service.c | 74 +------ 11 files changed, 222 insertions(+), 81 deletions(-) diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs index 541ffa2a..9b423ffc 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs @@ -2034,7 +2034,7 @@ namespace IEC61850 public delegate void RCBEventHandler(object parameter, ReportControlBlock rcb, ClientConnection con, RCBEventType eventType, string parameterName, MmsDataAccessError serviceError); - public delegate MmsDataAccessError WriteAccessHandler (DataAttribute dataAttr, MmsValue value, + public delegate MmsDataAccessError WriteAccessHandler (DataAttribute dataAttr, string dataRef, MmsValue value, ClientConnection connection, object parameter); /// @@ -2215,7 +2215,7 @@ namespace IEC61850 static extern void IedServer_setWriteAccessPolicy(IntPtr self, FunctionalConstraint fc, AccessPolicy policy); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int InternalWriteAccessHandler (IntPtr dataAttribute, IntPtr value, IntPtr connection, IntPtr parameter); + private delegate int InternalWriteAccessHandler (IntPtr dataAttribute, IntPtr dataRef, IntPtr value, IntPtr connection, IntPtr parameter); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedServer_handleWriteAccess(IntPtr self, IntPtr dataAttribute, @@ -2397,7 +2397,7 @@ namespace IEC61850 } } - int WriteAccessHandlerImpl (IntPtr dataAttribute, IntPtr value, IntPtr connection, IntPtr parameter) + int WriteAccessHandlerImpl (IntPtr dataAttribute, IntPtr dataRef, IntPtr value, IntPtr connection, IntPtr parameter) { WriteAccessHandlerInfo info; @@ -2407,9 +2407,11 @@ namespace IEC61850 clientConnections.TryGetValue(connection, out con); + string dataRefereence = Marshal.PtrToStringAnsi(dataRef); + MmsValue mmsValue = new MmsValue(value); - return (int)info.handler(info.dataAttribute, mmsValue.Clone(), con, info.parameter); + return (int)info.handler(info.dataAttribute, dataRefereence, mmsValue.Clone(), con, info.parameter); } else { diff --git a/examples/server_example_control/server_example_control.c b/examples/server_example_control/server_example_control.c index 364c20c6..ff7bf1ee 100644 --- a/examples/server_example_control/server_example_control.c +++ b/examples/server_example_control/server_example_control.c @@ -107,7 +107,7 @@ controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* v } static MmsDataAccessError -writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter) +writeAccessHandler (DataAttribute* dataAttribute, char* dataRef, MmsValue* value, ClientConnection connection, void* parameter) { ControlModel ctlModelVal = (ControlModel) MmsValue_toInt32(value); diff --git a/examples/server_example_password_auth/server_example_password_auth.c b/examples/server_example_password_auth/server_example_password_auth.c index 149c6fbb..1c1621ca 100644 --- a/examples/server_example_password_auth/server_example_password_auth.c +++ b/examples/server_example_password_auth/server_example_password_auth.c @@ -128,7 +128,7 @@ controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* v static MmsDataAccessError -writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter) +writeAccessHandler (DataAttribute* dataAttribute, char* dataRef, MmsValue* value, ClientConnection connection, void* parameter) { void* securityToken = ClientConnection_getSecurityToken(connection); diff --git a/examples/server_example_substitution/server_example_substitution.c b/examples/server_example_substitution/server_example_substitution.c index 2f41d892..56e5bbc4 100644 --- a/examples/server_example_substitution/server_example_substitution.c +++ b/examples/server_example_substitution/server_example_substitution.c @@ -70,7 +70,7 @@ updateProcessValues() } static MmsDataAccessError -writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter) +writeAccessHandler (DataAttribute* dataAttribute, char* dataRef, MmsValue* value, ClientConnection connection, void* parameter) { if (dataAttribute == IEDMODEL_LD1_GGIO1_AnIn1_subEna) { diff --git a/examples/server_example_write_handler/server_example_write_handler.c b/examples/server_example_write_handler/server_example_write_handler.c index d1d2295e..d7efdeaa 100644 --- a/examples/server_example_write_handler/server_example_write_handler.c +++ b/examples/server_example_write_handler/server_example_write_handler.c @@ -22,7 +22,7 @@ void sigint_handler(int signalId) } static MmsDataAccessError -writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter) +writeAccessHandler (DataAttribute* dataAttribute, char* dataRef, MmsValue* value, ClientConnection connection, void* parameter) { if (dataAttribute == IEDMODEL_Inverter_ZINV1_OutVarSet_setMag_f) { diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 52e1723a..341f41b3 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1713,6 +1713,7 @@ MmsGooseControlBlock_getNdsCom(MmsGooseControlBlock self); * stack will not update the value automatically. * * \param the data attribute that has been written by an MMS client. + * \param the dataRef the data reference for alternate access * \param the value the client want to write to the data attribute * \param connection the connection object of the client connection that invoked the write operation * \param parameter the user provided parameter @@ -1720,7 +1721,7 @@ MmsGooseControlBlock_getNdsCom(MmsGooseControlBlock self); * \return DATA_ACCESS_ERROR_SUCCESS, or DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE if access is accepted, DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED if access is denied. */ typedef MmsDataAccessError -(*WriteAccessHandler) (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter); +(*WriteAccessHandler) (DataAttribute* dataAttribute, char* dataRef, MmsValue* value, ClientConnection connection, void* parameter); /** * \brief Install a WriteAccessHandler for a data attribute. diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index a42de343..d3b4145e 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -2530,7 +2530,7 @@ getAccessPolicyForFC(MmsMapping* self, FunctionalConstraint fc) static MmsDataAccessError mmsWriteHandler(void* parameter, MmsDomain* domain, - char* variableId, MmsValue* value, MmsServerConnection connection) + char* variableId, char* dataRef, MmsValue* value, MmsServerConnection connection) { MmsMapping* self = (MmsMapping*) parameter; @@ -2838,11 +2838,6 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, cachedValue = MmsServer_getValueFromCache(self->mmsServer, domain, variableId); if (cachedValue) { - - if (!MmsValue_equalTypes(cachedValue, value)) { - return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; - } - bool handlerFound = false; AccessPolicy nodeAccessPolicy = getAccessPolicyForFC(self, fc); @@ -2878,7 +2873,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, connection); MmsDataAccessError handlerResult = - accessHandler->handler(dataAttribute, value, clientConnection, + accessHandler->handler(dataAttribute, dataRef, value, clientConnection, accessHandler->parameter); if ((handlerResult == DATA_ACCESS_ERROR_SUCCESS) || (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE)) { diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index 5e2f458d..c9730ce5 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -403,6 +403,10 @@ LIB61850_INTERNAL MmsDataAccessError mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value, MmsServerConnection connection); +LIB61850_INTERNAL MmsDataAccessError +mmsServer_setValueWithAlternateAccess(MmsServer self, MmsDomain* domain, char* itemId, AlternateAccess_t* alternateAccess, + MmsVariableSpecification* variable, MmsValue* value, MmsServerConnection connection); + /** * \brief Get the current value of a variable in the server data model * diff --git a/src/mms/inc_private/mms_server_libinternal.h b/src/mms/inc_private/mms_server_libinternal.h index e44bb643..d3878300 100644 --- a/src/mms/inc_private/mms_server_libinternal.h +++ b/src/mms/inc_private/mms_server_libinternal.h @@ -34,7 +34,7 @@ typedef MmsDataAccessError (*MmsReadAccessHandler) (void* parameter, MmsDomain* char* variableId, MmsServerConnection connection, bool isDirectAccess); typedef MmsDataAccessError (*MmsWriteVariableHandler)(void* parameter, - MmsDomain* domain, char* variableId, MmsValue* value, + MmsDomain* domain, char* variableId, char* dataRef, MmsValue* value, MmsServerConnection connection); typedef void (*MmsConnectionHandler)(void* parameter, diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index aa77f5ab..e292115e 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -481,15 +481,116 @@ MmsServer_insertIntoCache(MmsServer self, MmsDomain* domain, char* itemId, MmsVa } } +static bool +isAccessToArrayComponent(AlternateAccess_t* alternateAccess) +{ + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess != NULL) + { + if (alternateAccess->list.array[0]->choice.unnamed-> + choice.selectAlternateAccess.alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present == + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component) + { + return true; + } + else + return false; + } + else + return false; +} + +static MmsValue* +getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVariableSpecification* namedVariable, + MmsValue* structuredValue, char* dataRefBuf) +{ + MmsValue* retValue = NULL ; + + if (isAccessToArrayComponent(alternateAccess)) + { + Identifier_t component = alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess + ->list.array[0]->choice.unnamed->choice.selectAccess.choice.component; + + if (component.size > 129) + goto exit_function; + + MmsVariableSpecification* structSpec; + + if (namedVariable->type == MMS_ARRAY) + structSpec = namedVariable->typeSpec.array.elementTypeSpec; + else if (namedVariable->type == MMS_STRUCTURE) + structSpec = namedVariable; + else + goto exit_function; + + int i; + for (i = 0; i < structSpec->typeSpec.structure.elementCount; i++) { + + if ((int)strlen(structSpec->typeSpec.structure.elements[i]->name) + == component.size) { + if (strncmp(structSpec->typeSpec.structure.elements[i]->name, + (char*)component.buf, component.size) == 0) { + + snprintf(dataRefBuf, 129, "%s.%s", dataRefBuf, (char*)component.buf); + + MmsValue* value = MmsValue_getElement(structuredValue, i); + + if (isAccessToArrayComponent( + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess)) { + retValue = + getComponentOfArrayElement( + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess, + structSpec->typeSpec.structure.elements[i], + value, dataRefBuf); + } + else + retValue = value; + + goto exit_function; + } + } + } + } + +exit_function: + return retValue; +} + +static char* +mmsServer_getDataRef(MmsDomain* domain, char* itemId) { + char dataRefBuf[130]; + + const char* separator = strchr(itemId, '$'); + + if (separator != NULL) { + snprintf(dataRefBuf, 129, "%s/", domain->domainName); + + int bufOffset = strlen(domain->domainName) + 1; + + strncpy(dataRefBuf + bufOffset, itemId, 129 - bufOffset); + + bufOffset += separator - itemId; + + strncpy(dataRefBuf + bufOffset, separator + 3, 129 - bufOffset); + } + + dataRefBuf[129] = 0; + + StringUtils_replace(dataRefBuf, '$', '.'); + + return dataRefBuf; +} + MmsDataAccessError mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value, MmsServerConnection connection) { MmsDataAccessError indication; + char* dataRefBuf = mmsServer_getDataRef(domain, itemId); + if (self->writeHandler != NULL) { indication = self->writeHandler(self->writeHandlerParameter, domain, - itemId, value, connection); + itemId, dataRefBuf, value, connection); } else { MmsValue* cachedValue; @@ -509,6 +610,96 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va return indication; } +MmsDataAccessError +mmsServer_setValueWithAlternateAccess(MmsServer self, MmsDomain* domain, char* itemId, AlternateAccess_t* alternateAccess, MmsVariableSpecification* variable, + MmsValue* value, MmsServerConnection connection) +{ + MmsDataAccessError indication; + + char* dataRefBuf = mmsServer_getDataRef(domain, itemId); + + MmsValue* cachedArray; + + if (domain == NULL) + domain = (MmsDomain*)self->device; + + cachedArray = MmsServer_getValueFromCache(self, domain, itemId); + + if (cachedArray != NULL) { + + int index = mmsServer_getLowIndex(alternateAccess); + int numberOfElements = mmsServer_getNumberOfElements(alternateAccess); + + snprintf(dataRefBuf, 129, "%s(%d)", dataRefBuf, index); + + if (numberOfElements == 0) { /* select single array element with index */ + + MmsValue* elementValue; + + if (isAccessToArrayComponent(alternateAccess)) { + if (variable->typeSpec.array.elementTypeSpec->type != MMS_STRUCTURE) { + indication = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; + goto exit_function; + } + + MmsValue* structValue = MmsValue_getElement(cachedArray, index); + + if (structValue == NULL) { + indication = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; + goto exit_function; + } + + elementValue = getComponentOfArrayElement(alternateAccess, variable, structValue, dataRefBuf); + } + else { + elementValue = MmsValue_getElement(cachedArray, index); + } + + if (self->writeHandler == NULL) { + if (MmsValue_update(elementValue, value) == false) { + indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; + goto exit_function; + } + } + } + else { /* select sub-array with start-index and number-of-elements */ + + if (MmsValue_getType(value) != MMS_ARRAY) { + indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; + } + else { + if (self->writeHandler == NULL) { + int elementNo; + + for (elementNo = 0; elementNo < numberOfElements; elementNo++) { + MmsValue* newElement = MmsValue_getElement(value, elementNo); + MmsValue* elementValue = MmsValue_getElement(cachedArray, index++); + + if ((elementValue == NULL) || (newElement == NULL)) + indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; + else if (MmsValue_update(elementValue, newElement) == false) { + indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; + goto exit_function; + } + } + } + } + } + + indication = DATA_ACCESS_ERROR_SUCCESS; + + if (self->writeHandler != NULL) { + indication = self->writeHandler(self->writeHandlerParameter, domain, + itemId, dataRefBuf, value, connection); + } + } + else + indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + +exit_function: + return indication; +} + MmsValue* mmsServer_getValue(MmsServer self, MmsDomain* domain, char* itemId, MmsServerConnection connection, bool isDirectAccess) { diff --git a/src/mms/iso_mms/server/mms_write_service.c b/src/mms/iso_mms/server/mms_write_service.c index 31a171e4..56e545d4 100644 --- a/src/mms/iso_mms/server/mms_write_service.c +++ b/src/mms/iso_mms/server/mms_write_service.c @@ -615,74 +615,22 @@ mmsServer_handleWriteRequest( continue; } - if (alternateAccess != NULL) { - - if (domain == NULL) - domain = (MmsDomain*) device; + MmsDataAccessError valueIndication; - MmsValue* cachedArray = MmsServer_getValueFromCache(connection->server, domain, nameIdStr); - - if (cachedArray == NULL) { - accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; + if (alternateAccess != NULL) { + valueIndication = + mmsServer_setValueWithAlternateAccess(connection->server, domain, nameIdStr, alternateAccess, variable, value, connection); + } + else { + /* Check for correct type */ + if (MmsVariableSpecification_isValueOfType(variable, value) == false) { + accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; goto end_of_main_loop; } - int index = mmsServer_getLowIndex(alternateAccess); - int numberOfElements = mmsServer_getNumberOfElements(alternateAccess); - - if (numberOfElements == 0) { /* select single array element with index */ - - MmsValue* elementValue = MmsValue_getElement(cachedArray, index); - - if (elementValue == NULL) { - accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; - goto end_of_main_loop; - } - - if (MmsValue_update(elementValue, value) == false) { - accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; - goto end_of_main_loop; - } - } - else { /* select sub-array with start-index and number-of-elements */ - - if (MmsValue_getType(value) != MMS_ARRAY) { - accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; - goto end_of_main_loop; - } - - int elementNo; - - for (elementNo = 0; elementNo < numberOfElements; elementNo++) { - MmsValue* newElement = MmsValue_getElement(value, elementNo); - MmsValue* elementValue = MmsValue_getElement(cachedArray, index++); - - if ((elementValue == NULL) || (newElement == NULL) ) { - accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; - goto end_of_main_loop; - } - - if (MmsValue_update(elementValue, newElement) == false) { - accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; - goto end_of_main_loop; - } - - } - } - - accessResults[i] = DATA_ACCESS_ERROR_SUCCESS; - goto end_of_main_loop; - - } - - /* Check for correct type */ - if (MmsVariableSpecification_isValueOfType(variable, value) == false) { - accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; - goto end_of_main_loop; - } - - MmsDataAccessError valueIndication = + valueIndication = mmsServer_setValue(connection->server, domain, nameIdStr, value, connection); + } if (valueIndication == DATA_ACCESS_ERROR_NO_RESPONSE) sendResponse = false;