- IED server: implemented write access handler for array elements and components of array elements (LIB61850-437)

- IED server: new function IedServer_handleWriteAccessForDataObject (LIB61850-437)
pull/515/head
Michael Zillgith 1 year ago
parent d1ab50298f
commit 3280712e5a

@ -429,11 +429,11 @@ getCharWeight(int c)
{
static bool initialized = false;
static char lookupTable[LT_MAX_CHARS + 1];
static const char* charOrder = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz$_0123456789";
if (!initialized) {
int ltIndex;
int weight = 1;
const char* charOrder = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz$_0123456789";
for (ltIndex = 1; ltIndex < LT_MAX_CHARS; ltIndex++) {
if (strchr(charOrder, ltIndex)) continue;

@ -3,7 +3,7 @@
*
* IEC 61850 server API for libiec61850.
*
* Copyright 2013-2023 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -1845,6 +1845,19 @@ LIB61850_API void
IedServer_handleWriteAccessForComplexAttribute(IedServer self, DataAttribute* dataAttribute,
WriteAccessHandler handler, void* parameter);
/**
* \brief Install a WriteAccessHandler for all data attributes of a data object with a specific FC
*
* \param self the instance of IedServer to operate on.
* \param dataObject the data object to monitor
* \param fc the functional constraint to monitor
* \param handler the callback function that is invoked if a client tries to write to
* the monitored data attribute.
* \param parameter a user provided parameter that is passed to the WriteAccessHandler when called.
*/
LIB61850_API void
IedServer_handleWriteAccessForDataObject(IedServer self, DataObject* dataObject, FunctionalConstraint fc, WriteAccessHandler handler, void* parameter);
typedef enum {
ACCESS_POLICY_ALLOW,
ACCESS_POLICY_DENY

@ -124,7 +124,7 @@ LIB61850_INTERNAL MmsValue*
LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsServerConnection connection);
LIB61850_INTERNAL MmsDataAccessError
LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig,
MmsValue* value, MmsServerConnection connection);
#endif /* LIBIEC61850_SRC_IEC61850_INC_PRIVATE_LOGGING_H_ */

@ -149,7 +149,7 @@ LIB61850_INTERNAL void
MmsMapping_installReadAccessHandler(MmsMapping* self, ReadAccessHandler handler, void* paramter);
LIB61850_INTERNAL MmsDataAccessError
Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig,
MmsValue* value, MmsServerConnection connection);
LIB61850_INTERNAL MmsValue*

@ -41,7 +41,7 @@ LIB61850_INTERNAL MmsValue*
LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig , MmsServerConnection connection);
LIB61850_INTERNAL MmsDataAccessError
LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig,
MmsValue* value, MmsServerConnection connection);
LIB61850_INTERNAL void

@ -126,7 +126,7 @@ LIB61850_INTERNAL void
ReportControl_valueUpdated(ReportControl* self, int dataSetEntryIndex, int flag, bool modelLocked);
LIB61850_INTERNAL MmsValue*
ReportControl_getRCBValue(ReportControl* rc, char* elementName);
ReportControl_getRCBValue(ReportControl* rc, const char* elementName);
LIB61850_INTERNAL MmsVariableSpecification*
Reporting_createMmsBufferedRCBs(MmsMapping* self, MmsDomain* domain,
@ -137,7 +137,7 @@ Reporting_createMmsUnbufferedRCBs(MmsMapping* self, MmsDomain* domain,
LogicalNode* logicalNode, int reportsCount);
LIB61850_INTERNAL MmsDataAccessError
Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value,
Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, const char* elementName, MmsValue* value,
MmsServerConnection connection);
LIB61850_INTERNAL bool

