From 22e1bd90cad932e8a37e42626a378c627a495162 Mon Sep 17 00:00:00 2001 From: Rolf Kalbermatter <15158041+RolfKal@users.noreply.github.com> Date: Mon, 18 Nov 2024 22:43:01 +0100 Subject: [PATCH] feat(client): Add new function to retrieve the user supplied subscription and monitored item contexts (#6877) --- include/open62541/client_subscriptions.h | 14 +++ src/client/ua_client_subscriptions.c | 130 ++++++++++++++++++++--- src/pubsub/ua_pubsub_dataset.c | 2 +- 3 files changed, 130 insertions(+), 16 deletions(-) diff --git a/include/open62541/client_subscriptions.h b/include/open62541/client_subscriptions.h index 08c4a1717c7..6dd3d478dcf 100644 --- a/include/open62541/client_subscriptions.h +++ b/include/open62541/client_subscriptions.h @@ -102,6 +102,13 @@ UA_Client_Subscriptions_delete_async(UA_Client *client, UA_StatusCode UA_EXPORT UA_THREADSAFE UA_Client_Subscriptions_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId); +/* Retrieve or change the user supplied subscription contexts */ +UA_StatusCode UA_EXPORT UA_THREADSAFE +UA_Client_Subscriptions_getContext(UA_Client *client, UA_UInt32 subscriptionId, void **subContext); + +UA_StatusCode UA_EXPORT UA_THREADSAFE +UA_Client_Subscriptions_setContext(UA_Client *client, UA_UInt32 subscriptionId, void *subContext); + static UA_INLINE UA_THREADSAFE UA_SetPublishingModeResponse UA_Client_Subscriptions_setPublishingMode(UA_Client *client, const UA_SetPublishingModeRequest request) { @@ -277,6 +284,13 @@ UA_Client_MonitoredItems_setTriggering_async(UA_Client *client, userdata, requestId); } +/* Retrieve or change the user supplied monitored item context */ +UA_StatusCode UA_EXPORT UA_THREADSAFE +UA_Client_MonitoredItem_getContext(UA_Client *client, UA_UInt32 subscriptionId, UA_UInt32 monitoredItemId, void **monContext); + +UA_StatusCode UA_EXPORT UA_THREADSAFE +UA_Client_MonitoredItem_setContext(UA_Client *client, UA_UInt32 subscriptionId, UA_UInt32 monitoredItemId, void *monContext); + _UA_END_DECLS #endif /* UA_CLIENT_SUBSCRIPTIONS_H_ */ diff --git a/src/client/ua_client_subscriptions.c b/src/client/ua_client_subscriptions.c index d141ad4d579..c8f2a4c86b0 100644 --- a/src/client/ua_client_subscriptions.c +++ b/src/client/ua_client_subscriptions.c @@ -160,7 +160,7 @@ UA_Client_Subscriptions_create_async(UA_Client *client, } static UA_Client_Subscription * -findSubscription(const UA_Client *client, UA_UInt32 subscriptionId) { +findSubscriptionById(const UA_Client *client, UA_UInt32 subscriptionId) { UA_Client_Subscription *sub = NULL; LIST_FOREACH(sub, &client->subscriptions, listEntry) { if(sub->subscriptionId == subscriptionId) @@ -183,7 +183,7 @@ ua_Subscriptions_modify_handler(UA_Client *client, void *data, UA_UInt32 request CustomCallback *cc = (CustomCallback *)data; UA_LOCK(&client->clientMutex); UA_Client_Subscription *sub = - findSubscription(client, (UA_UInt32)(uintptr_t)cc->clientData); + findSubscriptionById(client, (UA_UInt32)(uintptr_t)cc->clientData); if(sub) { ua_Subscriptions_modify(client, sub, response); } else { @@ -198,6 +198,42 @@ ua_Subscriptions_modify_handler(UA_Client *client, void *data, UA_UInt32 request UA_free(cc); } +UA_StatusCode +UA_Client_Subscriptions_getContext(UA_Client *client, UA_UInt32 subscriptionId, void **subContext) +{ + if (!client || !subContext) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + UA_LOCK(&client->clientMutex); + UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId); + if (!sub) { + UA_UNLOCK(&client->clientMutex); + return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + } + + *subContext = sub->context; + UA_UNLOCK(&client->clientMutex); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Client_Subscriptions_setContext(UA_Client *client, UA_UInt32 subscriptionId, void *subContext) +{ + if (!client) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + UA_LOCK(&client->clientMutex); + UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId); + if (!sub) { + UA_UNLOCK(&client->clientMutex); + return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + } + + sub->context = subContext; + UA_UNLOCK(&client->clientMutex); + return UA_STATUSCODE_GOOD; +} + UA_ModifySubscriptionResponse UA_Client_Subscriptions_modify(UA_Client *client, const UA_ModifySubscriptionRequest request) { @@ -206,7 +242,7 @@ UA_Client_Subscriptions_modify(UA_Client *client, /* Find the internal representation */ UA_LOCK(&client->clientMutex); - UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId); + UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId); UA_UNLOCK(&client->clientMutex); if(!sub) { response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; @@ -220,7 +256,7 @@ UA_Client_Subscriptions_modify(UA_Client *client, /* Adjust the internal representation. Lookup again for thread-safety. */ UA_LOCK(&client->clientMutex); - sub = findSubscription(client, request.subscriptionId); + sub = findSubscriptionById(client, request.subscriptionId); if(!sub) { response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; UA_UNLOCK(&client->clientMutex); @@ -238,7 +274,7 @@ UA_Client_Subscriptions_modify_async(UA_Client *client, void *userdata, UA_UInt32 *requestId) { /* Find the internal representation */ UA_LOCK(&client->clientMutex); - UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId); + UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId); UA_UNLOCK(&client->clientMutex); if(!sub) return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; @@ -313,7 +349,7 @@ __Client_Subscription_processDelete(UA_Client *client, /* Get the Subscription */ UA_Client_Subscription *sub = - findSubscription(client, request->subscriptionIds[i]); + findSubscriptionById(client, request->subscriptionIds[i]); if(!sub) { UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT, "No internal representation of subscription %" PRIu32, @@ -465,7 +501,7 @@ ua_MonitoredItems_create(UA_Client *client, MonitoredItems_CreateData *data, UA_CreateMonitoredItemsRequest *request = &data->request; UA_Client_DeleteMonitoredItemCallback *deleteCallbacks = data->deleteCallbacks; - UA_Client_Subscription *sub = findSubscription(client, data->request.subscriptionId); + UA_Client_Subscription *sub = findSubscriptionById(client, data->request.subscriptionId); if(!sub) goto cleanup; @@ -607,7 +643,7 @@ ua_Client_MonitoredItems_create(UA_Client *client, } /* Test if the subscription is valid */ - UA_Client_Subscription *sub = findSubscription(client, request->subscriptionId); + UA_Client_Subscription *sub = findSubscriptionById(client, request->subscriptionId); if(!sub) { response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; return; @@ -644,7 +680,7 @@ createDataChanges_async(UA_Client *client, const UA_CreateMonitoredItemsRequest UA_UInt32 *requestId) { UA_LOCK_ASSERT(&client->clientMutex); - UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId); + UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId); if(!sub) return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; @@ -830,7 +866,7 @@ ua_MonitoredItems_delete_handler(UA_Client *client, void *d, UA_UInt32 requestId if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) goto cleanup; - sub = findSubscription(client, request->subscriptionId); + sub = findSubscriptionById(client, request->subscriptionId); if(!sub) { UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT, "No internal representation of subscription %" PRIu32, @@ -864,7 +900,7 @@ UA_Client_MonitoredItems_delete(UA_Client *client, UA_LOCK(&client->clientMutex); /* Find the internal subscription representation */ - UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId); + UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId); if(!sub) { UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT, "No internal representation of subscription %" PRIu32, @@ -962,7 +998,7 @@ UA_Client_MonitoredItems_modify(UA_Client *client, UA_ModifyMonitoredItemsResponse_init(&response); UA_LOCK(&client->clientMutex); - UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId); + UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId); if(!sub) { UA_UNLOCK(&client->clientMutex); response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; @@ -988,7 +1024,7 @@ UA_Client_MonitoredItems_modify_async(UA_Client *client, UA_ClientAsyncServiceCallback callback, void *userdata, UA_UInt32 *requestId) { UA_LOCK(&client->clientMutex); - UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId); + UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId); if(!sub) { UA_UNLOCK(&client->clientMutex); return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; @@ -1007,6 +1043,70 @@ UA_Client_MonitoredItems_modify_async(UA_Client *client, return statusCode; } +static void * +ua_MonitoredItem_findByID(void *data, UA_Client_MonitoredItem *mon) { + UA_UInt32 monitorId = *(UA_UInt32*)data; + if (monitorId && (mon->monitoredItemId == monitorId)) { + return mon; + } + return NULL; +} + +static UA_Client_MonitoredItem +*findMonitoredItemById(UA_Client_Subscription *sub, UA_UInt32 monitoredItemId) +{ + return (UA_Client_MonitoredItem *) + ZIP_ITER(MonitorItemsTree, &sub->monitoredItems, ua_MonitoredItem_findByID, &monitoredItemId); +} + +UA_StatusCode +UA_Client_MonitoredItem_getContext(UA_Client *client, UA_UInt32 subscriptionId, UA_UInt32 monitoredItemId, void **monContext) +{ + if (!client || !monContext) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + *monContext = NULL; + + UA_LOCK(&client->clientMutex); + UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId); + if (!sub) { + UA_UNLOCK(&client->clientMutex); + return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + } + + UA_StatusCode status = UA_STATUSCODE_BADMONITOREDITEMIDINVALID; + UA_Client_MonitoredItem *monItem = findMonitoredItemById(sub, monitoredItemId); + if (monItem) { + *monContext = monItem->context; + status = UA_STATUSCODE_GOOD; + } + UA_UNLOCK(&client->clientMutex); + return status; +} + +UA_StatusCode +UA_Client_MonitoredItem_setContext(UA_Client *client, UA_UInt32 subscriptionId, UA_UInt32 monitoredItemId, void *monContext) +{ + if (!client) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + UA_LOCK(&client->clientMutex); + UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId); + if (!sub) { + UA_UNLOCK(&client->clientMutex); + return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + } + + UA_StatusCode status = UA_STATUSCODE_BADMONITOREDITEMIDINVALID; + UA_Client_MonitoredItem *monItem = findMonitoredItemById(sub, monitoredItemId); + if (monItem) { + monItem->context = monContext; + status = UA_STATUSCODE_GOOD; + } + UA_UNLOCK(&client->clientMutex); + return status; +} + /*************************************/ /* Async Processing of Notifications */ /*************************************/ @@ -1208,7 +1308,7 @@ __Client_Subscriptions_processPublishResponse(UA_Client *client, UA_PublishReque { UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT, "Received BadNoSubscription, delete internal information about subscription"); - UA_Client_Subscription *sub = findSubscription(client, response->subscriptionId); + UA_Client_Subscription *sub = findSubscriptionById(client, response->subscriptionId); if(sub != NULL) __Client_Subscription_deleteInternal(client, sub); return; @@ -1219,7 +1319,7 @@ __Client_Subscriptions_processPublishResponse(UA_Client *client, UA_PublishReque return; } - UA_Client_Subscription *sub = findSubscription(client, response->subscriptionId); + UA_Client_Subscription *sub = findSubscriptionById(client, response->subscriptionId); if(!sub) { response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT, diff --git a/src/pubsub/ua_pubsub_dataset.c b/src/pubsub/ua_pubsub_dataset.c index cdfebcaf52e..ebb1a1e449f 100644 --- a/src/pubsub/ua_pubsub_dataset.c +++ b/src/pubsub/ua_pubsub_dataset.c @@ -456,7 +456,7 @@ UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src, } UA_DataSetField * -UA_DataSetField_find(UA_PubSubManager *psm, UA_NodeId id) { +UA_DataSetField_find(UA_PubSubManager *psm, const UA_NodeId id) { if(!psm) return NULL; UA_PublishedDataSet *tmpPDS;