123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- #include "ua_services.h"
- #include "ua_namespace_0.h"
- #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"
- #define COPY_STANDARDATTRIBUTES do { \
- if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DISPLAYNAME) { \
- vnode->displayName = attr.displayName; \
- UA_LocalizedText_init(&attr.displayName); \
- } \
- if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DESCRIPTION) { \
- vnode->description = attr.description; \
- UA_LocalizedText_init(&attr.description); \
- } \
- if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_WRITEMASK) \
- vnode->writeMask = attr.writeMask; \
- if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERWRITEMASK) \
- 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;
- }
- 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.
- */
- 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);
- }
- 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;
- }
- 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;
- }
- 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) {
- 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;
- }
|