|
@@ -3,6 +3,7 @@
|
|
|
#include "ua_statuscodes.h"
|
|
|
#include "nodestore/ua_nodestoreExample.h"
|
|
|
#include "ua_services_internal.h"
|
|
|
+#include "ua_namespace_manager.h"
|
|
|
#include "ua_session.h"
|
|
|
#include "ua_util.h"
|
|
|
|
|
@@ -21,232 +22,433 @@
|
|
|
vnode->userWriteMask = attr.userWriteMask; \
|
|
|
} while(0)
|
|
|
|
|
|
-static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node **new_node,
|
|
|
- const UA_VTable_Entry **vt) {
|
|
|
- if(attributes->typeId.identifier.numeric != 357) // VariableAttributes_Encoding_DefaultBinary,357,Object
|
|
|
- return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
|
|
|
-
|
|
|
- UA_VariableAttributes attr;
|
|
|
- UA_UInt32 pos = 0;
|
|
|
- // todo return more informative error codes from decodeBinary
|
|
|
- if(UA_VariableAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
|
|
|
- return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
|
|
|
-
|
|
|
- UA_VariableNode *vnode;
|
|
|
- if(UA_VariableNode_new(&vnode) != UA_STATUSCODE_GOOD) {
|
|
|
- UA_VariableAttributes_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_ACCESSLEVEL)
|
|
|
- vnode->accessLevel = attr.accessLevel;
|
|
|
-
|
|
|
- if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERACCESSLEVEL)
|
|
|
- vnode->userAccessLevel = attr.userAccessLevel;
|
|
|
-
|
|
|
- if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_HISTORIZING)
|
|
|
- vnode->historizing = attr.historizing;
|
|
|
-
|
|
|
- if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL)
|
|
|
- vnode->minimumSamplingInterval = attr.minimumSamplingInterval;
|
|
|
-
|
|
|
- if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUERANK)
|
|
|
- vnode->valueRank = attr.valueRank;
|
|
|
-
|
|
|
- if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS) {
|
|
|
- vnode->arrayDimensionsSize = attr.arrayDimensionsSize;
|
|
|
- vnode->arrayDimensions = attr.arrayDimensions;
|
|
|
- attr.arrayDimensionsSize = -1;
|
|
|
- attr.arrayDimensions = UA_NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DATATYPE ||
|
|
|
- attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_OBJECTTYPEORDATATYPE) {
|
|
|
- vnode->dataType = attr.dataType;
|
|
|
- UA_NodeId_init(&attr.dataType);
|
|
|
- }
|
|
|
-
|
|
|
- if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
|
|
|
- vnode->value = attr.value;
|
|
|
- UA_Variant_init(&attr.value);
|
|
|
- }
|
|
|
-
|
|
|
- UA_VariableAttributes_deleteMembers(&attr);
|
|
|
-
|
|
|
- *new_node = (UA_Node*)vnode;
|
|
|
- *vt = &UA_[UA_VARIABLENODE];
|
|
|
- return UA_STATUSCODE_GOOD;
|
|
|
+static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes,
|
|
|
+ UA_Node **new_node, const UA_VTable_Entry **vt) {
|
|
|
+ if (attributes->typeId.identifier.numeric != 357) // VariableAttributes_Encoding_DefaultBinary,357,Object
|
|
|
+ return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
|
|
|
+
|
|
|
+ UA_VariableAttributes attr;
|
|
|
+ UA_UInt32 pos = 0;
|
|
|
+ // todo return more informative error codes from decodeBinary
|
|
|
+ if (UA_VariableAttributes_decodeBinary(&attributes->body, &pos, &attr)
|
|
|
+ != UA_STATUSCODE_GOOD)
|
|
|
+ return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
|
|
|
+
|
|
|
+ UA_VariableNode *vnode;
|
|
|
+ if (UA_VariableNode_new(&vnode) != UA_STATUSCODE_GOOD) {
|
|
|
+ UA_VariableAttributes_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_ACCESSLEVEL)
|
|
|
+ vnode->accessLevel = attr.accessLevel;
|
|
|
+
|
|
|
+ if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERACCESSLEVEL)
|
|
|
+ vnode->userAccessLevel = attr.userAccessLevel;
|
|
|
+
|
|
|
+ if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_HISTORIZING)
|
|
|
+ vnode->historizing = attr.historizing;
|
|
|
+
|
|
|
+ if (attr.specifiedAttributes
|
|
|
+ & UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL)
|
|
|
+ vnode->minimumSamplingInterval = attr.minimumSamplingInterval;
|
|
|
+
|
|
|
+ if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUERANK)
|
|
|
+ vnode->valueRank = attr.valueRank;
|
|
|
+
|
|
|
+ if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS) {
|
|
|
+ vnode->arrayDimensionsSize = attr.arrayDimensionsSize;
|
|
|
+ vnode->arrayDimensions = attr.arrayDimensions;
|
|
|
+ attr.arrayDimensionsSize = -1;
|
|
|
+ attr.arrayDimensions = UA_NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DATATYPE
|
|
|
+ || attr.specifiedAttributes
|
|
|
+ & UA_NODEATTRIBUTESMASK_OBJECTTYPEORDATATYPE) {
|
|
|
+ vnode->dataType = attr.dataType;
|
|
|
+ UA_NodeId_init(&attr.dataType);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
|
|
|
+ vnode->value = attr.value;
|
|
|
+ UA_Variant_init(&attr.value);
|
|
|
+ }
|
|
|
+
|
|
|
+ UA_VariableAttributes_deleteMembers(&attr);
|
|
|
+
|
|
|
+ *new_node = (UA_Node*) vnode;
|
|
|
+ *vt = &UA_[UA_VARIABLENODE];
|
|
|
+ return UA_STATUSCODE_GOOD;
|
|
|
}
|
|
|
|
|
|
-UA_Int32 AddReference(UA_NodeStoreExample *nodestore, UA_Node *node, UA_ReferenceNode *reference);
|
|
|
+UA_Int32 AddReference(UA_NodeStoreExample *nodestore, UA_Node *node,
|
|
|
+ UA_ReferenceNode *reference);
|
|
|
|
|
|
/**
|
|
|
- If adding the node succeeds, the pointer will be set to zero. If the nodeid
|
|
|
- of the node is null (ns=0,i=0), a unique new nodeid will be assigned and
|
|
|
- returned in the AddNodesResult.
|
|
|
+ If adding the node succeeds, the pointer will be set to zero. If the nodeid
|
|
|
+ of the node is null (ns=0,i=0), a unique new nodeid will be assigned and
|
|
|
+ returned in the AddNodesResult.
|
|
|
*/
|
|
|
-UA_AddNodesResult AddNode(UA_Server *server, UA_Session *session, UA_Node **node,
|
|
|
- UA_ExpandedNodeId *parentNodeId, UA_NodeId *referenceTypeId) {
|
|
|
- UA_AddNodesResult result;
|
|
|
- UA_AddNodesResult_init(&result);
|
|
|
-
|
|
|
- const UA_Node *parent;
|
|
|
- if(UA_NodeStoreExample_get(server->nodestore, &parentNodeId->nodeId, &parent) != UA_STATUSCODE_GOOD) {
|
|
|
- result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- const UA_ReferenceTypeNode *referenceType;
|
|
|
- if(UA_NodeStoreExample_get(server->nodestore, referenceTypeId, (const UA_Node**)&referenceType) != UA_STATUSCODE_GOOD) {
|
|
|
- result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
|
|
|
- goto ret;
|
|
|
- }
|
|
|
-
|
|
|
- if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
|
|
|
- result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
|
|
|
- goto ret2;
|
|
|
- }
|
|
|
-
|
|
|
- if(referenceType->isAbstract == UA_TRUE) {
|
|
|
- result.statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
|
|
|
- goto ret2;
|
|
|
- }
|
|
|
-
|
|
|
- // todo: test if the referenetype is hierarchical
|
|
|
-
|
|
|
- if(UA_NodeId_isNull(&(*node)->nodeId)) {
|
|
|
- if(UA_NodeStoreExample_insert(server->nodestore, node,
|
|
|
- UA_NODESTORE_INSERT_UNIQUE | UA_NODESTORE_INSERT_GETMANAGED) != UA_STATUSCODE_GOOD) {
|
|
|
- result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
- goto ret2;
|
|
|
- }
|
|
|
- result.addedNodeId = (*node)->nodeId; // cannot fail as unique nodeids are numeric
|
|
|
- } else {
|
|
|
- if(UA_NodeId_copy(&(*node)->nodeId, &result.addedNodeId) != UA_STATUSCODE_GOOD) {
|
|
|
- result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
- goto ret2;
|
|
|
- }
|
|
|
-
|
|
|
- if(UA_NodeStoreExample_insert(server->nodestore, node, UA_NODESTORE_INSERT_GETMANAGED) != UA_STATUSCODE_GOOD) {
|
|
|
- result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS; // todo: differentiate out of memory
|
|
|
- UA_NodeId_deleteMembers(&result.addedNodeId);
|
|
|
- goto ret2;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- UA_ReferenceNode ref;
|
|
|
- UA_ReferenceNode_init(&ref);
|
|
|
- ref.referenceTypeId = referenceType->nodeId; // is numeric
|
|
|
- ref.isInverse = UA_TRUE; // todo: check if they are all not inverse..
|
|
|
- ref.targetId.nodeId = parent->nodeId;
|
|
|
- AddReference(server->nodestore, *node, &ref);
|
|
|
-
|
|
|
- // todo: error handling. remove new node from nodestore
|
|
|
-
|
|
|
- UA_NodeStoreExample_releaseManagedNode(*node);
|
|
|
- *node = UA_NULL;
|
|
|
-
|
|
|
- ret2:
|
|
|
- UA_NodeStoreExample_releaseManagedNode((UA_Node*)referenceType);
|
|
|
- ret:
|
|
|
- UA_NodeStoreExample_releaseManagedNode(parent);
|
|
|
-
|
|
|
- return result;
|
|
|
+UA_AddNodesResult AddNode(UA_Server *server, UA_Session *session,
|
|
|
+ UA_Node **node, UA_ExpandedNodeId *parentNodeId,
|
|
|
+ UA_NodeId *referenceTypeId) {
|
|
|
+ UA_AddNodesResult result;
|
|
|
+ UA_AddNodesResult_init(&result);
|
|
|
+
|
|
|
+ const UA_Node *parent;
|
|
|
+ if (UA_NodeStoreExample_get(server->nodestore, &parentNodeId->nodeId,
|
|
|
+ &parent) != UA_STATUSCODE_GOOD) {
|
|
|
+ result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ const UA_ReferenceTypeNode *referenceType;
|
|
|
+ if (UA_NodeStoreExample_get(server->nodestore, referenceTypeId,
|
|
|
+ (const UA_Node**) &referenceType) != UA_STATUSCODE_GOOD) {
|
|
|
+ result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
|
|
|
+ goto ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
|
|
|
+ result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
|
|
|
+ goto ret2;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (referenceType->isAbstract == UA_TRUE) {
|
|
|
+ result.statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
|
|
|
+ goto ret2;
|
|
|
+ }
|
|
|
+
|
|
|
+ // todo: test if the referenetype is hierarchical
|
|
|
+
|
|
|
+ if (UA_NodeId_isNull(&(*node)->nodeId)) {
|
|
|
+ if (UA_NodeStoreExample_insert(server->nodestore, node,
|
|
|
+ UA_NODESTORE_INSERT_UNIQUE | UA_NODESTORE_INSERT_GETMANAGED)
|
|
|
+ != UA_STATUSCODE_GOOD) {
|
|
|
+ result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ goto ret2;
|
|
|
+ }
|
|
|
+ result.addedNodeId = (*node)->nodeId; // cannot fail as unique nodeids are numeric
|
|
|
+ } else {
|
|
|
+ if (UA_NodeId_copy(&(*node)->nodeId, &result.addedNodeId)
|
|
|
+ != UA_STATUSCODE_GOOD) {
|
|
|
+ result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ goto ret2;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (UA_NodeStoreExample_insert(server->nodestore, node,
|
|
|
+ UA_NODESTORE_INSERT_GETMANAGED) != UA_STATUSCODE_GOOD) {
|
|
|
+ result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS; // todo: differentiate out of memory
|
|
|
+ UA_NodeId_deleteMembers(&result.addedNodeId);
|
|
|
+ goto ret2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ UA_ReferenceNode ref;
|
|
|
+ UA_ReferenceNode_init(&ref);
|
|
|
+ ref.referenceTypeId = referenceType->nodeId; // is numeric
|
|
|
+ ref.isInverse = UA_TRUE; // todo: check if they are all not inverse..
|
|
|
+ ref.targetId.nodeId = parent->nodeId;
|
|
|
+ AddReference(server->nodestore, *node, &ref);
|
|
|
+
|
|
|
+ // todo: error handling. remove new node from nodestore
|
|
|
+
|
|
|
+ UA_NodeStoreExample_releaseManagedNode(*node);
|
|
|
+ *node = UA_NULL;
|
|
|
+
|
|
|
+ ret2: UA_NodeStoreExample_releaseManagedNode((UA_Node*) referenceType);
|
|
|
+ ret: UA_NodeStoreExample_releaseManagedNode(parent);
|
|
|
+
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
-static void addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
|
|
|
- UA_AddNodesResult *result) {
|
|
|
- if(item->requestedNewNodeId.nodeId.namespaceIndex == 0) {
|
|
|
- // adding nodes to ns0 is not allowed over the wire
|
|
|
- result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- UA_Node *newNode;
|
|
|
- const UA_VTable_Entry *newNodeVT = UA_NULL;
|
|
|
- if(item->nodeClass == UA_NODECLASS_VARIABLE)
|
|
|
- result->statusCode = parseVariableNode(&item->nodeAttributes, &newNode, &newNodeVT);
|
|
|
- else // add more node types here..
|
|
|
- result->statusCode = UA_STATUSCODE_BADNOTIMPLEMENTED;
|
|
|
-
|
|
|
- if(result->statusCode != UA_STATUSCODE_GOOD)
|
|
|
- return;
|
|
|
-
|
|
|
- *result = AddNode(server, session, &newNode, &item->parentNodeId, &item->referenceTypeId);
|
|
|
- if(result->statusCode != UA_STATUSCODE_GOOD)
|
|
|
- newNodeVT->delete(newNode);
|
|
|
+static void addNodeFromAttributes(UA_Server *server, UA_Session *session,
|
|
|
+ UA_AddNodesItem *item, UA_AddNodesResult *result) {
|
|
|
+ if (item->requestedNewNodeId.nodeId.namespaceIndex == 0) {
|
|
|
+ // adding nodes to ns0 is not allowed over the wire
|
|
|
+ result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ UA_Node *newNode;
|
|
|
+ const UA_VTable_Entry *newNodeVT = UA_NULL;
|
|
|
+ if (item->nodeClass == UA_NODECLASS_VARIABLE)
|
|
|
+ result->statusCode = parseVariableNode(&item->nodeAttributes, &newNode,
|
|
|
+ &newNodeVT);
|
|
|
+ else
|
|
|
+ // add more node types here..
|
|
|
+ result->statusCode = UA_STATUSCODE_BADNOTIMPLEMENTED;
|
|
|
+
|
|
|
+ if (result->statusCode != UA_STATUSCODE_GOOD)
|
|
|
+ return;
|
|
|
+
|
|
|
+ *result = AddNode(server, session, &newNode, &item->parentNodeId,
|
|
|
+ &item->referenceTypeId);
|
|
|
+ if (result->statusCode != UA_STATUSCODE_GOOD)
|
|
|
+ newNodeVT->delete(newNode);
|
|
|
}
|
|
|
|
|
|
void Service_AddNodes(UA_Server *server, UA_Session *session,
|
|
|
- const UA_AddNodesRequest *request, UA_AddNodesResponse *response) {
|
|
|
- UA_assert(server != UA_NULL && session != UA_NULL);
|
|
|
-
|
|
|
- if(request->nodesToAddSize <= 0) {
|
|
|
- response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if(UA_Array_new((void **)&response->results, request->nodesToAddSize, &UA_[UA_ADDNODESRESULT])
|
|
|
- != UA_STATUSCODE_GOOD) {
|
|
|
- response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- response->resultsSize = request->nodesToAddSize;
|
|
|
- for(int i = 0;i < request->nodesToAddSize;i++)
|
|
|
- addNodeFromAttributes(server, session, &request->nodesToAdd[i], &response->results[i]);
|
|
|
+ const UA_AddNodesRequest *request, UA_AddNodesResponse *response) {
|
|
|
+ UA_assert(server != UA_NULL && session != UA_NULL);
|
|
|
+
|
|
|
+ if (request->nodesToAddSize <= 0) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (UA_Array_new((void **) &response->results, request->nodesToAddSize,
|
|
|
+ &UA_[UA_ADDNODESRESULT]) != UA_STATUSCODE_GOOD) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (UA_Array_new((void **) &response->diagnosticInfos,
|
|
|
+ request->nodesToAddSize, &UA_[UA_DIAGNOSTICINFO])
|
|
|
+ != UA_STATUSCODE_GOOD) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ response->resultsSize = request->nodesToAddSize;
|
|
|
+
|
|
|
+ UA_Int32 *numberOfFoundIndices;
|
|
|
+ UA_UInt16 *associatedIndices;
|
|
|
+ UA_UInt32 differentNamespaceIndexCount = 0;
|
|
|
+ if (UA_Array_new((void **) &numberOfFoundIndices,
|
|
|
+ request->nodesToAddSize, &UA_[UA_UINT32])
|
|
|
+ != UA_STATUSCODE_GOOD) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (UA_Array_new((void **) &associatedIndices, request->nodesToAddSize,
|
|
|
+ &UA_[UA_UINT16]) != UA_STATUSCODE_GOOD) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // find out count of different namespace indices
|
|
|
+
|
|
|
+ for (UA_Int32 i = 0; i < request->nodesToAddSize; i++) {
|
|
|
+
|
|
|
+ for (UA_UInt32 j = 0; j <= differentNamespaceIndexCount; j++) {
|
|
|
+ if (associatedIndices[j]
|
|
|
+ == request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex) {
|
|
|
+ if (j == 0) {
|
|
|
+ differentNamespaceIndexCount++;
|
|
|
+ }
|
|
|
+ numberOfFoundIndices[j]++;
|
|
|
+ break;
|
|
|
+ } else if (j == (differentNamespaceIndexCount - 1)) {
|
|
|
+ associatedIndices[j] =
|
|
|
+ request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex;
|
|
|
+ associatedIndices[j] = 1;
|
|
|
+ differentNamespaceIndexCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ UA_UInt32 *addNodesIndices;
|
|
|
+ if (UA_Array_new((void **) &addNodesIndices,
|
|
|
+ request->nodesToAddSize, &UA_[UA_UINT32])
|
|
|
+ != UA_STATUSCODE_GOOD) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (UA_UInt32 i = 0; i < differentNamespaceIndexCount; i++) {
|
|
|
+ UA_Namespace *tmpNamespace;
|
|
|
+ UA_NamespaceManager_getNamespace(server->namespaceManager,
|
|
|
+ associatedIndices[i], &tmpNamespace);
|
|
|
+ if (tmpNamespace != UA_NULL) {
|
|
|
+ //build up index array for each read operation onto a different namespace
|
|
|
+ UA_UInt32 n = 0;
|
|
|
+ for (UA_Int32 j = 0; j < request->nodesToAddSize; j++) {
|
|
|
+ if (request->nodesToAdd[j].requestedNewNodeId.nodeId.namespaceIndex
|
|
|
+ == associatedIndices[i]) {
|
|
|
+ addNodesIndices[n] = j;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //call read for every namespace
|
|
|
+ tmpNamespace->nodeStore->addNodes(request->nodesToAdd,
|
|
|
+ addNodesIndices, numberOfFoundIndices[i],
|
|
|
+ response->results, response->diagnosticInfos);
|
|
|
+
|
|
|
+ // response->results[i] = service_read_node(server, &request->nodesToRead[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ UA_free(addNodesIndices);
|
|
|
+ UA_free(numberOfFoundIndices);
|
|
|
+ UA_free(associatedIndices);
|
|
|
+
|
|
|
+/* if (request->nodesToAddSize <= 0) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (UA_Array_new((void **) &response->results, request->nodesToAddSize,
|
|
|
+ &UA_[UA_ADDNODESRESULT]) != UA_STATUSCODE_GOOD) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ response->resultsSize = request->nodesToAddSize;
|
|
|
+ for (int i = 0; i < request->nodesToAddSize; i++)
|
|
|
+ addNodeFromAttributes(server, session, &request->nodesToAdd[i],
|
|
|
+ &response->results[i]);
|
|
|
+ */
|
|
|
}
|
|
|
|
|
|
static UA_Int32 AddSingleReference(UA_Node *node, UA_ReferenceNode *reference) {
|
|
|
- // TODO: Check if reference already exists
|
|
|
- UA_Int32 count = node->referencesSize;
|
|
|
- UA_ReferenceNode *old_refs = node->references;
|
|
|
- UA_ReferenceNode *new_refs;
|
|
|
-
|
|
|
- if(count < 0) count = 0;
|
|
|
-
|
|
|
- if(!(new_refs = UA_alloc(sizeof(UA_ReferenceNode)*(count+1))))
|
|
|
- return UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
-
|
|
|
- UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
|
|
|
- if(UA_ReferenceNode_copy(reference, &new_refs[count]) != UA_STATUSCODE_GOOD) {
|
|
|
- UA_free(new_refs);
|
|
|
- return UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
- }
|
|
|
-
|
|
|
- node->references = new_refs;
|
|
|
- node->referencesSize = count+1;
|
|
|
- UA_free(old_refs);
|
|
|
- return UA_STATUSCODE_GOOD;
|
|
|
+ // TODO: Check if reference already exists
|
|
|
+ UA_Int32 count = node->referencesSize;
|
|
|
+ UA_ReferenceNode *old_refs = node->references;
|
|
|
+ UA_ReferenceNode *new_refs;
|
|
|
+
|
|
|
+ if (count < 0)
|
|
|
+ count = 0;
|
|
|
+
|
|
|
+ if (!(new_refs = UA_alloc(sizeof(UA_ReferenceNode) * (count + 1))))
|
|
|
+ return UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+
|
|
|
+ UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode) * count);
|
|
|
+ if (UA_ReferenceNode_copy(reference, &new_refs[count])
|
|
|
+ != UA_STATUSCODE_GOOD) {
|
|
|
+ UA_free(new_refs);
|
|
|
+ return UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ }
|
|
|
+
|
|
|
+ node->references = new_refs;
|
|
|
+ node->referencesSize = count + 1;
|
|
|
+ UA_free(old_refs);
|
|
|
+ return UA_STATUSCODE_GOOD;
|
|
|
}
|
|
|
|
|
|
-UA_Int32 AddReference(UA_NodeStoreExample *nodestore, UA_Node *node, UA_ReferenceNode *reference) {
|
|
|
- UA_Int32 retval = AddSingleReference(node, reference);
|
|
|
- UA_Node *targetnode;
|
|
|
- UA_ReferenceNode inversereference;
|
|
|
- if(retval != UA_STATUSCODE_GOOD || nodestore == UA_NULL)
|
|
|
- return retval;
|
|
|
-
|
|
|
- // Do a copy every time?
|
|
|
- if(UA_NodeStoreExample_get(nodestore, &reference->targetId.nodeId, (const UA_Node **)&targetnode) != UA_STATUSCODE_GOOD)
|
|
|
- return UA_STATUSCODE_BADINTERNALERROR;
|
|
|
-
|
|
|
- inversereference.referenceTypeId = reference->referenceTypeId;
|
|
|
- inversereference.isInverse = !reference->isInverse;
|
|
|
- inversereference.targetId.nodeId = node->nodeId;
|
|
|
- inversereference.targetId.namespaceUri = UA_STRING_NULL;
|
|
|
- inversereference.targetId.serverIndex = 0;
|
|
|
- retval = AddSingleReference(targetnode, &inversereference);
|
|
|
- UA_NodeStoreExample_releaseManagedNode(targetnode);
|
|
|
-
|
|
|
- return retval;
|
|
|
+UA_Int32 AddReference(UA_NodeStoreExample *nodestore, UA_Node *node,
|
|
|
+ UA_ReferenceNode *reference) {
|
|
|
+ UA_Int32 retval = AddSingleReference(node, reference);
|
|
|
+ UA_Node *targetnode;
|
|
|
+ UA_ReferenceNode inversereference;
|
|
|
+ if (retval != UA_STATUSCODE_GOOD || nodestore == UA_NULL)
|
|
|
+ return retval;
|
|
|
+
|
|
|
+ // Do a copy every time?
|
|
|
+ if (UA_NodeStoreExample_get(nodestore, &reference->targetId.nodeId,
|
|
|
+ (const UA_Node **) &targetnode) != UA_STATUSCODE_GOOD)
|
|
|
+ return UA_STATUSCODE_BADINTERNALERROR;
|
|
|
+
|
|
|
+ inversereference.referenceTypeId = reference->referenceTypeId;
|
|
|
+ inversereference.isInverse = !reference->isInverse;
|
|
|
+ inversereference.targetId.nodeId = node->nodeId;
|
|
|
+ inversereference.targetId.namespaceUri = UA_STRING_NULL;
|
|
|
+ inversereference.targetId.serverIndex = 0;
|
|
|
+ retval = AddSingleReference(targetnode, &inversereference);
|
|
|
+ UA_NodeStoreExample_releaseManagedNode(targetnode);
|
|
|
+
|
|
|
+ return retval;
|
|
|
}
|
|
|
|
|
|
void Service_AddReferences(UA_Server *server, UA_Session *session,
|
|
|
- const UA_AddReferencesRequest *request,
|
|
|
- UA_AddReferencesResponse *response) {
|
|
|
- response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTIMPLEMENTED;
|
|
|
+ const UA_AddReferencesRequest *request,
|
|
|
+ UA_AddReferencesResponse *response) {
|
|
|
+
|
|
|
+ if (request->referencesToAddSize <= 0) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (UA_Array_new((void **) &response->results, request->referencesToAddSize,
|
|
|
+ &UA_[UA_STATUSCODE]) != UA_STATUSCODE_GOOD) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (UA_Array_new((void **) &response->diagnosticInfos,
|
|
|
+ request->referencesToAddSize, &UA_[UA_DIAGNOSTICINFO])
|
|
|
+ != UA_STATUSCODE_GOOD) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ response->resultsSize = request->referencesToAddSize;
|
|
|
+
|
|
|
+ UA_Int32 *numberOfFoundIndices;
|
|
|
+ UA_UInt16 *associatedIndices;
|
|
|
+ UA_UInt32 differentNamespaceIndexCount = 0;
|
|
|
+ if (UA_Array_new((void **) &numberOfFoundIndices,
|
|
|
+ request->referencesToAddSize, &UA_[UA_UINT32])
|
|
|
+ != UA_STATUSCODE_GOOD) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (UA_Array_new((void **) &associatedIndices, request->referencesToAddSize,
|
|
|
+ &UA_[UA_UINT16]) != UA_STATUSCODE_GOOD) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // find out count of different namespace indices
|
|
|
+
|
|
|
+ for (UA_Int32 i = 0; i < request->referencesToAddSize; i++) {
|
|
|
+
|
|
|
+ for (UA_UInt32 j = 0; j <= differentNamespaceIndexCount; j++) {
|
|
|
+ if (associatedIndices[j]
|
|
|
+ == request->referencesToAdd[i].sourceNodeId.namespaceIndex) {
|
|
|
+ if (j == 0) {
|
|
|
+ differentNamespaceIndexCount++;
|
|
|
+ }
|
|
|
+ numberOfFoundIndices[j]++;
|
|
|
+ break;
|
|
|
+ } else if (j == (differentNamespaceIndexCount - 1)) {
|
|
|
+ associatedIndices[j] =
|
|
|
+ request->referencesToAdd[i].sourceNodeId.namespaceIndex;
|
|
|
+ associatedIndices[j] = 1;
|
|
|
+ differentNamespaceIndexCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ UA_UInt32 *readValueIdIndices;
|
|
|
+ if (UA_Array_new((void **) &readValueIdIndices,
|
|
|
+ request->referencesToAddSize, &UA_[UA_UINT32])
|
|
|
+ != UA_STATUSCODE_GOOD) {
|
|
|
+ response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (UA_UInt32 i = 0; i < differentNamespaceIndexCount; i++) {
|
|
|
+ UA_Namespace *tmpNamespace;
|
|
|
+ UA_NamespaceManager_getNamespace(server->namespaceManager,
|
|
|
+ associatedIndices[i], &tmpNamespace);
|
|
|
+ if (tmpNamespace != UA_NULL) {
|
|
|
+ //build up index array for each read operation onto a different namespace
|
|
|
+ UA_UInt32 n = 0;
|
|
|
+ for (UA_Int32 j = 0; j < request->referencesToAddSize; j++) {
|
|
|
+ if (request->referencesToAdd[j].sourceNodeId.namespaceIndex
|
|
|
+ == associatedIndices[i]) {
|
|
|
+ readValueIdIndices[n] = j;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //call read for every namespace
|
|
|
+ tmpNamespace->nodeStore->addReferences(request->referencesToAdd,
|
|
|
+ readValueIdIndices, numberOfFoundIndices[i],
|
|
|
+ response->results, response->diagnosticInfos);
|
|
|
+
|
|
|
+ // response->results[i] = service_read_node(server, &request->nodesToRead[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ UA_free(readValueIdIndices);
|
|
|
+ UA_free(numberOfFoundIndices);
|
|
|
+ UA_free(associatedIndices);
|
|
|
+ /*
|
|
|
+ for(UA_Int32 i = 0;i < response->resultsSize;i++){
|
|
|
+ response->results[i] = service_read_node(server, &request->nodesToRead[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+ //response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTIMPLEMENTED;
|
|
|
}
|