ua_client_subscriptions_deprecated.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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 2015-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
  6. * Copyright 2015 (c) Oleksiy Vasylyev
  7. * Copyright 2016 (c) Sten Grüner
  8. * Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA
  9. * Copyright 2016-2017 (c) Florian Palm
  10. * Copyright 2017 (c) Frank Meerkötter
  11. * Copyright 2017 (c) Stefan Profanter, fortiss GmbH
  12. */
  13. #include "ua_client_highlevel.h"
  14. #include "ua_client_internal.h"
  15. #include "ua_util.h"
  16. #ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */
  17. const UA_SubscriptionSettings UA_SubscriptionSettings_default = {
  18. 500.0, /* .requestedPublishingInterval */
  19. 10000, /* .requestedLifetimeCount */
  20. 1, /* .requestedMaxKeepAliveCount */
  21. 0, /* .maxNotificationsPerPublish */
  22. true, /* .publishingEnabled */
  23. 0 /* .priority */
  24. };
  25. UA_StatusCode
  26. UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings,
  27. UA_UInt32 *newSubscriptionId) {
  28. UA_CreateSubscriptionRequest request;
  29. UA_CreateSubscriptionRequest_init(&request);
  30. request.requestedPublishingInterval = settings.requestedPublishingInterval;
  31. request.requestedLifetimeCount = settings.requestedLifetimeCount;
  32. request.requestedMaxKeepAliveCount = settings.requestedMaxKeepAliveCount;
  33. request.maxNotificationsPerPublish = settings.maxNotificationsPerPublish;
  34. request.publishingEnabled = settings.publishingEnabled;
  35. request.priority = settings.priority;
  36. UA_CreateSubscriptionResponse response =
  37. UA_Client_Subscriptions_create(client, request, NULL, NULL, NULL);
  38. UA_StatusCode retval = response.responseHeader.serviceResult;
  39. if(retval == UA_STATUSCODE_GOOD && newSubscriptionId)
  40. *newSubscriptionId = response.subscriptionId;
  41. UA_CreateSubscriptionResponse_deleteMembers(&response);
  42. return retval;
  43. }
  44. UA_StatusCode
  45. UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId) {
  46. UA_DeleteSubscriptionsRequest request;
  47. UA_DeleteSubscriptionsRequest_init(&request);
  48. request.subscriptionIdsSize = 1;
  49. request.subscriptionIds = &subscriptionId;
  50. UA_DeleteSubscriptionsResponse response =
  51. UA_Client_Subscriptions_delete(client, request);
  52. UA_StatusCode retval = response.responseHeader.serviceResult;
  53. if(retval == UA_STATUSCODE_GOOD) {
  54. if(response.resultsSize != 1)
  55. retval = UA_STATUSCODE_BADINTERNALERROR;
  56. }
  57. if(retval == UA_STATUSCODE_GOOD)
  58. retval = response.results[0];
  59. UA_DeleteSubscriptionsResponse_deleteMembers(&response);
  60. return retval;
  61. }
  62. UA_StatusCode
  63. UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client) {
  64. if(client->state < UA_CLIENTSTATE_SESSION)
  65. return UA_STATUSCODE_BADSERVERNOTCONNECTED;
  66. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  67. UA_DateTime now = UA_DateTime_nowMonotonic();
  68. UA_DateTime maxDate = now + (UA_DateTime)(client->config.timeout * UA_DATETIME_MSEC);
  69. UA_Boolean moreNotifications = true;
  70. while(moreNotifications) {
  71. UA_PublishRequest request;
  72. UA_PublishRequest_init(&request);
  73. retval = UA_Client_preparePublishRequest(client, &request);
  74. if(retval != UA_STATUSCODE_GOOD)
  75. return retval;
  76. /* Manually increase the number of sent publish requests. Otherwise we
  77. * send out one too many when we process async responses when we wait
  78. * for the correct publish response. The
  79. * currentlyOutStandingPublishRequests will be reduced during processing
  80. * of the response. */
  81. client->currentlyOutStandingPublishRequests++;
  82. UA_PublishResponse response;
  83. __UA_Client_Service(client,
  84. &request, &UA_TYPES[UA_TYPES_PUBLISHREQUEST],
  85. &response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
  86. UA_Client_Subscriptions_processPublishResponse(client, &request, &response);
  87. UA_PublishRequest_deleteMembers(&request);
  88. now = UA_DateTime_nowMonotonic();
  89. if(now > maxDate) {
  90. moreNotifications = UA_FALSE;
  91. retval = UA_STATUSCODE_GOODNONCRITICALTIMEOUT;
  92. } else {
  93. moreNotifications = response.moreNotifications;
  94. }
  95. UA_PublishResponse_deleteMembers(&response);
  96. UA_PublishRequest_deleteMembers(&request);
  97. }
  98. if(client->state < UA_CLIENTSTATE_SESSION)
  99. return UA_STATUSCODE_BADSERVERNOTCONNECTED;
  100. return retval;
  101. }
  102. /* Callbacks for the MonitoredItems. The callbacks for the deprecated API are
  103. * wrapped. The wrapper is cleaned up upon destruction. */
  104. typedef struct {
  105. UA_MonitoredItemHandlingFunction origCallback;
  106. void *context;
  107. } dataChangeCallbackWrapper;
  108. static void
  109. dataChangeCallback(UA_Client *client, UA_UInt32 subId, void *subContext,
  110. UA_UInt32 monId, void *monContext, UA_DataValue *value) {
  111. dataChangeCallbackWrapper *wrapper = (dataChangeCallbackWrapper*)monContext;
  112. wrapper->origCallback(client, monId, value, wrapper->context);
  113. }
  114. typedef struct {
  115. UA_MonitoredEventHandlingFunction origCallback;
  116. void *context;
  117. } eventCallbackWrapper;
  118. static void
  119. eventCallback(UA_Client *client, UA_UInt32 subId, void *subContext,
  120. UA_UInt32 monId, void *monContext, size_t nEventFields,
  121. UA_Variant *eventFields) {
  122. eventCallbackWrapper *wrapper = (eventCallbackWrapper*)monContext;
  123. wrapper->origCallback(client, monId, nEventFields, eventFields, wrapper->context);
  124. }
  125. static void
  126. deleteMonitoredItemCallback(UA_Client *client, UA_UInt32 subId, void *subContext,
  127. UA_UInt32 monId, void *monContext) {
  128. UA_free(monContext);
  129. }
  130. static UA_StatusCode
  131. addMonitoredItems(UA_Client *client, const UA_UInt32 subscriptionId,
  132. UA_MonitoredItemCreateRequest *items, size_t itemsSize,
  133. UA_MonitoredItemHandlingFunction *hfs, void **hfContexts,
  134. UA_StatusCode *itemResults, UA_UInt32 *newMonitoredItemIds) {
  135. /* Create array of wrappers and callbacks */
  136. UA_STACKARRAY(dataChangeCallbackWrapper*, wrappers, itemsSize);
  137. UA_STACKARRAY(UA_Client_DeleteMonitoredItemCallback, deleteCbs, itemsSize);
  138. UA_STACKARRAY(UA_Client_DataChangeNotificationCallback, wrapperCbs, itemsSize);
  139. for(size_t i = 0; i < itemsSize; i++) {
  140. wrappers[i] = (dataChangeCallbackWrapper*)UA_malloc(sizeof(dataChangeCallbackWrapper));
  141. if(!wrappers[i]) {
  142. for(size_t j = 0; j < i; j++)
  143. UA_free(wrappers[j]);
  144. return UA_STATUSCODE_BADOUTOFMEMORY;
  145. }
  146. wrappers[i]->origCallback = (UA_MonitoredItemHandlingFunction)(uintptr_t)hfs[i];
  147. wrappers[i]->context = hfContexts[i];
  148. deleteCbs[i] = deleteMonitoredItemCallback;
  149. wrapperCbs[i] = dataChangeCallback;
  150. }
  151. /* Prepare the request */
  152. UA_CreateMonitoredItemsRequest request;
  153. UA_CreateMonitoredItemsRequest_init(&request);
  154. request.subscriptionId = subscriptionId;
  155. request.itemsToCreateSize = itemsSize;
  156. request.itemsToCreate = items;
  157. /* Process and return */
  158. UA_CreateMonitoredItemsResponse response =
  159. UA_Client_MonitoredItems_createDataChanges(client, request, (void**)wrappers,
  160. wrapperCbs, deleteCbs);
  161. UA_StatusCode retval = response.responseHeader.serviceResult;
  162. if(retval == UA_STATUSCODE_GOOD && response.resultsSize != itemsSize)
  163. retval = UA_STATUSCODE_BADINTERNALERROR;
  164. if(retval == UA_STATUSCODE_GOOD) {
  165. for(size_t i = 0; i < itemsSize; i++) {
  166. itemResults[i] = response.results[i].statusCode;
  167. newMonitoredItemIds[i] = response.results[i].monitoredItemId;
  168. }
  169. }
  170. UA_CreateMonitoredItemsResponse_deleteMembers(&response);
  171. return retval;
  172. }
  173. UA_StatusCode
  174. UA_Client_Subscriptions_addMonitoredItems(UA_Client *client, const UA_UInt32 subscriptionId,
  175. UA_MonitoredItemCreateRequest *items, size_t itemsSize,
  176. UA_MonitoredItemHandlingFunction *hfs,
  177. void **hfContexts, UA_StatusCode *itemResults,
  178. UA_UInt32 *newMonitoredItemIds) {
  179. return addMonitoredItems(client, subscriptionId, items, itemsSize, hfs, hfContexts, itemResults,
  180. newMonitoredItemIds);
  181. }
  182. UA_StatusCode
  183. UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
  184. UA_NodeId nodeId, UA_UInt32 attributeID,
  185. UA_MonitoredItemHandlingFunction hf, void *hfContext,
  186. UA_UInt32 *newMonitoredItemId, UA_Double samplingInterval) {
  187. UA_MonitoredItemCreateRequest item;
  188. UA_MonitoredItemCreateRequest_init(&item);
  189. item.itemToMonitor.nodeId = nodeId;
  190. item.itemToMonitor.attributeId = attributeID;
  191. item.monitoringMode = UA_MONITORINGMODE_REPORTING;
  192. item.requestedParameters.samplingInterval = samplingInterval;
  193. item.requestedParameters.discardOldest = true;
  194. item.requestedParameters.queueSize = 1;
  195. UA_StatusCode retval_item = UA_STATUSCODE_GOOD;
  196. UA_StatusCode retval =
  197. addMonitoredItems(client, subscriptionId, &item, 1,
  198. (UA_MonitoredItemHandlingFunction*)(uintptr_t)&hf,
  199. &hfContext, &retval_item, newMonitoredItemId);
  200. return retval | retval_item;
  201. }
  202. static UA_StatusCode
  203. addMonitoredEvents(UA_Client *client, const UA_UInt32 subscriptionId,
  204. UA_MonitoredItemCreateRequest *items, size_t itemsSize,
  205. UA_MonitoredEventHandlingFunction *hfs,
  206. void **hfContexts, UA_StatusCode *itemResults,
  207. UA_UInt32 *newMonitoredItemIds) {
  208. /* Create array of wrappers and callbacks */
  209. UA_STACKARRAY(eventCallbackWrapper*, wrappers, itemsSize);
  210. UA_STACKARRAY(UA_Client_DeleteMonitoredItemCallback, deleteCbs, itemsSize);
  211. UA_STACKARRAY(UA_Client_EventNotificationCallback, wrapperCbs, itemsSize);
  212. for(size_t i = 0; i < itemsSize; i++) {
  213. wrappers[i] = (eventCallbackWrapper*)UA_malloc(sizeof(eventCallbackWrapper));
  214. if(!wrappers[i]) {
  215. for(size_t j = 0; j < i; j++)
  216. UA_free(wrappers[j]);
  217. return UA_STATUSCODE_BADOUTOFMEMORY;
  218. }
  219. wrappers[i]->origCallback = (UA_MonitoredEventHandlingFunction)(uintptr_t)hfs[i];
  220. wrappers[i]->context = hfContexts[i];
  221. deleteCbs[i] = deleteMonitoredItemCallback;
  222. wrapperCbs[i] = eventCallback;
  223. }
  224. /* Prepare the request */
  225. UA_CreateMonitoredItemsRequest request;
  226. UA_CreateMonitoredItemsRequest_init(&request);
  227. request.subscriptionId = subscriptionId;
  228. request.itemsToCreateSize = itemsSize;
  229. request.itemsToCreate = items;
  230. /* Process and return */
  231. UA_CreateMonitoredItemsResponse response =
  232. UA_Client_MonitoredItems_createEvents(client, request, (void**)wrappers,
  233. wrapperCbs, deleteCbs);
  234. UA_StatusCode retval = response.responseHeader.serviceResult;
  235. if(retval == UA_STATUSCODE_GOOD && response.resultsSize != itemsSize)
  236. retval = UA_STATUSCODE_BADINTERNALERROR;
  237. if(retval == UA_STATUSCODE_GOOD) {
  238. for(size_t i = 0; i < itemsSize; i++)
  239. itemResults[i] = response.results[i].statusCode;
  240. }
  241. UA_CreateMonitoredItemsResponse_deleteMembers(&response);
  242. return retval;
  243. }
  244. UA_StatusCode
  245. UA_Client_Subscriptions_addMonitoredEvents(UA_Client *client, const UA_UInt32 subscriptionId,
  246. UA_MonitoredItemCreateRequest *items, size_t itemsSize,
  247. UA_MonitoredEventHandlingFunction *hfs,
  248. void **hfContexts, UA_StatusCode *itemResults,
  249. UA_UInt32 *newMonitoredItemIds) {
  250. return addMonitoredEvents(client, subscriptionId, items, itemsSize, hfs,
  251. hfContexts, itemResults, newMonitoredItemIds);
  252. }
  253. UA_StatusCode
  254. UA_Client_Subscriptions_addMonitoredEvent(UA_Client *client, UA_UInt32 subscriptionId,
  255. const UA_NodeId nodeId, UA_UInt32 attributeID,
  256. const UA_SimpleAttributeOperand *selectClauses,
  257. size_t selectClausesSize,
  258. const UA_ContentFilterElement *whereClauses,
  259. size_t whereClausesSize,
  260. const UA_MonitoredEventHandlingFunction hf,
  261. void *hfContext, UA_UInt32 *newMonitoredItemId) {
  262. UA_MonitoredItemCreateRequest item;
  263. UA_MonitoredItemCreateRequest_init(&item);
  264. item.itemToMonitor.nodeId = nodeId;
  265. item.itemToMonitor.attributeId = attributeID;
  266. item.monitoringMode = UA_MONITORINGMODE_REPORTING;
  267. item.requestedParameters.samplingInterval = 0;
  268. item.requestedParameters.discardOldest = false;
  269. UA_EventFilter *evFilter = UA_EventFilter_new();
  270. if(!evFilter)
  271. return UA_STATUSCODE_BADOUTOFMEMORY;
  272. UA_EventFilter_init(evFilter);
  273. evFilter->selectClausesSize = selectClausesSize;
  274. evFilter->selectClauses = (UA_SimpleAttributeOperand*)(uintptr_t)selectClauses;
  275. evFilter->whereClause.elementsSize = whereClausesSize;
  276. evFilter->whereClause.elements = (UA_ContentFilterElement*)(uintptr_t)whereClauses;
  277. item.requestedParameters.filter.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  278. item.requestedParameters.filter.content.decoded.type = &UA_TYPES[UA_TYPES_EVENTFILTER];
  279. item.requestedParameters.filter.content.decoded.data = evFilter;
  280. UA_StatusCode retval_item = UA_STATUSCODE_GOOD;
  281. UA_StatusCode retval = addMonitoredEvents(client, subscriptionId, &item, 1,
  282. (UA_MonitoredEventHandlingFunction*)(uintptr_t)&hf,
  283. &hfContext, &retval_item, newMonitoredItemId);
  284. UA_free(evFilter);
  285. return retval | retval_item;
  286. }
  287. static UA_StatusCode
  288. removeMonitoredItems(UA_Client *client, UA_UInt32 subscriptionId,
  289. UA_UInt32 *monitoredItemIds, size_t itemsSize,
  290. UA_StatusCode *itemResults) {
  291. UA_DeleteMonitoredItemsRequest request;
  292. UA_DeleteMonitoredItemsRequest_init(&request);
  293. request.subscriptionId = subscriptionId;
  294. request.monitoredItemIdsSize = itemsSize;
  295. request.monitoredItemIds = monitoredItemIds;
  296. UA_DeleteMonitoredItemsResponse response = UA_Client_MonitoredItems_delete(client, request);
  297. UA_StatusCode retval = response.responseHeader.serviceResult;
  298. if(retval == UA_STATUSCODE_GOOD) {
  299. if(response.resultsSize != itemsSize) {
  300. retval = UA_STATUSCODE_BADINTERNALERROR;
  301. } else {
  302. for(size_t i = 0; i < itemsSize; i++)
  303. itemResults[i] = response.results[i];
  304. }
  305. }
  306. UA_DeleteMonitoredItemsResponse_deleteMembers(&response);
  307. return retval;
  308. }
  309. UA_StatusCode
  310. UA_Client_Subscriptions_removeMonitoredItems(UA_Client *client, UA_UInt32 subscriptionId,
  311. UA_UInt32 *monitoredItemIds, size_t itemsSize,
  312. UA_StatusCode *itemResults) {
  313. return removeMonitoredItems(client, subscriptionId, monitoredItemIds, itemsSize, itemResults);
  314. }
  315. UA_StatusCode
  316. UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
  317. UA_UInt32 monitoredItemId) {
  318. UA_StatusCode retval_item = UA_STATUSCODE_GOOD;
  319. UA_StatusCode retval = removeMonitoredItems(client, subscriptionId, &monitoredItemId, 1, &retval_item);
  320. return retval | retval_item;
  321. }
  322. #endif /* UA_ENABLE_SUBSCRIPTIONS */