static UA_StatusCode CopyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, const UA_WriteValue *wvalue) { if(!wvalue->value.hasValue) return UA_STATUSCODE_BADNODATA; void *value = wvalue->value.value.data; void *target = NULL; const UA_DataType *type = NULL; UA_StatusCode retval = UA_STATUSCODE_GOOD; switch(wvalue->attributeId) { case UA_ATTRIBUTEID_NODEID: case UA_ATTRIBUTEID_NODECLASS: case UA_ATTRIBUTEID_DATATYPE: retval = UA_STATUSCODE_BADWRITENOTSUPPORTED; break; case UA_ATTRIBUTEID_BROWSENAME: CHECK_DATATYPE(QUALIFIEDNAME); target = &node->browseName; type = &UA_TYPES[UA_TYPES_QUALIFIEDNAME]; break; case UA_ATTRIBUTEID_DISPLAYNAME: CHECK_DATATYPE(LOCALIZEDTEXT); target = &node->displayName; type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]; break; case UA_ATTRIBUTEID_DESCRIPTION: CHECK_DATATYPE(LOCALIZEDTEXT); target = &node->description; type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]; break; case UA_ATTRIBUTEID_WRITEMASK: CHECK_DATATYPE(UINT32); node->writeMask = *(UA_UInt32*)value; break; case UA_ATTRIBUTEID_USERWRITEMASK: CHECK_DATATYPE(UINT32); node->userWriteMask = *(UA_UInt32*)value; break; case UA_ATTRIBUTEID_ISABSTRACT: CHECK_NODECLASS_WRITE(UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_VARIABLETYPE | UA_NODECLASS_DATATYPE); CHECK_DATATYPE(BOOLEAN); ((UA_ObjectTypeNode*)node)->isAbstract = *(UA_Boolean*)value; break; case UA_ATTRIBUTEID_SYMMETRIC: CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE); CHECK_DATATYPE(BOOLEAN); ((UA_ReferenceTypeNode*)node)->symmetric = *(UA_Boolean*)value; break; case UA_ATTRIBUTEID_INVERSENAME: CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE); CHECK_DATATYPE(LOCALIZEDTEXT); target = &((UA_ReferenceTypeNode*)node)->inverseName; type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]; break; case UA_ATTRIBUTEID_CONTAINSNOLOOPS: CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW); CHECK_DATATYPE(BOOLEAN); ((UA_ViewNode*)node)->containsNoLoops = *(UA_Boolean*)value; break; case UA_ATTRIBUTEID_EVENTNOTIFIER: CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT); CHECK_DATATYPE(BYTE); ((UA_ViewNode*)node)->eventNotifier = *(UA_Byte*)value; break; case UA_ATTRIBUTEID_VALUE: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); if(((const UA_VariableNode*)node)->valueSource == UA_VALUESOURCE_VARIANT) retval = CopyValueIntoNode((UA_VariableNode*)node, wvalue); else retval = Service_Write_single_ValueDataSource(server, session, (const UA_VariableNode*)node, wvalue); break; case UA_ATTRIBUTEID_ACCESSLEVEL: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_DATATYPE(BYTE); ((UA_VariableNode*)node)->accessLevel = *(UA_Byte*)value; break; case UA_ATTRIBUTEID_USERACCESSLEVEL: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_DATATYPE(BYTE); ((UA_VariableNode*)node)->userAccessLevel = *(UA_Byte*)value; break; case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_DATATYPE(DOUBLE); ((UA_VariableNode*)node)->minimumSamplingInterval = *(UA_Double*)value; break; case UA_ATTRIBUTEID_HISTORIZING: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_DATATYPE(BOOLEAN); ((UA_VariableNode*)node)->historizing = *(UA_Boolean*)value; break; case UA_ATTRIBUTEID_EXECUTABLE: CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD); CHECK_DATATYPE(BOOLEAN); ((UA_MethodNode*)node)->executable = *(UA_Boolean*)value; break; case UA_ATTRIBUTEID_USEREXECUTABLE: CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD); CHECK_DATATYPE(BOOLEAN); ((UA_MethodNode*)node)->userExecutable = *(UA_Boolean*)value; break; default: retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID; break; } if(type) { UA_deleteMembers(target, type); retval = UA_copy(value, target, type); } return retval; }
/* This function implements the main part of the write service and operates on a copy of the node (not in single-threaded mode). */ static UA_StatusCode copyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, const UA_WriteValue *wvalue) { const void *value = wvalue->value.value.data; UA_UInt32 userWriteMask = getUserWriteMask(server, session, node); UA_StatusCode retval = UA_STATUSCODE_GOOD; const UA_VariableTypeNode *type; switch(wvalue->attributeId) { case UA_ATTRIBUTEID_NODEID: case UA_ATTRIBUTEID_NODECLASS: case UA_ATTRIBUTEID_USERWRITEMASK: case UA_ATTRIBUTEID_USERACCESSLEVEL: case UA_ATTRIBUTEID_USEREXECUTABLE: retval = UA_STATUSCODE_BADWRITENOTSUPPORTED; break; case UA_ATTRIBUTEID_BROWSENAME: CHECK_USERWRITEMASK(UA_WRITEMASK_BROWSENAME); CHECK_DATATYPE_SCALAR(QUALIFIEDNAME); UA_QualifiedName_deleteMembers(&node->browseName); UA_QualifiedName_copy((const UA_QualifiedName *)value, &node->browseName); break; case UA_ATTRIBUTEID_DISPLAYNAME: CHECK_USERWRITEMASK(UA_WRITEMASK_DISPLAYNAME); CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT); UA_LocalizedText_deleteMembers(&node->displayName); UA_LocalizedText_copy((const UA_LocalizedText *)value, &node->displayName); break; case UA_ATTRIBUTEID_DESCRIPTION: CHECK_USERWRITEMASK(UA_WRITEMASK_DESCRIPTION); CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT); UA_LocalizedText_deleteMembers(&node->description); UA_LocalizedText_copy((const UA_LocalizedText *)value, &node->description); break; case UA_ATTRIBUTEID_WRITEMASK: CHECK_USERWRITEMASK(UA_WRITEMASK_WRITEMASK); CHECK_DATATYPE_SCALAR(UINT32); node->writeMask = *(const UA_UInt32*)value; break; case UA_ATTRIBUTEID_ISABSTRACT: CHECK_USERWRITEMASK(UA_WRITEMASK_ISABSTRACT); CHECK_DATATYPE_SCALAR(BOOLEAN); retval = writeIsAbstractAttribute(node, *(const UA_Boolean*)value); break; case UA_ATTRIBUTEID_SYMMETRIC: CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE); CHECK_USERWRITEMASK(UA_WRITEMASK_SYMMETRIC); CHECK_DATATYPE_SCALAR(BOOLEAN); ((UA_ReferenceTypeNode*)node)->symmetric = *(const UA_Boolean*)value; break; case UA_ATTRIBUTEID_INVERSENAME: CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE); CHECK_USERWRITEMASK(UA_WRITEMASK_INVERSENAME); CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT); UA_LocalizedText_deleteMembers(&((UA_ReferenceTypeNode*)node)->inverseName); UA_LocalizedText_copy((const UA_LocalizedText *)value, &((UA_ReferenceTypeNode*)node)->inverseName); break; case UA_ATTRIBUTEID_CONTAINSNOLOOPS: CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW); CHECK_USERWRITEMASK(UA_WRITEMASK_CONTAINSNOLOOPS); CHECK_DATATYPE_SCALAR(BOOLEAN); ((UA_ViewNode*)node)->containsNoLoops = *(const UA_Boolean*)value; break; case UA_ATTRIBUTEID_EVENTNOTIFIER: CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT); CHECK_USERWRITEMASK(UA_WRITEMASK_EVENTNOTIFIER); CHECK_DATATYPE_SCALAR(BYTE); ((UA_ViewNode*)node)->eventNotifier = *(const UA_Byte*)value; break; case UA_ATTRIBUTEID_VALUE: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); if(node->nodeClass == UA_NODECLASS_VARIABLE) { /* The access to a value variable is granted via the AccessLevel * and UserAccessLevel attributes */ UA_Byte accessLevel = getAccessLevel(server, session, (const UA_VariableNode*)node); if(!(accessLevel & (UA_ACCESSLEVELMASK_WRITE))) { retval = UA_STATUSCODE_BADNOTWRITABLE; break; } accessLevel = getUserAccessLevel(server, session, (const UA_VariableNode*)node); if(!(accessLevel & (UA_ACCESSLEVELMASK_WRITE))) { retval = UA_STATUSCODE_BADUSERACCESSDENIED; break; } } else { /* UA_NODECLASS_VARIABLETYPE */ CHECK_USERWRITEMASK(UA_WRITEMASK_VALUEFORVARIABLETYPE); } retval = writeValueAttribute(server, session, (UA_VariableNode*)node, &wvalue->value, &wvalue->indexRange); break; case UA_ATTRIBUTEID_DATATYPE: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); CHECK_USERWRITEMASK(UA_WRITEMASK_DATATYPE); CHECK_DATATYPE_SCALAR(NODEID); GET_NODETYPE retval = writeDataTypeAttribute(server, session, (UA_VariableNode*)node, type, (const UA_NodeId*)value); UA_Nodestore_release(server, (const UA_Node*)type); break; case UA_ATTRIBUTEID_VALUERANK: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); CHECK_USERWRITEMASK(UA_WRITEMASK_VALUERANK); CHECK_DATATYPE_SCALAR(INT32); GET_NODETYPE retval = writeValueRankAttribute(server, session, (UA_VariableNode*)node, type, *(const UA_Int32*)value); UA_Nodestore_release(server, (const UA_Node*)type); break; case UA_ATTRIBUTEID_ARRAYDIMENSIONS: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); CHECK_USERWRITEMASK(UA_WRITEMASK_ARRRAYDIMENSIONS); CHECK_DATATYPE_ARRAY(UINT32); GET_NODETYPE retval = writeArrayDimensionsAttribute(server, session, (UA_VariableNode*)node, type, wvalue->value.value.arrayLength, (UA_UInt32 *)wvalue->value.value.data); UA_Nodestore_release(server, (const UA_Node*)type); break; case UA_ATTRIBUTEID_ACCESSLEVEL: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_USERWRITEMASK(UA_WRITEMASK_ACCESSLEVEL); CHECK_DATATYPE_SCALAR(BYTE); ((UA_VariableNode*)node)->accessLevel = *(const UA_Byte*)value; break; case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_USERWRITEMASK(UA_WRITEMASK_MINIMUMSAMPLINGINTERVAL); CHECK_DATATYPE_SCALAR(DOUBLE); ((UA_VariableNode*)node)->minimumSamplingInterval = *(const UA_Double*)value; break; case UA_ATTRIBUTEID_HISTORIZING: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_USERWRITEMASK(UA_WRITEMASK_HISTORIZING); CHECK_DATATYPE_SCALAR(BOOLEAN); ((UA_VariableNode*)node)->historizing = *(const UA_Boolean*)value; break; case UA_ATTRIBUTEID_EXECUTABLE: CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD); CHECK_USERWRITEMASK(UA_WRITEMASK_EXECUTABLE); CHECK_DATATYPE_SCALAR(BOOLEAN); ((UA_MethodNode*)node)->executable = *(const UA_Boolean*)value; break; default: retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID; break; } if(retval != UA_STATUSCODE_GOOD) UA_LOG_INFO_SESSION(server->config.logger, session, "WriteRequest returned status code %s", UA_StatusCode_name(retval)); return retval; }