static UA_StatusCode parseReferenceTypeNode(UA_ExtensionObject *attributes, UA_Node **new_node) { UA_ReferenceTypeAttributes attr; size_t pos = 0; // todo return more informative error codes from decodeBinary if(UA_ReferenceTypeAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD) return UA_STATUSCODE_BADNODEATTRIBUTESINVALID; UA_ReferenceTypeNode *vnode = UA_ReferenceTypeNode_new(); if(!vnode) { UA_ReferenceTypeAttributes_deleteMembers(&attr); return UA_STATUSCODE_BADOUTOFMEMORY; } // now copy all the attributes. This potentially removes them from the decoded attributes. COPY_STANDARDATTRIBUTES; if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ISABSTRACT) vnode->isAbstract = attr.isAbstract; if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_SYMMETRIC) vnode->symmetric = attr.symmetric; if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_INVERSENAME) { vnode->inverseName = attr.inverseName; attr.inverseName.text.length = -1; attr.inverseName.text.data = UA_NULL; attr.inverseName.locale.length = -1; attr.inverseName.locale.data = UA_NULL; } UA_ReferenceTypeAttributes_deleteMembers(&attr); *new_node = (UA_Node*) vnode; return UA_STATUSCODE_GOOD; }
static UA_Server* makeTestSequence(void) { UA_Server *server = UA_Server_new(UA_ServerConfig_standard); /* VariableNode */ UA_Variant *myIntegerVariant = UA_Variant_new(); UA_Int32 myInteger = 42; UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]); const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer"); const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, UA_LOCALIZEDTEXT("en_US","the answer"), UA_LOCALIZEDTEXT("en_US","the answer"), 0, 0, parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL); /* ObjectNode */ UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 50), UA_QUALIFIEDNAME(1, "Demo"), UA_LOCALIZEDTEXT("en_US","Demo"), UA_LOCALIZEDTEXT("en_US","Demo"), 0, 0, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL); /* ReferenceTypeNode */ UA_ReferenceTypeNode *organizes = UA_ReferenceTypeNode_new(); copyNames((UA_Node*)organizes, "Organizes"); organizes->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "OrganizedBy"); organizes->nodeId.identifier.numeric = UA_NS0ID_ORGANIZES; organizes->isAbstract = UA_FALSE; organizes->symmetric = UA_FALSE; UA_Server_addNode(server, (UA_Node*)organizes, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE)); /* ViewNode */ UA_ViewNode *viewtest = UA_ViewNode_new(); copyNames((UA_Node*)viewtest, "Viewtest"); viewtest->nodeId.identifier.numeric = UA_NS0ID_VIEWNODE; UA_Server_addNode(server, (UA_Node*)viewtest, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE)); /* MethodNode */ UA_MethodNode *methodtest = UA_MethodNode_new(); copyNames((UA_Node*)methodtest, "Methodtest"); methodtest->nodeId.identifier.numeric = UA_NS0ID_METHODNODE; UA_Server_addNode(server, (UA_Node*)methodtest, UA_EXPANDEDNODEID_NUMERIC(0, 3), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE)); return server; }
static UA_Node * referenceTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ReferenceTypeAttributes *attr) { UA_ReferenceTypeNode *rtnode = UA_ReferenceTypeNode_new(); if(!rtnode) return NULL; UA_StatusCode retval = copyStandardAttributes((UA_Node*)rtnode, item, (const UA_NodeAttributes*)attr); rtnode->isAbstract = attr->isAbstract; rtnode->symmetric = attr->symmetric; retval |= UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName); if(retval != UA_STATUSCODE_GOOD) { UA_Node_deleteAnyNodeClass((UA_Node*)rtnode); return NULL; } return (UA_Node*)rtnode; }
/* Adds a one-way reference to the local nodestore */ static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item) { const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId); if(!node) return UA_STATUSCODE_BADINTERNALERROR; UA_StatusCode retval = UA_STATUSCODE_GOOD; #ifndef UA_MULTITHREADING size_t i = node->referencesSize; if(node->referencesSize < 0) i = 0; size_t refssize = (i+1) | 3; // so the realloc is not necessary every time UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * refssize); if(!new_refs) retval = UA_STATUSCODE_BADOUTOFMEMORY; else { UA_ReferenceNode_init(&new_refs[i]); retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[i].referenceTypeId); new_refs[i].isInverse = !item->isForward; retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[i].targetId); /* hack. be careful! possible only in the single-threaded case. */ UA_Node *mutable_node = (UA_Node*)(uintptr_t)node; mutable_node->references = new_refs; if(retval != UA_STATUSCODE_GOOD) { UA_NodeId_deleteMembers(&new_refs[node->referencesSize].referenceTypeId); UA_ExpandedNodeId_deleteMembers(&new_refs[node->referencesSize].targetId); } else mutable_node->referencesSize = i+1; } UA_NodeStore_release(node); return retval; #else UA_Node *newNode = UA_NULL; void (*deleteNode)(UA_Node*) = UA_NULL; switch(node->nodeClass) { case UA_NODECLASS_OBJECT: newNode = (UA_Node*)UA_ObjectNode_new(); UA_ObjectNode_copy((const UA_ObjectNode*)node, (UA_ObjectNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_ObjectNode_delete; break; case UA_NODECLASS_VARIABLE: newNode = (UA_Node*)UA_VariableNode_new(); UA_VariableNode_copy((const UA_VariableNode*)node, (UA_VariableNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_VariableNode_delete; break; case UA_NODECLASS_METHOD: newNode = (UA_Node*)UA_MethodNode_new(); UA_MethodNode_copy((const UA_MethodNode*)node, (UA_MethodNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_MethodNode_delete; break; case UA_NODECLASS_OBJECTTYPE: newNode = (UA_Node*)UA_ObjectTypeNode_new(); UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)node, (UA_ObjectTypeNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_ObjectTypeNode_delete; break; case UA_NODECLASS_VARIABLETYPE: newNode = (UA_Node*)UA_VariableTypeNode_new(); UA_VariableTypeNode_copy((const UA_VariableTypeNode*)node, (UA_VariableTypeNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_VariableTypeNode_delete; break; case UA_NODECLASS_REFERENCETYPE: newNode = (UA_Node*)UA_ReferenceTypeNode_new(); UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)node, (UA_ReferenceTypeNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_ReferenceTypeNode_delete; break; case UA_NODECLASS_DATATYPE: newNode = (UA_Node*)UA_DataTypeNode_new(); UA_DataTypeNode_copy((const UA_DataTypeNode*)node, (UA_DataTypeNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_DataTypeNode_delete; break; case UA_NODECLASS_VIEW: newNode = (UA_Node*)UA_ViewNode_new(); UA_ViewNode_copy((const UA_ViewNode*)node, (UA_ViewNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_ViewNode_delete; break; default: return UA_STATUSCODE_BADINTERNALERROR; } UA_Int32 count = node->referencesSize; if(count < 0) count = 0; UA_ReferenceNode *old_refs = newNode->references; UA_ReferenceNode *new_refs = UA_malloc(sizeof(UA_ReferenceNode)*(count+1)); if(!new_refs) { deleteNode(newNode); UA_NodeStore_release(node); return UA_STATUSCODE_BADOUTOFMEMORY; } // insert the new reference UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count); UA_ReferenceNode_init(&new_refs[count]); retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId); new_refs[count].isInverse = !item->isForward; retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId); if(retval != UA_STATUSCODE_GOOD) { UA_Array_delete(new_refs, &UA_TYPES[UA_TYPES_REFERENCENODE], ++count); newNode->references = UA_NULL; newNode->referencesSize = 0; deleteNode(newNode); UA_NodeStore_release(node); return UA_STATUSCODE_BADOUTOFMEMORY; } UA_free(old_refs); newNode->references = new_refs; newNode->referencesSize = ++count; retval = UA_NodeStore_replace(server->nodestore, node, newNode, UA_NULL); UA_NodeStore_release(node); if (retval == UA_STATUSCODE_BADINTERNALERROR) { /* presumably because the node was replaced and an old version was updated at the same time. just try again */ deleteNode(newNode); return addOneWayReferenceWithSession(server, session, item); } return retval; #endif }