|
@@ -23,17 +23,19 @@ struct getNodesHandle {
|
|
|
};
|
|
|
|
|
|
/* generates a unique event id */
|
|
|
-static UA_StatusCode UA_Event_generateEventId(UA_Server *server, UA_ByteString *generatedId) {
|
|
|
+static UA_StatusCode
|
|
|
+UA_Event_generateEventId(UA_Server *server, UA_ByteString *generatedId) {
|
|
|
/* EventId is a ByteString, which is basically just a string
|
|
|
* We will use a 16-Byte ByteString as an identifier */
|
|
|
generatedId->length = 16;
|
|
|
generatedId->data = (UA_Byte *) UA_malloc(16 * sizeof(UA_Byte));
|
|
|
- if (!generatedId->data) {
|
|
|
+ if(!generatedId->data) {
|
|
|
UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_USERLAND,
|
|
|
"Server unable to allocate memory for EventId data.");
|
|
|
UA_free(generatedId);
|
|
|
return UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
}
|
|
|
+
|
|
|
/* GUIDs are unique, have a size of 16 byte and already have
|
|
|
* a generator so use that.
|
|
|
* Make sure GUIDs really do have 16 byte, in case someone may
|
|
@@ -44,13 +46,13 @@ static UA_StatusCode UA_Event_generateEventId(UA_Server *server, UA_ByteString *
|
|
|
return UA_STATUSCODE_GOOD;
|
|
|
}
|
|
|
|
|
|
-static UA_StatusCode findAllSubtypesNodeIteratorCallback(UA_NodeId parentId, UA_Boolean isInverse,
|
|
|
- UA_NodeId referenceTypeId, void *handle) {
|
|
|
+static UA_StatusCode
|
|
|
+findAllSubtypesNodeIteratorCallback(UA_NodeId parentId, UA_Boolean isInverse,
|
|
|
+ UA_NodeId referenceTypeId, void *handle) {
|
|
|
/* only subtypes of hasSubtype */
|
|
|
UA_NodeId hasSubtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
|
|
|
- if (isInverse || !UA_NodeId_equal(&referenceTypeId, &hasSubtypeId)) {
|
|
|
+ if(isInverse || !UA_NodeId_equal(&referenceTypeId, &hasSubtypeId))
|
|
|
return UA_STATUSCODE_GOOD;
|
|
|
- }
|
|
|
|
|
|
Events_nodeListElement *entry = (Events_nodeListElement *) UA_malloc(sizeof(Events_nodeListElement));
|
|
|
if (!entry) {
|
|
@@ -72,19 +74,20 @@ static UA_StatusCode findAllSubtypesNodeIteratorCallback(UA_NodeId parentId, UA_
|
|
|
|
|
|
/* Searches for an attribute of an event with the name 'name' and the depth from the event relativePathSize.
|
|
|
* Returns the browsePathResult of searching for that node */
|
|
|
-static void UA_Event_findVariableNode(UA_Server *server, UA_QualifiedName *name, size_t relativePathSize,
|
|
|
- const UA_NodeId *event, UA_BrowsePathResult *out) {
|
|
|
+static void
|
|
|
+UA_Event_findVariableNode(UA_Server *server, UA_QualifiedName *name, size_t relativePathSize,
|
|
|
+ const UA_NodeId *event, UA_BrowsePathResult *out) {
|
|
|
/* get a list with all subtypes of aggregates */
|
|
|
struct getNodesHandle handle;
|
|
|
Events_nodeList list;
|
|
|
LIST_INIT(&list);
|
|
|
handle.server = server;
|
|
|
handle.nodes = &list;
|
|
|
- UA_StatusCode retval = UA_Server_forEachChildNodeCall(server, UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
|
|
|
- findAllSubtypesNodeIteratorCallback, &handle);
|
|
|
- if (retval != UA_STATUSCODE_GOOD) {
|
|
|
+ UA_StatusCode retval =
|
|
|
+ UA_Server_forEachChildNodeCall(server, UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
|
|
|
+ findAllSubtypesNodeIteratorCallback, &handle);
|
|
|
+ if(retval != UA_STATUSCODE_GOOD)
|
|
|
out->statusCode = retval;
|
|
|
- }
|
|
|
|
|
|
/* check if you can find the node with any of the subtypes of aggregates */
|
|
|
UA_Boolean nodeFound = UA_FALSE;
|
|
@@ -105,9 +108,8 @@ static void UA_Event_findVariableNode(UA_Server *server, UA_QualifiedName *name,
|
|
|
bp.relativePath.elements = &rpe;
|
|
|
|
|
|
*out = UA_Server_translateBrowsePathToNodeIds(server, &bp);
|
|
|
- if (out->statusCode == UA_STATUSCODE_GOOD) {
|
|
|
+ if(out->statusCode == UA_STATUSCODE_GOOD)
|
|
|
nodeFound = UA_TRUE;
|
|
|
- }
|
|
|
}
|
|
|
LIST_REMOVE(iter, listEntry);
|
|
|
UA_NodeId_delete(iter->node);
|
|
@@ -122,8 +124,6 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType, UA_NodeId *o
|
|
|
return UA_STATUSCODE_BADINVALIDARGUMENT;
|
|
|
}
|
|
|
|
|
|
- UA_StatusCode retval;
|
|
|
-
|
|
|
/* make sure the eventType is a subtype of BaseEventType */
|
|
|
UA_NodeId hasSubtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
|
|
|
UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
|
|
@@ -142,27 +142,30 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType, UA_NodeId *o
|
|
|
UA_QualifiedName_init(&name);
|
|
|
|
|
|
/* create an ObjectNode which represents the event */
|
|
|
- retval = UA_Server_addObjectNode(server,
|
|
|
- UA_NODEID_NULL, /* the user may not have control over the nodeId */
|
|
|
- UA_NODEID_NULL, /* an event does not have a parent */
|
|
|
- UA_NODEID_NULL, /* an event does not have any references */
|
|
|
- name, /* an event does not have a name */
|
|
|
- eventType, /* the type of the event */
|
|
|
- oAttr, /* default attributes are fine */
|
|
|
- NULL, /* no node context */
|
|
|
- outNodeId);
|
|
|
+ UA_StatusCode retval =
|
|
|
+ UA_Server_addObjectNode(server,
|
|
|
+ UA_NODEID_NULL, /* the user may not have control over the nodeId */
|
|
|
+ UA_NODEID_NULL, /* an event does not have a parent */
|
|
|
+ UA_NODEID_NULL, /* an event does not have any references */
|
|
|
+ name, /* an event does not have a name */
|
|
|
+ eventType, /* the type of the event */
|
|
|
+ oAttr, /* default attributes are fine */
|
|
|
+ NULL, /* no node context */
|
|
|
+ outNodeId);
|
|
|
|
|
|
if (retval != UA_STATUSCODE_GOOD) {
|
|
|
UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_USERLAND,
|
|
|
"Adding event failed. StatusCode %s", UA_StatusCode_name(retval));
|
|
|
return retval;
|
|
|
}
|
|
|
+
|
|
|
/* find the eventType variableNode */
|
|
|
name = UA_QUALIFIEDNAME(0, "EventType");
|
|
|
UA_BrowsePathResult bpr;
|
|
|
UA_BrowsePathResult_init(&bpr);
|
|
|
UA_Event_findVariableNode(server, &name, 1, outNodeId, &bpr);
|
|
|
- if (bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
|
|
|
+ if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
|
|
|
+ UA_BrowsePathResult_deleteMembers(&bpr);
|
|
|
return bpr.statusCode;
|
|
|
}
|
|
|
UA_Variant value;
|
|
@@ -176,43 +179,48 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType, UA_NodeId *o
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
-static UA_Boolean isValidEvent(UA_Server *server, const UA_NodeId *validEventParent, const UA_NodeId *eventId) {
|
|
|
+static UA_Boolean
|
|
|
+isValidEvent(UA_Server *server, const UA_NodeId *validEventParent, const UA_NodeId *eventId) {
|
|
|
/* find the eventType variableNode */
|
|
|
UA_BrowsePathResult bpr;
|
|
|
UA_BrowsePathResult_init(&bpr);
|
|
|
UA_QualifiedName findName = UA_QUALIFIEDNAME(0, "EventType");
|
|
|
UA_Event_findVariableNode(server, &findName, 1, eventId, &bpr);
|
|
|
- if (bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
|
|
|
+ if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
|
|
|
+ UA_BrowsePathResult_deleteMembers(&bpr);
|
|
|
return UA_FALSE;
|
|
|
}
|
|
|
UA_NodeId hasSubtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
|
|
|
- UA_Boolean tmp = isNodeInTree(&server->config.nodestore, &bpr.targets[0].targetId.nodeId, validEventParent,
|
|
|
- &hasSubtypeId, 1);
|
|
|
+ UA_Boolean tmp = isNodeInTree(&server->config.nodestore, &bpr.targets[0].targetId.nodeId,
|
|
|
+ validEventParent, &hasSubtypeId, 1);
|
|
|
UA_BrowsePathResult_deleteMembers(&bpr);
|
|
|
return tmp;
|
|
|
}
|
|
|
|
|
|
|
|
|
-static UA_StatusCode whereClausesApply(UA_Server *server, const UA_ContentFilter whereClause, UA_EventFieldList *efl,
|
|
|
- UA_Boolean *result) {
|
|
|
+static UA_StatusCode
|
|
|
+whereClausesApply(UA_Server *server, const UA_ContentFilter whereClause,
|
|
|
+ UA_EventFieldList *efl, UA_Boolean *result) {
|
|
|
/* if the where clauses aren't specified leave everything as is */
|
|
|
- if (whereClause.elementsSize == 0) {
|
|
|
+ if(whereClause.elementsSize == 0) {
|
|
|
*result = UA_TRUE;
|
|
|
return UA_STATUSCODE_GOOD;
|
|
|
}
|
|
|
+
|
|
|
/* where clauses were specified */
|
|
|
- UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_USERLAND, "Where clauses are not supported by the server.");
|
|
|
+ UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_USERLAND,
|
|
|
+ "Where clauses are not supported by the server.");
|
|
|
*result = UA_TRUE;
|
|
|
return UA_STATUSCODE_BADNOTSUPPORTED;
|
|
|
}
|
|
|
|
|
|
/* filters the given event with the given filter and writes the results into a notification */
|
|
|
-static UA_StatusCode UA_Server_filterEvent(UA_Server *server, const UA_NodeId *eventNode, UA_EventFilter *filter,
|
|
|
- UA_EventNotification *notification) {
|
|
|
- if (filter->selectClausesSize == 0) {
|
|
|
+static UA_StatusCode
|
|
|
+UA_Server_filterEvent(UA_Server *server, const UA_NodeId *eventNode, UA_EventFilter *filter,
|
|
|
+ UA_EventNotification *notification) {
|
|
|
+ if (filter->selectClausesSize == 0)
|
|
|
return UA_STATUSCODE_BADEVENTFILTERINVALID;
|
|
|
- }
|
|
|
- UA_StatusCode retval;
|
|
|
+
|
|
|
/* setup */
|
|
|
UA_EventFieldList_init(¬ification->fields);
|
|
|
|
|
@@ -242,39 +250,42 @@ static UA_StatusCode UA_Server_filterEvent(UA_Server *server, const UA_NodeId *e
|
|
|
/* check if the browsePath is BaseEventType, in which case nothing more needs to be checked */
|
|
|
UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
|
|
|
/* iterate over the selectClauses */
|
|
|
- for (size_t i = 0; i < filter->selectClausesSize; i++) {
|
|
|
- if (!UA_NodeId_equal(&filter->selectClauses[i].typeDefinitionId, &baseEventTypeId)
|
|
|
- && !isValidEvent(server, &filter->selectClauses[0].typeDefinitionId, eventNode)) {
|
|
|
+ for(size_t i = 0; i < filter->selectClausesSize; i++) {
|
|
|
+ if(!UA_NodeId_equal(&filter->selectClauses[i].typeDefinitionId, &baseEventTypeId) &&
|
|
|
+ !isValidEvent(server, &filter->selectClauses[0].typeDefinitionId, eventNode)) {
|
|
|
UA_Variant_init(¬ification->fields.eventFields[i]);
|
|
|
/* EventFilterResult currently isn't being used
|
|
|
notification->result.selectClauseResults[i] = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; */
|
|
|
continue;
|
|
|
}
|
|
|
+
|
|
|
/* type is correct */
|
|
|
/* find the variable node with the data being looked for */
|
|
|
UA_BrowsePathResult bpr;
|
|
|
UA_BrowsePathResult_init(&bpr);
|
|
|
- UA_Event_findVariableNode(server, filter->selectClauses[i].browsePath, filter->selectClauses[i].browsePathSize,
|
|
|
- eventNode, &bpr);
|
|
|
+ UA_Event_findVariableNode(server, filter->selectClauses[i].browsePath,
|
|
|
+ filter->selectClauses[i].browsePathSize, eventNode, &bpr);
|
|
|
if (bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
|
|
|
UA_Variant_init(¬ification->fields.eventFields[i]);
|
|
|
continue;
|
|
|
}
|
|
|
+
|
|
|
/* copy the value */
|
|
|
UA_Boolean whereClauseResult = UA_TRUE;
|
|
|
UA_Boolean whereClausesUsed = UA_FALSE; /* placeholder until whereClauses are implemented */
|
|
|
- retval = whereClausesApply(server, filter->whereClause, ¬ification->fields, &whereClauseResult);
|
|
|
- if (retval == UA_STATUSCODE_BADNOTSUPPORTED) {
|
|
|
+ UA_StatusCode retval = whereClausesApply(server, filter->whereClause,
|
|
|
+ ¬ification->fields, &whereClauseResult);
|
|
|
+ if (retval == UA_STATUSCODE_BADNOTSUPPORTED)
|
|
|
whereClausesUsed = UA_TRUE;
|
|
|
- }
|
|
|
- if (whereClauseResult) {
|
|
|
- retval = UA_Server_readValue(server, bpr.targets[0].targetId.nodeId, ¬ification->fields.eventFields[i]);
|
|
|
- if (retval != UA_STATUSCODE_GOOD) {
|
|
|
+
|
|
|
+ if(whereClauseResult) {
|
|
|
+ retval = UA_Server_readValue(server, bpr.targets[0].targetId.nodeId,
|
|
|
+ ¬ification->fields.eventFields[i]);
|
|
|
+ if(retval != UA_STATUSCODE_GOOD)
|
|
|
UA_Variant_init(¬ification->fields.eventFields[i]);
|
|
|
- }
|
|
|
- if (whereClausesUsed) {
|
|
|
+
|
|
|
+ if(whereClausesUsed)
|
|
|
return UA_STATUSCODE_BADNOTSUPPORTED;
|
|
|
- }
|
|
|
} else {
|
|
|
UA_Variant_init(¬ification->fields.eventFields[i]);
|
|
|
/* TODO: better statuscode for failing at where clauses */
|
|
@@ -286,8 +297,9 @@ static UA_StatusCode UA_Server_filterEvent(UA_Server *server, const UA_NodeId *e
|
|
|
return UA_STATUSCODE_GOOD;
|
|
|
}
|
|
|
|
|
|
-static UA_StatusCode eventSetConstants(UA_Server *server, const UA_NodeId *event, const UA_NodeId *origin,
|
|
|
- UA_ByteString *outEventId) {
|
|
|
+static UA_StatusCode
|
|
|
+eventSetConstants(UA_Server *server, const UA_NodeId *event,
|
|
|
+ const UA_NodeId *origin, UA_ByteString *outEventId) {
|
|
|
UA_BrowsePathResult bpr;
|
|
|
UA_BrowsePathResult_init(&bpr);
|
|
|
/* set the source */
|
|
@@ -347,12 +359,12 @@ static UA_StatusCode eventSetConstants(UA_Server *server, const UA_NodeId *event
|
|
|
|
|
|
|
|
|
/* insert each node into the list (passed as handle) */
|
|
|
-static UA_StatusCode getParentsNodeIteratorCallback(UA_NodeId parentId, UA_Boolean isInverse,
|
|
|
- UA_NodeId referenceTypeId, void *handle) {
|
|
|
+static UA_StatusCode
|
|
|
+getParentsNodeIteratorCallback(UA_NodeId parentId, UA_Boolean isInverse,
|
|
|
+ UA_NodeId referenceTypeId, void *handle) {
|
|
|
/* parents have an inverse reference */
|
|
|
- if (!isInverse) {
|
|
|
+ if(!isInverse)
|
|
|
return UA_STATUSCODE_GOOD;
|
|
|
- }
|
|
|
|
|
|
Events_nodeListElement *entry = (Events_nodeListElement *) UA_malloc(sizeof(Events_nodeListElement));
|
|
|
if (!entry) {
|
|
@@ -373,13 +385,15 @@ static UA_StatusCode getParentsNodeIteratorCallback(UA_NodeId parentId, UA_Boole
|
|
|
|
|
|
/* filters an event according to the filter specified by mon and then adds it to mons notification queue */
|
|
|
static UA_StatusCode
|
|
|
-UA_Event_addEventToMonitoredItem(UA_Server *server, const UA_NodeId *event, UA_MonitoredItem *mon) {
|
|
|
+UA_Event_addEventToMonitoredItem(UA_Server *server, const UA_NodeId *event,
|
|
|
+ UA_MonitoredItem *mon) {
|
|
|
UA_Notification *notification = (UA_Notification *) UA_malloc(sizeof(UA_Notification));
|
|
|
- if (!notification) {
|
|
|
+ if(!notification)
|
|
|
return UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
- }
|
|
|
+
|
|
|
/* apply the filter */
|
|
|
- UA_StatusCode retval = UA_Server_filterEvent(server, event, &mon->filter.eventFilter, ¬ification->data.event);
|
|
|
+ UA_StatusCode retval = UA_Server_filterEvent(server, event, &mon->filter.eventFilter,
|
|
|
+ ¬ification->data.event);
|
|
|
if (retval != UA_STATUSCODE_GOOD) {
|
|
|
UA_free(notification);
|
|
|
return retval;
|
|
@@ -405,15 +419,16 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
|
|
|
{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ORGANIZES}},
|
|
|
{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}}
|
|
|
};
|
|
|
- if (!isNodeInTree(&server->config.nodestore, &origin, &objectsFolderId, references, 2)) {
|
|
|
- UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_USERLAND, "Node for event must be in ObjectsFolder!");
|
|
|
+
|
|
|
+ if(!isNodeInTree(&server->config.nodestore, &origin, &objectsFolderId, references, 2)) {
|
|
|
+ UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_USERLAND,
|
|
|
+ "Node for event must be in ObjectsFolder!");
|
|
|
return UA_STATUSCODE_BADINVALIDARGUMENT;
|
|
|
}
|
|
|
|
|
|
UA_StatusCode retval = eventSetConstants(server, &eventNodeId, &origin, outEventId);
|
|
|
- if (retval != UA_STATUSCODE_GOOD) {
|
|
|
+ if(retval != UA_STATUSCODE_GOOD)
|
|
|
return retval;
|
|
|
- }
|
|
|
|
|
|
/* get an array with all parents */
|
|
|
struct getNodesHandle parentHandle;
|
|
@@ -422,9 +437,8 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
|
|
|
parentHandle.server = server;
|
|
|
parentHandle.nodes = &parentList;
|
|
|
retval = getParentsNodeIteratorCallback(origin, UA_TRUE, UA_NODEID_NULL, &parentHandle);
|
|
|
- if (retval != UA_STATUSCODE_GOOD) {
|
|
|
+ if(retval != UA_STATUSCODE_GOOD)
|
|
|
return retval;
|
|
|
- }
|
|
|
|
|
|
/* add the event to each node's monitored items */
|
|
|
Events_nodeListElement *parentIter, *tmp_parentIter;
|