$OpenBSD: patch-src_client_ua_client_highlevel_c,v 1.2 2021/08/13 15:30:13 bluhm Exp $

The user callback should always be called, also in case of an error.
https://github.com/open62541/open62541/pull/3691
Although this pull request was not merged, the new callback semantics
has been implemented during refactoring in AttributeReadCallback().
https://github.com/open62541/open62541/commit/9e193c3a893765db085ccc75e9d3929b6f7b8f82

https://github.com/open62541/open62541/commit/b172ae033adb5dd2aa6766b9cd6af8fc8c91453c

Index: src/client/ua_client_highlevel.c
--- src/client/ua_client_highlevel.c.orig
+++ src/client/ua_client_highlevel.c
@@ -786,18 +786,21 @@ void ValueAttributeRead(UA_Client *client, void *userd
         }
     }
 
-    /* Could not process, delete the callback anyway */
-    if(!done)
+    /* Could not process, run the callback anyway */
+    if(!done) {
         UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT,
                     "Cannot process the response to the async read "
                     "request %u", requestId);
+        cc->callback(client, userdata, requestId, NULL);
+    }
 
     LIST_REMOVE(cc, pointers);
     UA_free(cc);
 }
 
 /*Read Attributes*/
-UA_StatusCode __UA_Client_readAttribute_async(UA_Client *client,
+UA_StatusCode
+__UA_Client_readAttribute_async(UA_Client *client,
         const UA_NodeId *nodeId, UA_AttributeId attributeId,
         const UA_DataType *outDataType, UA_ClientAsyncServiceCallback callback,
         void *userdata, UA_UInt32 *reqId) {
@@ -810,20 +813,21 @@ UA_StatusCode __UA_Client_readAttribute_async(UA_Clien
     request.nodesToRead = &item;
     request.nodesToReadSize = 1;
 
-    __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_READREQUEST],
-                             ValueAttributeRead, &UA_TYPES[UA_TYPES_READRESPONSE],
-                             userdata, reqId);
-
     CustomCallback *cc = (CustomCallback*) UA_malloc(sizeof(CustomCallback));
     if (!cc)
         return UA_STATUSCODE_BADOUTOFMEMORY;
     cc->callback = callback;
-    cc->callbackId = *reqId;
 
     cc->attributeId = attributeId;
     cc->outDataType = outDataType;
 
+    __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_READREQUEST],
+                             ValueAttributeRead, &UA_TYPES[UA_TYPES_READRESPONSE],
+                             userdata, &cc->callbackId);
+
     LIST_INSERT_HEAD(&client->customCallbacks, cc, pointers);
+    if (reqId != NULL)
+        *reqId = cc->callbackId;
 
     return UA_STATUSCODE_GOOD;
 }