@ -1679,6 +1679,38 @@ IedServer_handleWriteAccessForComplexAttribute(IedServer self, DataAttribute* da
}
}
void
IedServer_handleWriteAccessForDataObject(IedServer self, DataObject* dataObject, FunctionalConstraint fc, WriteAccessHandler handler, void* parameter)
{
if (dataObject == NULL) {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: IedServer_handlerWriteAccessForDataObject - dataObject == NULL!\n");
}
else
{
ModelNode* childElement = dataObject->firstChild;
while (childElement)
{
if (childElement->modelType == DataAttributeModelType)
{
DataAttribute* dataAttribute = (DataAttribute*) childElement;
if (dataAttribute->fc == fc)
{
IedServer_handleWriteAccessForComplexAttribute(self, dataAttribute, handler, parameter);
}
}
else if (childElement->modelType == DataObjectModelType)
{
IedServer_handleWriteAccessForDataObject(self, (DataObject*) childElement, fc, handler, parameter);
}
childElement = childElement->sibling;
}
}
}
void
IedServer_setReadAccessHandler(IedServer self, ReadAccessHandler handler, void* parameter)
{

@ -1923,7 +1923,7 @@ checkValidityOfOriginParameter(MmsValue* origin)
}
MmsDataAccessError
Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig,
MmsValue* value, MmsServerConnection connection)
{
MmsDataAccessError indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;

@ -482,7 +482,7 @@ copyLCBValuesToTrackingObject(MmsMapping* self, LogControl* logControl)
#endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */
MmsDataAccessError
LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig,
MmsValue* value, MmsServerConnection connection)
{
(void)connection;

@ -2344,7 +2344,7 @@ lookupGCB(MmsMapping* self, MmsDomain* domain, char* lnName, char* objectName)
#endif
static MmsDataAccessError
writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig,
MmsValue* value, MmsServerConnection connection)
{
char variableId[130];
@ -2605,12 +2605,24 @@ getAccessPolicyForFC(MmsMapping* self, FunctionalConstraint fc)
static MmsDataAccessError
mmsWriteHandler(void* parameter, MmsDomain* domain,
char* variableId, MmsValue* value, MmsServerConnection connection)
const char* variableId, int arrayIdx, const char* componentId, MmsValue* value, MmsServerConnection connection)
{
MmsMapping* self = (MmsMapping*) parameter;
if (DEBUG_IED_SERVER)
{
if (arrayIdx != -1) {
if (componentId) {
printf("IED_SERVER: Write requested %s(%i).%s\n", variableId, arrayIdx, componentId);
}
else {
printf("IED_SERVER: Write requested %s(%i)\n", variableId, arrayIdx);
}
}
else {
printf("IED_SERVER: Write requested %s\n", variableId);
}
}
/* Access control based on functional constraint */
@ -2691,7 +2703,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
if (rcNameLen == variableIdLen) {
if (strncmp(variableId, rc->name, variableIdLen) == 0) {
char* elementName = variableId + rcNameLen + 1;
const char* elementName = variableId + rcNameLen + 1;
return Reporting_RCBWriteAccessHandler(self, rc, elementName, value, connection);
}
@ -2946,13 +2958,19 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */
/* writable data model elements - SP, SV, CF, DC, BL */
if (fc != IEC61850_FC_NONE) {
if (fc != IEC61850_FC_NONE)
{
MmsValue* cachedValue;
if (arrayIdx != -1) {
cachedValue = MmsServer_getValueFromCacheEx2(self->mmsServer, domain, variableId, arrayIdx, componentId);
}
else {
cachedValue = MmsServer_getValueFromCache(self->mmsServer, domain, variableId);
}
if (cachedValue) {
if (cachedValue)
{
if (!MmsValue_equalTypes(cachedValue, value)) {
return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
}
@ -2965,7 +2983,8 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
printf("IED_SERVER: write to %s policy:%i\n", variableId, nodeAccessPolicy);
#if (CONFIG_IEC61850_SETTING_GROUPS == 1)
if (isFunctionalConstraint("SE", separator)) {
if (isFunctionalConstraint("SE", separator))
{
SettingGroup* sg = getSettingGroupByMmsDomain(self, domain);
if (sg != NULL) {
@ -2982,12 +3001,13 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
/* Call write access handlers */
LinkedList writeHandlerListElement = LinkedList_getNext(self->attributeAccessHandlers);
while (writeHandlerListElement != NULL) {
while (writeHandlerListElement)
{
AttributeAccessHandler* accessHandler = (AttributeAccessHandler*) writeHandlerListElement->data;
DataAttribute* dataAttribute = accessHandler->attribute;
if (dataAttribute->mmsValue == cachedValue) {
if (dataAttribute->mmsValue == cachedValue)
{
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer,
connection);
@ -2995,7 +3015,8 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
accessHandler->handler(dataAttribute, value, clientConnection,
accessHandler->parameter);
if ((handlerResult == DATA_ACCESS_ERROR_SUCCESS) || (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE)) {
if ((handlerResult == DATA_ACCESS_ERROR_SUCCESS) || (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE))
{
handlerFound = true;
if (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE)
@ -3011,14 +3032,14 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
}
/* DENY access if no handler is found and default policy is DENY */
if (!handlerFound) {
if (!handlerFound)
{
if (nodeAccessPolicy == ACCESS_POLICY_DENY)
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
}
if (updateValue) {
if (updateValue)
{
DataAttribute* da = IedModel_lookupDataAttributeByMmsValue(self->model, cachedValue);
if (da)

@ -131,7 +131,7 @@ MmsSampledValueControlBlock_isEnabled(MmsSampledValueControlBlock self)
}
MmsDataAccessError
LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig,
MmsValue* value, MmsServerConnection connection)
{
char variableId[130];

@ -252,7 +252,7 @@ ReportControl_destroy(ReportControl* self)
}
MmsValue*
ReportControl_getRCBValue(ReportControl* rc, char* elementName)
ReportControl_getRCBValue(ReportControl* rc, const char* elementName)
{
if (rc->buffered) {
if (strcmp(elementName, "RptID") == 0)
@ -460,7 +460,7 @@ copyRCBValuesToTrackingObject(MmsMapping* self, ReportControl* rc)
}
static void
updateSingleTrackingValue(MmsMapping* self, ReportControl* rc, char* name, MmsValue* newValue)
updateSingleTrackingValue(MmsMapping* self, ReportControl* rc, const char* name, MmsValue* newValue)
{
if (rc->buffered) {
if (self->brcbTrk) {
@ -1906,7 +1906,7 @@ reserveRcb(ReportControl* rc, MmsServerConnection connection)
}
MmsDataAccessError
Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value,
Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, const char* elementName, MmsValue* value,
MmsServerConnection connection)
{
MmsDataAccessError retVal = DATA_ACCESS_ERROR_SUCCESS;

@ -399,7 +399,7 @@ mmsServer_isAccessToArrayComponent(AlternateAccess_t* alternateAccess);
LIB61850_INTERNAL MmsValue*
mmsServer_getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVariableSpecification* namedVariable,
MmsValue* structuredValue);
MmsValue* structuredValue, char* componentId);
LIB61850_INTERNAL int
mmsServer_getLowIndex(AlternateAccess_t* alternateAccess);
@ -417,6 +417,10 @@ LIB61850_INTERNAL MmsDataAccessError
mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value,
MmsServerConnection connection);
LIB61850_INTERNAL MmsDataAccessError
mmsServer_setValueEx(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value,
MmsServerConnection connection, int arrayIdx, const char* componentId);
/**
* \brief Get the current value of a variable in the server data model
*

@ -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, const char* variableId, int arrayIdx, const char* componentId, MmsValue* value,
MmsServerConnection connection);
typedef bool (*MmsListAccessHandler) (void* parameter, MmsGetNameListType listType, MmsDomain* domain,

@ -202,30 +202,35 @@ alternateArrayAccess(MmsServerConnection connection,
MmsValue* arrayValue = mmsServer_getValue(connection->server, domain, itemId, connection, false);
if (arrayValue != NULL) {
if (arrayValue != NULL)
{
MmsValue* value = NULL;
if (numberOfElements == 0)
if (mmsServer_isAccessToArrayComponent(alternateAccess)) {
{
if (mmsServer_isAccessToArrayComponent(alternateAccess))
{
if (namedVariable->typeSpec.array.elementTypeSpec->type == MMS_STRUCTURE) {
MmsValue* structValue = MmsValue_getElement(arrayValue, index);
if (structValue != NULL)
value = mmsServer_getComponentOfArrayElement(alternateAccess,
namedVariable, structValue);
namedVariable, structValue, NULL);
}
}
else {
value = MmsValue_getElement(arrayValue, index);
}
else {
}
else
{
value = MmsValue_createEmptyArray(numberOfElements);
MmsValue_setDeletable(value);
int resultIndex = 0;
while (index < lowIndex + numberOfElements) {
while (index < lowIndex + numberOfElements)
{
MmsValue* elementValue = NULL;
elementValue = MmsValue_getElement(arrayValue, index);

@ -536,9 +536,10 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va
{
MmsDataAccessError indication;
if (self->writeHandler != NULL) {
if (self->writeHandler)
{
indication = self->writeHandler(self->writeHandlerParameter, domain,
itemId, value, connection);
itemId, -1, NULL, value, connection);
}
else {
MmsValue* cachedValue;
@ -548,7 +549,36 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va
cachedValue = MmsServer_getValueFromCache(self, domain, itemId);
if (cachedValue != NULL) {
if (cachedValue) {
MmsValue_update(cachedValue, value);
indication = DATA_ACCESS_ERROR_SUCCESS;
} else
indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
}
return indication;
}
MmsDataAccessError
mmsServer_setValueEx(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value,
MmsServerConnection connection, int arrayIdx, const char* componentId)
{
MmsDataAccessError indication;
if (self->writeHandler)
{
indication = self->writeHandler(self->writeHandlerParameter, domain,
itemId, arrayIdx, componentId, value, connection);
}
else {
MmsValue* cachedValue = NULL;
if (domain == NULL)
domain = (MmsDomain*) self->device;
cachedValue = MmsServer_getValueFromCacheEx2(self, domain, itemId, arrayIdx, componentId);
if (cachedValue) {
MmsValue_update(cachedValue, value);
indication = DATA_ACCESS_ERROR_SUCCESS;
} else
@ -591,8 +621,6 @@ mmsServer_checkReadAccess(MmsServer self, MmsDomain* domain, char* itemId, MmsSe
{
MmsDataAccessError accessError = DATA_ACCESS_ERROR_SUCCESS;
printf("mmsServer_checkReadAccess(%s/%s)\n", domain->domainName, itemId);
if (self->readAccessHandler) {
accessError =
self->readAccessHandler(self->readAccessHandlerParameter, (domain == (MmsDomain*) self->device) ? NULL : domain,

@ -287,7 +287,7 @@ mmsServer_isAccessToArrayComponent(AlternateAccess_t* alternateAccess)
MmsValue*
mmsServer_getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVariableSpecification* namedVariable,
MmsValue* structuredValue)
MmsValue* structuredValue, char* componentId)
{
MmsValue* retValue = NULL;
@ -319,16 +319,33 @@ mmsServer_getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVari
{
MmsValue* value = MmsValue_getElement(structuredValue, i);
if (value)
{
if (mmsServer_isAccessToArrayComponent(
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess)) {
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess))
{
if (componentId)
{
strcat(componentId, structSpec->typeSpec.structure.elements[i]->name);
strcat(componentId, "$");
}
retValue =
mmsServer_getComponentOfArrayElement(
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess,
structSpec->typeSpec.structure.elements[i],
value);
value, componentId);
}
else
{
if (componentId)
{
strcat(componentId, structSpec->typeSpec.structure.elements[i]->name);
}
retValue = value;
}
}
goto exit_function;
}

@ -517,33 +517,36 @@ getComponent(MmsServerConnection connection, MmsDomain* domain, AlternateAccess_
{
MmsVariableSpecification* retValue = NULL;
if (mmsServer_isComponentAccess(alternateAccess)) {
if (mmsServer_isComponentAccess(alternateAccess))
{
Identifier_t component =
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component;
if (component.size > 129)
goto exit_function;
if (namedVariable->type == MMS_STRUCTURE) {
if (namedVariable->type == MMS_STRUCTURE)
{
int i;
for (i = 0; i < namedVariable->typeSpec.structure.elementCount; i++) {
for (i = 0; i < namedVariable->typeSpec.structure.elementCount; i++)
{
if ((int) strlen(namedVariable->typeSpec.structure.elements[i]->name)
== component.size) {
== component.size)
{
if (!strncmp(namedVariable->typeSpec.structure.elements[i]->name,
(char*) component.buf, component.size))
{
if (strlen(variableName) + component.size < 199) {
if (strlen(variableName) + component.size < 199)
{
StringUtils_appendString(variableName, 200, "$");
/* here we need strncat because component.buf is not null terminated! */
strncat(variableName, (const char*)component.buf, (size_t)component.size);
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess
!= NULL) {
!= NULL)
{
retValue =
getComponent(connection, domain,
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess,
@ -690,7 +693,7 @@ mmsServer_handleWriteRequest(
AlternateAccess_t* alternateAccess = varSpec->alternateAccess;
if (alternateAccess != NULL)
if (alternateAccess)
{
if ((variable->type == MMS_STRUCTURE) && (mmsServer_isComponentAccess(alternateAccess) == false)) {
accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;
@ -717,7 +720,7 @@ mmsServer_handleWriteRequest(
continue;
}
if (alternateAccess != NULL)
if (alternateAccess)
{
if (domain == NULL)
domain = (MmsDomain*) device;
@ -747,18 +750,26 @@ mmsServer_handleWriteRequest(
{
MmsVariableSpecification* namedVariable = MmsDomain_getNamedVariable(domain, nameIdStr);
char componentId[65];
componentId[0] = 0;
if (namedVariable) {
elementValue = mmsServer_getComponentOfArrayElement(alternateAccess, namedVariable, elementValue);
elementValue = mmsServer_getComponentOfArrayElement(alternateAccess, namedVariable, elementValue, componentId);
}
if ((namedVariable == NULL) || (elementValue == NULL)) {
accessResults[i] = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT;
goto end_of_main_loop;
}
else
{
accessResults[i] = mmsServer_setValueEx(connection->server, domain, nameIdStr, value, connection, index, componentId);
}
if (MmsValue_update(elementValue, value) == false) {
accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
goto end_of_main_loop;
}
else
{
accessResults[i] = mmsServer_setValueEx(connection->server, domain, nameIdStr, value, connection, index, NULL);
goto end_of_main_loop;
}
}
@ -816,16 +827,13 @@ mmsServer_handleWriteRequest(
goto end_of_main_loop;
}
MmsDataAccessError valueIndication =
mmsServer_setValue(connection->server, domain, nameIdStr, value, connection);
if (valueIndication == DATA_ACCESS_ERROR_NO_RESPONSE)
sendResponse = false;
accessResults[i] = valueIndication;
accessResults[i] = mmsServer_setValue(connection->server, domain, nameIdStr, value, connection);
end_of_main_loop:
if (accessResults[i] == DATA_ACCESS_ERROR_NO_RESPONSE)
sendResponse = false;
MmsValue_delete(value);
}

Loading…
Cancel
Save