Переглянути джерело

cosmetic improvements; increase the client timeout

Julius Pfrommer 9 роки тому
батько
коміт
ac07df68b6

+ 1 - 1
src/client/ua_client.c

@@ -9,7 +9,7 @@
 #include "ua_transport_generated_encoding_binary.h"
 
 const UA_EXPORT UA_ClientConfig UA_ClientConfig_standard =
-    { .timeout = 500 /* ms receive timout */, .secureChannelLifeTime = 30000,
+    { .timeout = 5000 /* ms receive timout */, .secureChannelLifeTime = 30000,
       .timeToRenewSecureChannel = 2000,
       {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
        .maxMessageSize = 65536, .maxChunkCount = 1}};

+ 29 - 37
src/server/ua_securechannel_manager.c

@@ -2,9 +2,9 @@
 #include "ua_session.h"
 #include "ua_statuscodes.h"
 
-UA_StatusCode UA_SecureChannelManager_init(UA_SecureChannelManager *cm,
-        size_t maxChannelCount, UA_UInt32 tokenLifetime,
-        UA_UInt32 startChannelId, UA_UInt32 startTokenId) {
+UA_StatusCode
+UA_SecureChannelManager_init(UA_SecureChannelManager *cm, size_t maxChannelCount, UA_UInt32 tokenLifetime,
+                             UA_UInt32 startChannelId, UA_UInt32 startTokenId) {
     LIST_INIT(&cm->channels);
     cm->lastChannelId = startChannelId;
     cm->lastTokenId = startTokenId;
@@ -16,8 +16,7 @@ UA_StatusCode UA_SecureChannelManager_init(UA_SecureChannelManager *cm,
 
 void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) {
     channel_list_entry *entry, *temp;
-    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp)
-    {
+    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp) {
         LIST_REMOVE(entry, pointers);
         UA_SecureChannel_deleteMembersCleanup(&entry->channel);
         UA_free(entry);
@@ -25,15 +24,13 @@ void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) {
 }
 
 /* remove channels that were not renewed or who have no connection attached */
-void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm,
-        UA_DateTime now) {
+void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm, UA_DateTime now) {
     channel_list_entry *entry, *temp;
-    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp)
-    {
-        UA_DateTime timeout = entry->channel.securityToken.createdAt
-                + ((UA_DateTime) entry->channel.securityToken.revisedLifetime
-                        * 10000);
-        if (timeout < now || !entry->channel.connection) {
+    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp) {
+        UA_DateTime timeout =
+            entry->channel.securityToken.createdAt +
+            ((UA_DateTime)entry->channel.securityToken.revisedLifetime * 10000);
+        if(timeout < now || !entry->channel.connection) {
             LIST_REMOVE(entry, pointers);
             UA_SecureChannel_deleteMembersCleanup(&entry->channel);
 #ifndef UA_MULTITHREADING
@@ -43,7 +40,7 @@ void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm,
                     &cm->currentChannelCount, -1);
 #endif
             UA_free(entry);
-        } else if (entry->channel.nextSecurityToken.tokenId > 0) {
+        } else if(entry->channel.nextSecurityToken.tokenId > 0) {
             UA_SecureChannel_revolveTokens(&entry->channel);
         }
     }
@@ -58,7 +55,7 @@ UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
     if(cm->currentChannelCount >= cm->maxChannelCount)
         return UA_STATUSCODE_BADOUTOFMEMORY;
     channel_list_entry *entry = UA_malloc(sizeof(channel_list_entry));
-    if (!entry)
+    if(!entry)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 #ifndef UA_MULTITHREADING
     cm->currentChannelCount++;
@@ -78,7 +75,7 @@ UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
             (request->requestedLifetime > cm->maxChannelLifetime) ?
                     cm->maxChannelLifetime : request->requestedLifetime;
     /* pragmatic workaround to get clients requesting lifetime of 0 working */
-    if (entry->channel.securityToken.revisedLifetime == 0)
+    if(entry->channel.securityToken.revisedLifetime == 0)
         entry->channel.securityToken.revisedLifetime = cm->maxChannelLifetime;
 
     UA_ByteString_copy(&request->clientNonce, &entry->channel.clientNonce);
@@ -95,15 +92,16 @@ UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
     return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode UA_SecureChannelManager_renew(UA_SecureChannelManager *cm,
-        UA_Connection *conn, const UA_OpenSecureChannelRequest *request,
-        UA_OpenSecureChannelResponse *response) {
+UA_StatusCode
+UA_SecureChannelManager_renew(UA_SecureChannelManager *cm, UA_Connection *conn,
+                              const UA_OpenSecureChannelRequest *request,
+                              UA_OpenSecureChannelResponse *response) {
     UA_SecureChannel *channel = conn->channel;
-    if (!channel)
+    if(!channel)
         return UA_STATUSCODE_BADINTERNALERROR;
 
     /* if no security token is already issued */
-    if (channel->nextSecurityToken.tokenId == 0) {
+    if(channel->nextSecurityToken.tokenId == 0) {
         channel->nextSecurityToken.channelId = channel->securityToken.channelId;
         //FIXME: UaExpert seems not to use the new tokenid
         channel->nextSecurityToken.tokenId = cm->lastTokenId++;
@@ -114,45 +112,39 @@ UA_StatusCode UA_SecureChannelManager_renew(UA_SecureChannelManager *cm,
                         cm->maxChannelLifetime : request->requestedLifetime;
 
         /* pragmatic workaround to get clients requesting lifetime of 0 working */
-        if (channel->nextSecurityToken.revisedLifetime == 0)
+        if(channel->nextSecurityToken.revisedLifetime == 0)
             channel->nextSecurityToken.revisedLifetime = cm->maxChannelLifetime;
     }
 
-    if (channel->clientNonce.data)
+    if(channel->clientNonce.data)
         UA_ByteString_deleteMembers(&channel->clientNonce);
 
     UA_ByteString_copy(&request->clientNonce, &channel->clientNonce);
     UA_ByteString_copy(&channel->serverNonce, &response->serverNonce);
-    UA_ChannelSecurityToken_copy(&channel->nextSecurityToken,
-            &response->securityToken);
+    UA_ChannelSecurityToken_copy(&channel->nextSecurityToken, &response->securityToken);
     return UA_STATUSCODE_GOOD;
 }
 
-UA_SecureChannel *
-UA_SecureChannelManager_get(UA_SecureChannelManager *cm, UA_UInt32 channelId) {
+UA_SecureChannel * UA_SecureChannelManager_get(UA_SecureChannelManager *cm, UA_UInt32 channelId) {
     channel_list_entry *entry;
-    LIST_FOREACH(entry, &cm->channels, pointers)
-    {
-        if (entry->channel.securityToken.channelId == channelId)
+    LIST_FOREACH(entry, &cm->channels, pointers) {
+        if(entry->channel.securityToken.channelId == channelId)
             return &entry->channel;
     }
     return NULL;
 }
 
-UA_StatusCode UA_SecureChannelManager_close(UA_SecureChannelManager *cm,
-        UA_UInt32 channelId) {
+UA_StatusCode UA_SecureChannelManager_close(UA_SecureChannelManager *cm, UA_UInt32 channelId) {
     channel_list_entry *entry;
-    LIST_FOREACH(entry, &cm->channels, pointers)
-    {
-        if (entry->channel.securityToken.channelId == channelId) {
+    LIST_FOREACH(entry, &cm->channels, pointers) {
+        if(entry->channel.securityToken.channelId == channelId) {
             LIST_REMOVE(entry, pointers);
             UA_SecureChannel_deleteMembersCleanup(&entry->channel);
             UA_free(entry);
 #ifndef UA_MULTITHREADING
             cm->currentChannelCount--;
 #else
-            cm->currentChannelCount = uatomic_add_return(
-                    &cm->currentChannelCount, -1);
+            cm->currentChannelCount = uatomic_add_return(&cm->currentChannelCount, -1);
 #endif
             return UA_STATUSCODE_GOOD;
         }

+ 54 - 50
src/server/ua_services_nodemanagement.c

@@ -586,7 +586,8 @@ UA_StatusCode UA_EXPORT
 UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                                     const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                     const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                                    const UA_VariableAttributes attr, const UA_DataSource dataSource, UA_NodeId *outNewNodeId) {
+                                    const UA_VariableAttributes attr, const UA_DataSource dataSource,
+                                    UA_NodeId *outNewNodeId) {
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
 
@@ -684,47 +685,47 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 
     UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
                               &item.referenceTypeId, &result);
-    if(result.statusCode != UA_STATUSCODE_GOOD)
+    if(result.statusCode != UA_STATUSCODE_GOOD) {
         UA_MethodNode_delete(node);
+        return result.statusCode;
+    }
     
-    if(result.statusCode == UA_STATUSCODE_GOOD && method != NULL) {
-        UA_ExpandedNodeId parent;
-        UA_ExpandedNodeId_init(&parent);
-        parent.nodeId = result.addedNodeId;
+    UA_ExpandedNodeId parent;
+    UA_ExpandedNodeId_init(&parent);
+    parent.nodeId = result.addedNodeId;
     
-        /* create InputArguments */
-        UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
-        inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-        inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
-        inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-        inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-        inputArgumentsVariableNode->valueRank = 1;
-        UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
-                                inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-        UA_AddNodesResult inputAddRes;
-        const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
-        UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
-                                  &parent.nodeId, &hasproperty, &inputAddRes);
-        // todo: check if adding succeeded
-        UA_AddNodesResult_deleteMembers(&inputAddRes);
-
-        /* create OutputArguments */
-        UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
-        outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-        outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
-        outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-        outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-        outputArgumentsVariableNode->valueRank = 1;
-        UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
-                                outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-        UA_AddNodesResult outputAddRes;
-        UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
-                                  &parent.nodeId, &hasproperty, &outputAddRes);
-        // todo: check if adding succeeded
-        UA_AddNodesResult_deleteMembers(&outputAddRes);
-    }
-
-    if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
+    /* create InputArguments */
+    UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
+    inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+    inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
+    inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+    inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+    inputArgumentsVariableNode->valueRank = 1;
+    UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
+                            inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+    UA_AddNodesResult inputAddRes;
+    const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
+    UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
+                              &parent.nodeId, &hasproperty, &inputAddRes);
+    // todo: check if adding succeeded
+    UA_AddNodesResult_deleteMembers(&inputAddRes);
+
+    /* create OutputArguments */
+    UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
+    outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+    outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
+    outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+    outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+    outputArgumentsVariableNode->valueRank = 1;
+    UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
+                            outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+    UA_AddNodesResult outputAddRes;
+    UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
+                              &parent.nodeId, &hasproperty, &outputAddRes);
+    // todo: check if adding succeeded
+    UA_AddNodesResult_deleteMembers(&outputAddRes);
+
+    if(outNewNodeId)
         *outNewNodeId = result.addedNodeId;
     else
         UA_AddNodesResult_deleteMembers(&result);
@@ -756,8 +757,8 @@ addOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node, const
 	return retval;
 }
 
-UA_StatusCode Service_AddReferences_single(UA_Server *server, UA_Session *session,
-                                           const UA_AddReferencesItem *item) {
+UA_StatusCode
+Service_AddReferences_single(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item) {
     if(item->targetServerUri.length > 0)
         return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
 
@@ -836,8 +837,9 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 
 // TODO: Check consistency constraints, remove the references.
 
-UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                                         UA_Boolean deleteReferences) {
+UA_StatusCode
+Service_DeleteNodes_single(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
+                           UA_Boolean deleteReferences) {
     UA_MT_CONST UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
@@ -926,6 +928,7 @@ deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
         node->references[i] = node->references[node->referencesSize-1];
         node->referencesSize--;
         edited = UA_TRUE;
+        break;
     }
     if(!edited)
         return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED;
@@ -936,9 +939,10 @@ deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
 }
 
 UA_StatusCode
-Service_DeleteReferences_single(UA_Server *server, UA_Session *session, const UA_DeleteReferencesItem *item) {
+Service_DeleteReferences_single(UA_Server *server, UA_Session *session,
+                                const UA_DeleteReferencesItem *item) {
     UA_StatusCode retval = UA_Server_editNode(server, session, &item->sourceNodeId,
-                                       (UA_EditNodeCallback)deleteOneWayReference, item);
+                                              (UA_EditNodeCallback)deleteOneWayReference, item);
     if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
         return retval;
     UA_DeleteReferencesItem secondItem;
@@ -950,9 +954,9 @@ Service_DeleteReferences_single(UA_Server *server, UA_Session *session, const UA
                               (UA_EditNodeCallback)deleteOneWayReference, &secondItem);
 }
 
-void Service_DeleteReferences(UA_Server *server, UA_Session *session,
-                              const UA_DeleteReferencesRequest *request,
-                              UA_DeleteReferencesResponse *response) {
+void
+Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_DeleteReferencesRequest *request,
+                         UA_DeleteReferencesResponse *response) {
     if(request->referencesToDeleteSize <= 0) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         return;
@@ -964,6 +968,6 @@ void Service_DeleteReferences(UA_Server *server, UA_Session *session,
     }
     response->resultsSize = request->referencesToDeleteSize;
     for(size_t i = 0; i < request->referencesToDeleteSize; i++)
-        response->results[i] = Service_DeleteReferences_single(server, session,
-                                                               &request->referencesToDelete[i]);
+        response->results[i] =
+            Service_DeleteReferences_single(server, session, &request->referencesToDelete[i]);
 }

+ 22 - 33
src/server/ua_services_view.c

@@ -9,7 +9,6 @@ fillReferenceDescription(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode
                          UA_UInt32 mask, UA_ReferenceDescription *descr) {
     UA_ReferenceDescription_init(descr);
     UA_StatusCode retval = UA_NodeId_copy(&curr->nodeId, &descr->nodeId.nodeId);
-
     if(mask & UA_BROWSERESULTMASK_REFERENCETYPEID)
         retval |= UA_NodeId_copy(&ref->referenceTypeId, &descr->referenceTypeId);
     if(mask & UA_BROWSERESULTMASK_ISFORWARD)
@@ -31,8 +30,6 @@ fillReferenceDescription(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode
             }
         }
     }
-    if(retval != UA_STATUSCODE_GOOD)
-        UA_ReferenceDescription_deleteMembers(descr);
     return retval;
 }
 
@@ -215,12 +212,9 @@ static void removeCp(struct ContinuationPointEntry *cp, UA_Session* session) {
  */
 void
 Service_Browse_single(UA_Server *server, UA_Session *session, struct ContinuationPointEntry *cp,
-                      const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result) {
-    UA_UInt32 continuationIndex = 0;
-    size_t referencesCount = 0;
-    size_t referencesIndex = 0;
-    
+                      const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result) { 
     /* set the browsedescription if a cp is given */
+    UA_UInt32 continuationIndex = 0;
     if(cp) {
         descr = &cp->browseDescription;
         maxrefs = cp->maxReferences;
@@ -247,11 +241,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
                 return;
         } else {
             const UA_Node *rootRef = UA_NodeStore_get(server->nodestore, &descr->referenceTypeId);
-            if(!rootRef) {
-                result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
-                return;
-            }
-            if(rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE) {
+            if(!rootRef || rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE) {
                 result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
                 return;
             }
@@ -283,9 +273,9 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
         real_maxrefs = node->referencesSize;
     if(node->referencesSize <= 0)
         real_maxrefs = 0;
-    else if(real_maxrefs > (UA_UInt32)node->referencesSize)
+    else if(real_maxrefs > node->referencesSize)
         real_maxrefs = node->referencesSize;
-    result->references = UA_malloc(sizeof(UA_ReferenceDescription) * real_maxrefs);
+    result->references = UA_Array_new(real_maxrefs, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]);
     if(!result->references) {
         result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         goto cleanup;
@@ -294,6 +284,9 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
     /* loop over the node's references */
     size_t skipped = 0;
     UA_Boolean isExternal = UA_FALSE;
+    size_t referencesCount = 0;
+    size_t referencesIndex = 0;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     for(; referencesIndex < node->referencesSize && referencesCount < real_maxrefs; referencesIndex++) {
     	isExternal = UA_FALSE;
     	const UA_Node *current =
@@ -301,31 +294,20 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
                                relevant_refs, relevant_refs_size, &isExternal);
         if(!current)
             continue;
+
         if(skipped < continuationIndex) {
-#ifdef UA_EXTERNAL_NAMESPACES
-        	if(isExternal == UA_TRUE)
-        		/* relevant_node returns a node malloced with UA_ObjectNode_new
-                   if it is external (there is no UA_Node_new function) */
-        		UA_ObjectNode_delete((UA_ObjectNode*)(uintptr_t)current);
-#endif
             skipped++;
-            continue;
+        } else {
+            retval |= fillReferenceDescription(server->nodestore, current, &node->references[referencesIndex],
+                                               descr->resultMask, &result->references[referencesCount]);
+            referencesCount++;
         }
-        UA_StatusCode retval =
-            fillReferenceDescription(server->nodestore, current, &node->references[referencesIndex],
-                                     descr->resultMask, &result->references[referencesCount]);
 #ifdef UA_EXTERNAL_NAMESPACES
+        /* relevant_node returns a node malloced with UA_ObjectNode_new
+           if it is external (there is no UA_Node_new function) */
         if(isExternal == UA_TRUE)
         	UA_ObjectNode_delete((UA_ObjectNode*)(uintptr_t)current);
 #endif
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_Array_delete(result->references, referencesCount, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]);
-            result->references = NULL;
-            result->referencesSize = 0;
-            result->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
-            goto cleanup;
-        }
-        referencesCount++;
     }
 
     result->referencesSize = referencesCount;
@@ -334,6 +316,13 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
         result->references = NULL;
     }
 
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Array_delete(result->references, result->referencesSize, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]);
+        result->references = NULL;
+        result->referencesSize = 0;
+        result->statusCode = retval;
+    }
+
     cleanup:
     if(!all_refs && descr->includeSubtypes)
         UA_Array_delete(relevant_refs, relevant_refs_size, &UA_TYPES[UA_TYPES_NODEID]);