ua_subscription_events.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
  6. */
  7. #include "ua_server_internal.h"
  8. #include "ua_subscription.h"
  9. #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
  10. UA_StatusCode
  11. UA_MonitoredItem_removeNodeEventCallback(UA_Server *server, UA_Session *session,
  12. UA_Node *node, void *data) {
  13. /* data is the monitoredItemID */
  14. /* catch edge case that it's the first element */
  15. if (data == ((UA_ObjectNode *) node)->monitoredItemQueue) {
  16. ((UA_ObjectNode *)node)->monitoredItemQueue = ((UA_MonitoredItem *)data)->next;
  17. return UA_STATUSCODE_GOOD;
  18. }
  19. /* SLIST_FOREACH */
  20. for (UA_MonitoredItem *entry = ((UA_ObjectNode *) node)->monitoredItemQueue->next;
  21. entry != NULL; entry=entry->next) {
  22. if (entry == (UA_MonitoredItem *)data) {
  23. /* SLIST_REMOVE */
  24. UA_MonitoredItem *iter = ((UA_ObjectNode *) node)->monitoredItemQueue;
  25. for (; iter->next != entry; iter=iter->next) {}
  26. iter->next = entry->next;
  27. /* Unlike SLIST_REMOVE, do not free the entry, since it
  28. * is still being worked on in the calling function */
  29. break;
  30. }
  31. }
  32. return UA_STATUSCODE_GOOD;
  33. }
  34. typedef struct Events_nodeListElement {
  35. LIST_ENTRY(Events_nodeListElement) listEntry;
  36. UA_NodeId nodeId;
  37. } Events_nodeListElement;
  38. struct getNodesHandle {
  39. UA_Server *server;
  40. LIST_HEAD(Events_nodeList, Events_nodeListElement) nodes;
  41. };
  42. /* generates a unique event id */
  43. static UA_StatusCode
  44. UA_Event_generateEventId(UA_Server *server, UA_ByteString *generatedId) {
  45. /* EventId is a ByteString, which is basically just a string
  46. * We will use a 16-Byte ByteString as an identifier */
  47. generatedId->length = 16;
  48. generatedId->data = (UA_Byte *) UA_malloc(16 * sizeof(UA_Byte));
  49. if(!generatedId->data) {
  50. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_USERLAND,
  51. "Server unable to allocate memory for EventId data.");
  52. return UA_STATUSCODE_BADOUTOFMEMORY;
  53. }
  54. /* GUIDs are unique, have a size of 16 byte and already have
  55. * a generator so use that.
  56. * Make sure GUIDs really do have 16 byte, in case someone may
  57. * have changed that struct */
  58. UA_assert(sizeof(UA_Guid) == 16);
  59. UA_Guid tmpGuid = UA_Guid_random();
  60. memcpy(generatedId->data, &tmpGuid, 16);
  61. return UA_STATUSCODE_GOOD;
  62. }
  63. UA_StatusCode
  64. UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType, UA_NodeId *outNodeId) {
  65. if(!outNodeId) {
  66. UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND, "outNodeId cannot be NULL!");
  67. return UA_STATUSCODE_BADINVALIDARGUMENT;
  68. }
  69. /* Make sure the eventType is a subtype of BaseEventType */
  70. UA_NodeId hasSubtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
  71. UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
  72. if(!isNodeInTree(server->nsCtx, &eventType, &baseEventTypeId, &hasSubtypeId, 1)) {
  73. UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
  74. "Event type must be a subtype of BaseEventType!");
  75. return UA_STATUSCODE_BADINVALIDARGUMENT;
  76. }
  77. /* Create an ObjectNode which represents the event */
  78. UA_QualifiedName name;
  79. UA_QualifiedName_init(&name);
  80. UA_NodeId newNodeId = UA_NODEID_NULL;
  81. UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
  82. UA_StatusCode retval =
  83. UA_Server_addObjectNode(server,
  84. UA_NODEID_NULL, /* Set a random unused NodeId */
  85. UA_NODEID_NULL, /* No parent */
  86. UA_NODEID_NULL, /* No parent reference */
  87. name, /* an event does not have a name */
  88. eventType, /* the type of the event */
  89. oAttr, /* default attributes are fine */
  90. NULL, /* no node context */
  91. &newNodeId);
  92. if(retval != UA_STATUSCODE_GOOD) {
  93. UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
  94. "Adding event failed. StatusCode %s", UA_StatusCode_name(retval));
  95. return retval;
  96. }
  97. /* Find the eventType variable */
  98. name = UA_QUALIFIEDNAME(0, "EventType");
  99. UA_BrowsePathResult bpr = UA_Server_browseSimplifiedBrowsePath(server, newNodeId, 1, &name);
  100. if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
  101. retval = bpr.statusCode;
  102. UA_BrowsePathResult_deleteMembers(&bpr);
  103. UA_Server_deleteNode(server, newNodeId, true);
  104. UA_NodeId_deleteMembers(&newNodeId);
  105. return retval;
  106. }
  107. /* Set the EventType */
  108. UA_Variant value;
  109. UA_Variant_init(&value);
  110. UA_Variant_setScalar(&value, (void*)(uintptr_t)&eventType, &UA_TYPES[UA_TYPES_NODEID]);
  111. retval = UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);
  112. UA_BrowsePathResult_deleteMembers(&bpr);
  113. if(retval != UA_STATUSCODE_GOOD) {
  114. UA_Server_deleteNode(server, newNodeId, true);
  115. UA_NodeId_deleteMembers(&newNodeId);
  116. return retval;
  117. }
  118. *outNodeId = newNodeId;
  119. return UA_STATUSCODE_GOOD;
  120. }
  121. static UA_Boolean
  122. isValidEvent(UA_Server *server, const UA_NodeId *validEventParent, const UA_NodeId *eventId) {
  123. /* find the eventType variableNode */
  124. UA_QualifiedName findName = UA_QUALIFIEDNAME(0, "EventType");
  125. UA_BrowsePathResult bpr = UA_Server_browseSimplifiedBrowsePath(server, *eventId, 1, &findName);
  126. if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
  127. UA_BrowsePathResult_deleteMembers(&bpr);
  128. return false;
  129. }
  130. /* Get the EventType Property Node */
  131. UA_Variant tOutVariant;
  132. UA_Variant_init(&tOutVariant);
  133. /* Read the Value of EventType Property Node (the Value should be a NodeId) */
  134. UA_StatusCode retval = UA_Server_readValue(server, bpr.targets[0].targetId.nodeId, &tOutVariant);
  135. if(retval != UA_STATUSCODE_GOOD ||
  136. !UA_Variant_hasScalarType(&tOutVariant, &UA_TYPES[UA_TYPES_NODEID])) {
  137. UA_BrowsePathResult_deleteMembers(&bpr);
  138. return false;
  139. }
  140. const UA_NodeId *tEventType = (UA_NodeId*)tOutVariant.data;
  141. /* Make sure the EventType is not a Subtype of CondtionType
  142. * First check for filter set using UaExpert
  143. * (ConditionId Clause won't be present in Events, which are not Conditions)
  144. * Second check for Events which are Conditions or Alarms (Part 9 not supported yet) */
  145. UA_NodeId conditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE);
  146. UA_NodeId hasSubtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
  147. if(UA_NodeId_equal(validEventParent, &conditionTypeId) ||
  148. isNodeInTree(server->nsCtx, tEventType, &conditionTypeId, &hasSubtypeId, 1)) {
  149. UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
  150. "Alarms and Conditions are not supported yet!");
  151. UA_BrowsePathResult_deleteMembers(&bpr);
  152. UA_Variant_deleteMembers(&tOutVariant);
  153. return false;
  154. }
  155. /* check whether Valid Event other than Conditions */
  156. UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
  157. UA_Boolean isSubtypeOfBaseEvent = isNodeInTree(server->nsCtx, tEventType,
  158. &baseEventTypeId, &hasSubtypeId, 1);
  159. UA_BrowsePathResult_deleteMembers(&bpr);
  160. UA_Variant_deleteMembers(&tOutVariant);
  161. return isSubtypeOfBaseEvent;
  162. }
  163. /* static UA_StatusCode */
  164. /* whereClausesApply(UA_Server *server, const UA_ContentFilter whereClause, */
  165. /* UA_EventFieldList *efl, UA_Boolean *result) { */
  166. /* /\* if the where clauses aren't specified leave everything as is *\/ */
  167. /* if(whereClause.elementsSize == 0) { */
  168. /* *result = true; */
  169. /* return UA_STATUSCODE_GOOD; */
  170. /* } */
  171. /* /\* where clauses were specified *\/ */
  172. /* UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_USERLAND, */
  173. /* "Where clauses are not supported by the server."); */
  174. /* *result = true; */
  175. /* return UA_STATUSCODE_BADNOTSUPPORTED; */
  176. /* } */
  177. /* Part 4: 7.4.4.5 SimpleAttributeOperand
  178. * The clause can point to any attribute of nodes. Either a child of the event
  179. * node and also the event type. */
  180. static UA_StatusCode
  181. resolveSimpleAttributeOperand(UA_Server *server, UA_Session *session, const UA_NodeId *origin,
  182. const UA_SimpleAttributeOperand *sao, UA_Variant *value) {
  183. /* Prepare the ReadValueId */
  184. UA_ReadValueId rvi;
  185. UA_ReadValueId_init(&rvi);
  186. rvi.indexRange = sao->indexRange;
  187. rvi.attributeId = sao->attributeId;
  188. /* If this list (browsePath) is empty the Node is the instance of the
  189. * TypeDefinition. */
  190. if(sao->browsePathSize == 0) {
  191. rvi.nodeId = sao->typeDefinitionId;
  192. UA_DataValue v = UA_Server_readWithSession(server, session, &rvi, UA_TIMESTAMPSTORETURN_NEITHER);
  193. if(v.status == UA_STATUSCODE_GOOD && v.hasValue)
  194. *value = v.value;
  195. return v.status;
  196. }
  197. /* Resolve the browse path */
  198. UA_BrowsePathResult bpr =
  199. UA_Server_browseSimplifiedBrowsePath(server, *origin, sao->browsePathSize, sao->browsePath);
  200. if(bpr.targetsSize == 0 && bpr.statusCode == UA_STATUSCODE_GOOD)
  201. bpr.statusCode = UA_STATUSCODE_BADNOTFOUND;
  202. if(bpr.statusCode != UA_STATUSCODE_GOOD) {
  203. UA_StatusCode retval = bpr.statusCode;
  204. UA_BrowsePathResult_deleteMembers(&bpr);
  205. return retval;
  206. }
  207. /* Read the first matching element. Move the value to the output. */
  208. rvi.nodeId = bpr.targets[0].targetId.nodeId;
  209. UA_DataValue v = UA_Server_readWithSession(server, session, &rvi, UA_TIMESTAMPSTORETURN_NEITHER);
  210. if(v.status == UA_STATUSCODE_GOOD && v.hasValue)
  211. *value = v.value;
  212. UA_BrowsePathResult_deleteMembers(&bpr);
  213. return v.status;
  214. }
  215. /* filters the given event with the given filter and writes the results into a notification */
  216. static UA_StatusCode
  217. UA_Server_filterEvent(UA_Server *server, UA_Session *session,
  218. const UA_NodeId *eventNode, UA_EventFilter *filter,
  219. UA_EventNotification *notification) {
  220. if (filter->selectClausesSize == 0)
  221. return UA_STATUSCODE_BADEVENTFILTERINVALID;
  222. /* setup */
  223. UA_EventFieldList_init(&notification->fields);
  224. /* EventFilterResult isn't being used currently
  225. UA_EventFilterResult_init(&notification->result); */
  226. notification->fields.eventFieldsSize = filter->selectClausesSize;
  227. notification->fields.eventFields = (UA_Variant *) UA_Array_new(notification->fields.eventFieldsSize,
  228. &UA_TYPES[UA_TYPES_VARIANT]);
  229. if (!notification->fields.eventFields) {
  230. /* EventFilterResult currently isn't being used
  231. UA_EventFiterResult_deleteMembers(&notification->result); */
  232. return UA_STATUSCODE_BADOUTOFMEMORY;
  233. }
  234. /* EventFilterResult currently isn't being used
  235. notification->result.selectClauseResultsSize = filter->selectClausesSize;
  236. notification->result.selectClauseResults = (UA_StatusCode *)
  237. UA_Array_new(filter->selectClausesSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
  238. if (!notification->result->selectClauseResults) {
  239. UA_EventFieldList_deleteMembers(&notification->fields);
  240. UA_EventFilterResult_deleteMembers(&notification->result);
  241. return UA_STATUSCODE_BADOUTOFMEMORY;
  242. }
  243. */
  244. /* ================ apply the filter ===================== */
  245. /* check if the browsePath is BaseEventType, in which case nothing more needs to be checked */
  246. UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
  247. /* iterate over the selectClauses */
  248. for(size_t i = 0; i < filter->selectClausesSize; i++) {
  249. if(!UA_NodeId_equal(&filter->selectClauses[i].typeDefinitionId, &baseEventTypeId) &&
  250. !isValidEvent(server, &filter->selectClauses[i].typeDefinitionId, eventNode)) {
  251. UA_Variant_init(&notification->fields.eventFields[i]);
  252. /* EventFilterResult currently isn't being used
  253. notification->result.selectClauseResults[i] = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; */
  254. continue;
  255. }
  256. /* TODO: Put the result into the selectClausResults */
  257. resolveSimpleAttributeOperand(server, session, eventNode,
  258. &filter->selectClauses[i],
  259. &notification->fields.eventFields[i]);
  260. }
  261. /* UA_Boolean whereClauseResult = true; */
  262. /* return whereClausesApply(server, filter->whereClause, &notification->fields, &whereClauseResult); */
  263. return UA_STATUSCODE_GOOD;
  264. }
  265. static UA_StatusCode
  266. eventSetStandardFields(UA_Server *server, const UA_NodeId *event,
  267. const UA_NodeId *origin, UA_ByteString *outEventId) {
  268. /* Set the SourceNode */
  269. UA_StatusCode retval;
  270. UA_QualifiedName name = UA_QUALIFIEDNAME(0, "SourceNode");
  271. UA_BrowsePathResult bpr = UA_Server_browseSimplifiedBrowsePath(server, *event, 1, &name);
  272. if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
  273. retval = bpr.statusCode;
  274. UA_BrowsePathResult_deleteMembers(&bpr);
  275. return retval;
  276. }
  277. UA_Variant value;
  278. UA_Variant_init(&value);
  279. UA_Variant_setScalarCopy(&value, origin, &UA_TYPES[UA_TYPES_NODEID]);
  280. retval = UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);
  281. UA_Variant_deleteMembers(&value);
  282. UA_BrowsePathResult_deleteMembers(&bpr);
  283. if(retval != UA_STATUSCODE_GOOD)
  284. return retval;
  285. /* Set the ReceiveTime */
  286. name = UA_QUALIFIEDNAME(0, "ReceiveTime");
  287. bpr = UA_Server_browseSimplifiedBrowsePath(server, *event, 1, &name);
  288. if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
  289. retval = bpr.statusCode;
  290. UA_BrowsePathResult_deleteMembers(&bpr);
  291. return retval;
  292. }
  293. UA_DateTime rcvTime = UA_DateTime_now();
  294. UA_Variant_setScalar(&value, &rcvTime, &UA_TYPES[UA_TYPES_DATETIME]);
  295. retval = UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);
  296. UA_BrowsePathResult_deleteMembers(&bpr);
  297. if(retval != UA_STATUSCODE_GOOD)
  298. return retval;
  299. /* Set the EventId */
  300. UA_ByteString eventId = UA_BYTESTRING_NULL;
  301. retval = UA_Event_generateEventId(server, &eventId);
  302. if(retval != UA_STATUSCODE_GOOD)
  303. return retval;
  304. name = UA_QUALIFIEDNAME(0, "EventId");
  305. bpr = UA_Server_browseSimplifiedBrowsePath(server, *event, 1, &name);
  306. if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
  307. retval = bpr.statusCode;
  308. UA_ByteString_deleteMembers(&eventId);
  309. UA_BrowsePathResult_deleteMembers(&bpr);
  310. return retval;
  311. }
  312. UA_Variant_init(&value);
  313. UA_Variant_setScalar(&value, &eventId, &UA_TYPES[UA_TYPES_BYTESTRING]);
  314. retval = UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);
  315. UA_BrowsePathResult_deleteMembers(&bpr);
  316. if(retval != UA_STATUSCODE_GOOD) {
  317. UA_ByteString_deleteMembers(&eventId);
  318. return retval;
  319. }
  320. /* Return the EventId */
  321. if(outEventId)
  322. *outEventId = eventId;
  323. else
  324. UA_ByteString_deleteMembers(&eventId);
  325. return UA_STATUSCODE_GOOD;
  326. }
  327. /* Insert each node into the list (passed as handle) */
  328. static UA_StatusCode
  329. getParentsNodeIteratorCallback(UA_NodeId parentId, UA_Boolean isInverse,
  330. UA_NodeId referenceTypeId, struct getNodesHandle *handle) {
  331. /* Parents have an inverse reference */
  332. if(!isInverse)
  333. return UA_STATUSCODE_GOOD;
  334. /* Is this a hierarchical reference? */
  335. if(!isNodeInTree(handle->server->nsCtx, &referenceTypeId,
  336. &hierarchicalReferences, &subtypeId, 1))
  337. return UA_STATUSCODE_GOOD;
  338. Events_nodeListElement *entry = (Events_nodeListElement *)
  339. UA_malloc(sizeof(Events_nodeListElement));
  340. if(!entry)
  341. return UA_STATUSCODE_BADOUTOFMEMORY;
  342. UA_StatusCode retval = UA_NodeId_copy(&parentId, &entry->nodeId);
  343. if(retval != UA_STATUSCODE_GOOD) {
  344. UA_free(entry);
  345. return retval;
  346. }
  347. LIST_INSERT_HEAD(&handle->nodes, entry, listEntry);
  348. /* Recursion */
  349. UA_Server_forEachChildNodeCall(handle->server, parentId, (UA_NodeIteratorCallback)getParentsNodeIteratorCallback, handle);
  350. return UA_STATUSCODE_GOOD;
  351. }
  352. /* Filters an event according to the filter specified by mon and then adds it to
  353. * mons notification queue */
  354. static UA_StatusCode
  355. UA_Event_addEventToMonitoredItem(UA_Server *server, const UA_NodeId *event,
  356. UA_MonitoredItem *mon) {
  357. UA_Notification *notification = (UA_Notification *) UA_malloc(sizeof(UA_Notification));
  358. if(!notification)
  359. return UA_STATUSCODE_BADOUTOFMEMORY;
  360. /* Get the session */
  361. UA_Subscription *sub = mon->subscription;
  362. UA_Session *session = sub->session;
  363. /* Apply the filter */
  364. UA_StatusCode retval = UA_Server_filterEvent(server, session, event,
  365. &mon->filter.eventFilter,
  366. &notification->data.event);
  367. if(retval != UA_STATUSCODE_GOOD) {
  368. UA_free(notification);
  369. return retval;
  370. }
  371. /* Enqueue the notification */
  372. notification->mon = mon;
  373. UA_Notification_enqueue(server, mon->subscription, mon, notification);
  374. return UA_STATUSCODE_GOOD;
  375. }
  376. static const UA_NodeId objectsFolderId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_OBJECTSFOLDER}};
  377. static const UA_NodeId parentReferences_events[2] =
  378. {{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ORGANIZES}},
  379. {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}}};
  380. UA_StatusCode
  381. UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_NodeId origin,
  382. UA_ByteString *outEventId, const UA_Boolean deleteEventNode) {
  383. /* Check that the origin node exists */
  384. const UA_Node *originNode = UA_Nodestore_getNode(server->nsCtx, &origin);
  385. if(!originNode) {
  386. UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
  387. "Origin node for event does not exist.");
  388. return UA_STATUSCODE_BADNOTFOUND;
  389. }
  390. UA_Nodestore_releaseNode(server->nsCtx, originNode);
  391. /* Make sure the origin is in the ObjectsFolder (TODO: or in the ViewsFolder) */
  392. UA_NodeId *parentTypeHierachy = NULL;
  393. size_t parentTypeHierachySize = 0;
  394. getTypesHierarchy(server->nsCtx, parentReferences_events, 2,
  395. &parentTypeHierachy, &parentTypeHierachySize, true);
  396. UA_Boolean isInObjectsFolder = isNodeInTree(server->nsCtx, &origin, &objectsFolderId,
  397. parentTypeHierachy, parentTypeHierachySize);
  398. UA_Array_delete(parentTypeHierachy, parentTypeHierachySize, &UA_TYPES[UA_TYPES_NODEID]);
  399. if (!isInObjectsFolder) {
  400. UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
  401. "Node for event must be in ObjectsFolder!");
  402. return UA_STATUSCODE_BADINVALIDARGUMENT;
  403. }
  404. UA_StatusCode retval = eventSetStandardFields(server, &eventNodeId, &origin, outEventId);
  405. if(retval != UA_STATUSCODE_GOOD) {
  406. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  407. "Events: Could not set the standard event fields with StatusCode %s",
  408. UA_StatusCode_name(retval));
  409. return retval;
  410. }
  411. /* Get an array with all parents. The first call to
  412. * getParentsNodeIteratorCallback adds the emitting node itself. */
  413. struct getNodesHandle parentHandle;
  414. parentHandle.server = server;
  415. LIST_INIT(&parentHandle.nodes);
  416. retval = getParentsNodeIteratorCallback(origin, true, parentReferences_events[1], &parentHandle);
  417. if(retval != UA_STATUSCODE_GOOD) {
  418. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  419. "Events: Could not create the list of nodes listening on the "
  420. "event with StatusCode %s", UA_StatusCode_name(retval));
  421. return retval;
  422. }
  423. /* Add the event to each node's monitored items */
  424. Events_nodeListElement *parentIter, *tmp_parentIter;
  425. LIST_FOREACH_SAFE(parentIter, &parentHandle.nodes, listEntry, tmp_parentIter) {
  426. const UA_ObjectNode *node = (const UA_ObjectNode*)
  427. UA_Nodestore_getNode(server->nsCtx, &parentIter->nodeId);
  428. if(node->nodeClass == UA_NODECLASS_OBJECT) {
  429. for(UA_MonitoredItem *monIter = node->monitoredItemQueue; monIter != NULL; monIter = monIter->next) {
  430. retval = UA_Event_addEventToMonitoredItem(server, &eventNodeId, monIter);
  431. if(retval != UA_STATUSCODE_GOOD) {
  432. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  433. "Events: Could not add the event to a listening node with StatusCode %s",
  434. UA_StatusCode_name(retval));
  435. }
  436. }
  437. }
  438. UA_Nodestore_releaseNode(server->nsCtx, (const UA_Node*)node);
  439. LIST_REMOVE(parentIter, listEntry);
  440. UA_NodeId_deleteMembers(&parentIter->nodeId);
  441. UA_free(parentIter);
  442. }
  443. /* Delete the node representation of the event */
  444. if(deleteEventNode) {
  445. retval = UA_Server_deleteNode(server, eventNodeId, true);
  446. if (retval != UA_STATUSCODE_GOOD) {
  447. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  448. "Attempt to remove event using deleteNode failed. StatusCode %s",
  449. UA_StatusCode_name(retval));
  450. return retval;
  451. }
  452. }
  453. return UA_STATUSCODE_GOOD;
  454. }
  455. #endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */