Browse Source

Fix modification of monitored items

If a client handle is modified after creation, the new value is used in
data change notifications from the server. If the new handle doesn't match
the initial handle, the client is unable to dispatch the data change
notification to the callback associated with the monitored item.

Client handles supplied by the API user during monitored item creation
are replaced internally by a counter value and there is no way to retrieve
the client handle for a monitored item after its creation.
Setting the client handle from the monitored item id before sending the
modify request to the server solves that problem.
Jannis Voelker 5 years ago
parent
commit
4d0cc3177d
2 changed files with 49 additions and 12 deletions
  1. 11 12
      include/open62541/client_subscriptions.h
  2. 38 0
      src/client/ua_client_subscriptions.c

+ 11 - 12
include/open62541/client_subscriptions.h

@@ -99,8 +99,8 @@ UA_Client_Subscriptions_setPublishingMode(UA_Client *client,
  * forward Event notifications from that node.
  *
  * During the creation of a MonitoredItem, the server may return changed
- * adjusted parameters. Use ``UA_Client_MonitoredItem_getParameters`` to get the
- * current parameters. */
+ * adjusted parameters. Check the returned ``UA_CreateMonitoredItemsResponse``
+ * to get the current parameters. */
 
 /* Provides default values for a new monitored item. */
 static UA_INLINE UA_MonitoredItemCreateRequest
@@ -116,6 +116,10 @@ UA_MonitoredItemCreateRequest_default(UA_NodeId nodeId) {
     return request;
 }
 
+/**
+ * The clientHandle parameter can't be set by the user, any value will be replaced
+ * by the client before sending the request to the server. */
+
 /* Callback for the deletion of a MonitoredItem */
 typedef void (*UA_Client_DeleteMonitoredItemCallback)
     (UA_Client *client, UA_UInt32 subId, void *subContext,
@@ -165,20 +169,15 @@ UA_Client_MonitoredItems_delete(UA_Client *client, const UA_DeleteMonitoredItems
 UA_StatusCode UA_EXPORT
 UA_Client_MonitoredItems_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId, UA_UInt32 monitoredItemId);
 
+/* The clientHandle parameter will be filled automatically */
+UA_ModifyMonitoredItemsResponse UA_EXPORT
+UA_Client_MonitoredItems_modify(UA_Client *client,
+                                const UA_ModifyMonitoredItemsRequest request);
+
 /**
  * The following service calls go directly to the server. The MonitoredItem settings are
  * not stored in the client. */
 
-static UA_INLINE UA_ModifyMonitoredItemsResponse
-UA_Client_MonitoredItems_modify(UA_Client *client,
-                                const UA_ModifyMonitoredItemsRequest request) {
-    UA_ModifyMonitoredItemsResponse response;
-    __UA_Client_Service(client,
-                        &request, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST],
-                        &response, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE]);
-    return response;
-}
-
 static UA_INLINE UA_SetMonitoringModeResponse
 UA_Client_MonitoredItems_setMonitoringMode(UA_Client *client,
                                            const UA_SetMonitoringModeRequest request) {

+ 38 - 0
src/client/ua_client_subscriptions.c

@@ -439,6 +439,44 @@ UA_Client_MonitoredItems_deleteSingle(UA_Client *client, UA_UInt32 subscriptionI
     return retval;
 }
 
+UA_ModifyMonitoredItemsResponse UA_EXPORT
+UA_Client_MonitoredItems_modify(UA_Client *client,
+                                const UA_ModifyMonitoredItemsRequest request) {
+    UA_ModifyMonitoredItemsResponse response;
+
+    UA_Client_Subscription *sub = 0;
+    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
+        if (sub->subscriptionId == request.subscriptionId)
+            break;
+    }
+
+    if (!sub) {
+        UA_ModifyMonitoredItemsResponse_init(&response);
+        response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
+        return response;
+    }
+
+    UA_ModifyMonitoredItemsRequest modifiedRequest;
+    UA_ModifyMonitoredItemsRequest_copy(&request, &modifiedRequest);
+
+    for (size_t i = 0; i < modifiedRequest.itemsToModifySize; ++i) {
+        UA_Client_MonitoredItem *mon = 0;
+        LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
+            if(mon->monitoredItemId == modifiedRequest.itemsToModify[i].monitoredItemId) {
+                modifiedRequest.itemsToModify[i].requestedParameters.clientHandle = mon->clientHandle;
+                break;
+            }
+        }
+    }
+
+    __UA_Client_Service(client,
+                        &modifiedRequest, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE]);
+
+    UA_ModifyMonitoredItemsRequest_deleteMembers(&modifiedRequest);
+    return response;
+}
+
 /*************************************/
 /* Async Processing of Notifications */
 /*************************************/