UA_StatusCode getTypesHierarchy(void *nsCtx, const UA_NodeId *leafType, size_t leafTypeSize, UA_NodeId **typeHierarchy, size_t *typeHierarchySize, UA_Boolean walkDownwards) { UA_NodeId *results = NULL; size_t results_count = 0; for (size_t i = 0; i < leafTypeSize; i++) { UA_NodeId *tmpResults = NULL; size_t tmpResults_size = 0; UA_StatusCode retval = getTypeHierarchy(nsCtx, &leafType[i], &tmpResults, &tmpResults_size, walkDownwards); if(retval != UA_STATUSCODE_GOOD) { UA_Array_delete(results, results_count, &UA_TYPES[UA_TYPES_NODEID]); return retval; } if (tmpResults_size == 0 || tmpResults == NULL ) continue; size_t new_size = sizeof(UA_NodeId) * (results_count + tmpResults_size); UA_NodeId *new_results = (UA_NodeId*)UA_realloc(results, new_size); if(!new_results) { UA_Array_delete(results, results_count, &UA_TYPES[UA_TYPES_NODEID]); return UA_STATUSCODE_BADOUTOFMEMORY; } results = new_results; memcpy(&results[results_count],tmpResults, sizeof(UA_NodeId)*tmpResults_size); /* do not use UA_Array_delete since we still need the content of the nodes */ UA_free(tmpResults); results_count = results_count + tmpResults_size; } *typeHierarchy = results; *typeHierarchySize = results_count; return UA_STATUSCODE_GOOD; }
/** * Gets a list of nodeIds which are referenced by this node. * Hereby the list will be filtered to only include references * which are of the given `references` types. */ static UA_StatusCode getReferencedNodesWithReferenceType(UA_NodeId **results_ptr, size_t *results_count, size_t *results_size, const UA_Node *node, const UA_NodeReferenceKind *references, size_t referencesSize) { UA_NodeId *results = *results_ptr; for(size_t i = 0; i < node->referencesSize; ++i) { /* Is the reference kind relevant? */ UA_NodeReferenceKind *refs = &node->references[i]; bool referenceInList = false; for (size_t j=0; j<referencesSize && !referenceInList; j++) { referenceInList = refs->isInverse == references[j].isInverse && UA_NodeId_equal(&references[j].referenceTypeId, &refs->referenceTypeId); } if (!referenceInList) continue; /* Append all targets of the reference kind .. if not a duplicate */ for(size_t j = 0; j < refs->targetIdsSize; ++j) { /* Is the target a duplicate? (multi-inheritance) */ UA_NodeId *targetId = &refs->targetIds[j].nodeId; UA_Boolean duplicate = false; for(size_t k = 0; k < *results_count; ++k) { if(UA_NodeId_equal(targetId, &results[k])) { duplicate = true; break; } } if(duplicate) continue; /* Increase array length if necessary */ if(*results_count >= *results_size) { size_t new_size = sizeof(UA_NodeId) * (*results_size) * 2; UA_NodeId *new_results = (UA_NodeId*)UA_realloc(results, new_size); if(!new_results) { UA_Array_delete(results, *results_count, &UA_TYPES[UA_TYPES_NODEID]); return UA_STATUSCODE_BADOUTOFMEMORY; } results = new_results; *results_ptr = results; *results_size *= 2; } /* Copy new nodeid to the end of the list */ UA_StatusCode retval = UA_NodeId_copy(targetId, &results[*results_count]); if(retval != UA_STATUSCODE_GOOD) { UA_Array_delete(results, *results_count, &UA_TYPES[UA_TYPES_NODEID]); return retval; } *results_count += 1; } } return UA_STATUSCODE_GOOD; }
/* Adds a one-way reference to the local nodestore */ static UA_StatusCode addOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node, const UA_AddReferencesItem *item) { size_t i = node->referencesSize; 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) return UA_STATUSCODE_BADOUTOFMEMORY; node->references = new_refs; UA_ReferenceNode_init(&new_refs[i]); UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[i].referenceTypeId); retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[i].targetId); new_refs[i].isInverse = !item->isForward; if(retval == UA_STATUSCODE_GOOD) node->referencesSize = i+1; else UA_ReferenceNode_deleteMembers(&new_refs[i]); return retval; }
static #endif UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range) { UA_Int32 index = 0; size_t dimensionsMax = 0; struct UA_NumericRangeDimension *dimensions = NULL; UA_StatusCode retval = UA_STATUSCODE_GOOD; size_t pos = 0; do { /* alloc dimensions */ if(index >= (UA_Int32)dimensionsMax) { struct UA_NumericRangeDimension *newds; newds = UA_realloc(dimensions, sizeof(struct UA_NumericRangeDimension) * (dimensionsMax + 2)); if(!newds) { retval = UA_STATUSCODE_BADOUTOFMEMORY; break; } dimensions = newds; dimensionsMax = dimensionsMax + 2; } /* read the dimension */ size_t progress = readDimension(&str->data[pos], str->length - pos, &dimensions[index]); if(progress == 0) { retval = UA_STATUSCODE_BADINDEXRANGEINVALID; break; } pos += progress; index++; /* loop into the next dimension */ if(pos >= str->length) break; } while(str->data[pos] == ',' && pos++); if(retval == UA_STATUSCODE_GOOD && index > 0) { range->dimensions = dimensions; range->dimensionsSize = index; } else UA_free(dimensions); return retval; }
static UA_StatusCode parse_numericrange(const UA_String str, UA_NumericRange *range) { if(str.length < 0 || str.length >= 1023) return UA_STATUSCODE_BADINTERNALERROR; char *cstring = UA_alloca(str.length+1); UA_memcpy(cstring, str.data, str.length); cstring[str.length] = 0; UA_Int32 index = 0; size_t dimensionsIndex = 0; size_t dimensionsMax = 3; // more should be uncommon struct UA_NumericRangeDimension *dimensions = UA_malloc(sizeof(struct UA_NumericRangeDimension) * 3); if(!dimensions) return UA_STATUSCODE_BADOUTOFMEMORY; UA_StatusCode retval = UA_STATUSCODE_GOOD; do { UA_Int32 min, max; UA_Int32 progress; UA_Int32 res = sscanf(&cstring[index], "%" SCNu32 "%n", &min, &progress); if(res <= 0 || min < 0) { retval = UA_STATUSCODE_BADINDEXRANGEINVALID; break; } index += progress; if(index >= str.length || cstring[index] == ',') max = min; else { res = sscanf(&cstring[index], ":%" SCNu32 "%n", &max, &progress); if(res <= 0 || max < 0 || min >= max) { retval = UA_STATUSCODE_BADINDEXRANGEINVALID; break; } index += progress; } if(dimensionsIndex >= dimensionsMax) { struct UA_NumericRangeDimension *newDimensions = UA_realloc(dimensions, sizeof(struct UA_NumericRangeDimension) * 2 * dimensionsMax); if(!newDimensions) { UA_free(dimensions); return UA_STATUSCODE_BADOUTOFMEMORY; } dimensions = newDimensions; dimensionsMax *= 2; } dimensions[dimensionsIndex].min = min; dimensions[dimensionsIndex].max = max; dimensionsIndex++; } while(retval == UA_STATUSCODE_GOOD && index + 1 < str.length && cstring[index] == ',' && ++index); if(retval != UA_STATUSCODE_GOOD) { UA_free(dimensions); return retval; } range->dimensions = dimensions; range->dimensionsSize = dimensionsIndex; return retval; }
/* 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 }