Browse Source

return the added node id only when requested

Julius Pfrommer 9 years ago
parent
commit
1811544b2d

+ 18 - 18
examples/server.c

@@ -233,19 +233,19 @@ int main(int argc, char** argv) {
     v_attr.description = UA_LOCALIZEDTEXT("en_US","current time");
     v_attr.displayName = UA_LOCALIZEDTEXT("en_US","current time");
     const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time");
-    UA_AddNodesResult res;
-    res = UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL,
-                                              UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                              UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), dateName,
-                                              UA_NODEID_NULL, v_attr, dateDataSource);
+    UA_NodeId dataSourceId;
+    UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL,
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), dateName,
+                                        UA_NODEID_NULL, v_attr, dateDataSource, &dataSourceId);
 
     // Get and reattach the datasource
     UA_DataSource dataSourceCopy;
-    UA_Server_getNodeAttribute_value_dataSource(server, res.addedNodeId, &dataSourceCopy);
+    UA_Server_getNodeAttribute_value_dataSource(server, dataSourceId, &dataSourceCopy);
     if (dataSourceCopy.read != dateDataSource.read)
         UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND, "The returned dataSource is not the same as we set?");
     else
-        UA_Server_setNodeAttribute_value_dataSource(server, res.addedNodeId, dataSourceCopy);
+        UA_Server_setNodeAttribute_value_dataSource(server, dataSourceId, dataSourceCopy);
 #ifndef _WIN32
     /* cpu temperature monitoring for linux machines */
     if((temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))) {
@@ -259,7 +259,7 @@ int main(int argc, char** argv) {
         UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL,
                                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), tempName,
-                                            UA_NODEID_NULL, v_attr, temperatureDataSource);
+                                            UA_NODEID_NULL, v_attr, temperatureDataSource, NULL);
     }
 
     /* LED control for rpi */
@@ -285,7 +285,7 @@ int main(int argc, char** argv) {
             UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL,
                                                 UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                                 UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), statusName,
-                                                UA_NODEID_NULL, v_attr, ledStatusDataSource);
+                                                UA_NODEID_NULL, v_attr, ledStatusDataSource, NULL);
         } else
             UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND,
                            "[Raspberry Pi] LED file exist, but is not accessible (try to run server with sudo)");
@@ -304,7 +304,7 @@ int main(int argc, char** argv) {
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                              myIntegerName, UA_NODEID_NULL, myVar);
+                              myIntegerName, UA_NODEID_NULL, myVar, NULL);
     UA_Variant_deleteMembers(&myVar.value);
 
     /**************/
@@ -319,7 +319,7 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Demo"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
 
 #define SCALARID 50001
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Scalar");
@@ -327,7 +327,7 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Scalar"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
 
 #define ARRAYID 50002
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Array");
@@ -335,14 +335,14 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Array"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
 
 #define MATRIXID 50003
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Matrix");
     object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Matrix");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Matrix"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
 
     UA_UInt32 id = 51000; // running id in namespace 0
     for(UA_UInt32 type = 0; UA_IS_BUILTIN(type); type++) {
@@ -362,7 +362,7 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, SCALARID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
         UA_Variant_deleteMembers(&attr.value);
 
         /* add an array node for every built-in type */
@@ -371,7 +371,7 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, ARRAYID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
         UA_Variant_deleteMembers(&attr.value);
 
         /* add an matrix node for every built-in type */
@@ -386,7 +386,7 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, MATRIXID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
         UA_Variant_deleteMembers(&attr.value);
     }
 
@@ -421,7 +421,7 @@ int main(int argc, char** argv) {
                             UA_QUALIFIEDNAME(1,"ping"), addmethodattributes,
                             &getMonitoredItems, // Call this method
                             (void *) server,    // Pass our server pointer as a handle to the method
-                            1, &inputArguments, 1, &outputArguments);
+                            1, &inputArguments, 1, &outputArguments, NULL);
 #endif
    
     // Example for iterating over all nodes referenced by "Objects":

+ 1 - 1
examples/server_datasource.c

@@ -66,7 +66,7 @@ int main(int argc, char** argv) {
     UA_Server_addDataSourceVariableNode(server, myIntegerNodeId,
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                        myIntegerName, UA_NODEID_NULL, attr, dateDataSource);
+                                        myIntegerName, UA_NODEID_NULL, attr, dateDataSource, NULL);
 
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
     UA_Server_delete(server);

+ 2 - 2
examples/server_method.c

@@ -88,7 +88,7 @@ int main(int argc, char** argv) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                             UA_QUALIFIEDNAME(1, "hello world"), 
                             helloAttr, &helloWorldMethod, NULL,
-                            1, &inputArguments, 1, &outputArguments);
+                            1, &inputArguments, 1, &outputArguments, NULL);
 
     //END OF EXAMPLE 1
 
@@ -129,7 +129,7 @@ int main(int argc, char** argv) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), 
                             UA_QUALIFIEDNAME(1, "IncInt32ArrayValues"),
                             incAttr, &IncInt32ArrayValuesMethod, NULL,
-                            1, &inputArguments, 1, &outputArguments);
+                            1, &inputArguments, 1, &outputArguments, NULL);
     //END OF EXAMPLE 2
 
     /* start server */

+ 3 - 4
examples/server_udp.c

@@ -40,10 +40,9 @@ int main(int argc, char** argv) {
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_AddNodesResult res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
-                                                      parentReferenceNodeId, myIntegerName,
-                                                      UA_NODEID_NULL, attr);
-    UA_AddNodesResult_deleteMembers(&res);
+    UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                              parentReferenceNodeId, myIntegerName,
+                              UA_NODEID_NULL, attr, NULL);
 
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
 	UA_Server_delete(server);

+ 3 - 4
examples/server_variable.c

@@ -54,10 +54,9 @@ int main(int argc, char** argv) {
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_AddNodesResult res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
-                                                      parentReferenceNodeId, myIntegerName,
-                                                      UA_NODEID_NULL, attr);
-    UA_AddNodesResult_deleteMembers(&res);
+    UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                              parentReferenceNodeId, myIntegerName,
+                              UA_NODEID_NULL, attr, NULL);
 
     UA_ValueCallback callback = {(void*)7, onRead, onWrite};
     UA_Server_setAttribute_value_callback(server, myIntegerNodeId, callback);

+ 39 - 36
include/ua_server.h

@@ -215,90 +215,93 @@ UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, const UA_Nod
                        const UA_ExpandedNodeId targetId, UA_Boolean isForward);
 
 /* Don't use this function. There are typed versions as inline functions. */
-UA_AddNodesResult UA_EXPORT
+UA_StatusCode UA_EXPORT
 UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_NodeId requestedNewNodeId,
                   const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                   const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                  const UA_NodeAttributes *attr, const UA_DataType *attributeType);
+                  const UA_NodeAttributes *attr, const UA_DataType *attributeType, UA_NodeId *outNewNodeId);
 
-static UA_INLINE UA_AddNodesResult
+static UA_INLINE UA_StatusCode
 UA_Server_addVariableNode(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_VariableAttributes attr, UA_NodeId *outNewNodeId) {
     return UA_Server_addNode(server, UA_NODECLASS_VARIABLE, requestedNewNodeId, parentNodeId,
                              referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
-                             &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES]); }
+                             &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], outNewNodeId); }
 
-static UA_INLINE UA_AddNodesResult
+static UA_INLINE UA_StatusCode
 UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                              const UA_QualifiedName browseName, const UA_VariableTypeAttributes attr) {
+                              const UA_QualifiedName browseName, const UA_VariableTypeAttributes attr,
+                              UA_NodeId *outNewNodeId) {
     return UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE, requestedNewNodeId, parentNodeId,
-                             referenceTypeId, browseName, UA_NODEID_NULL,
-                             (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES]); }
+                             referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], outNewNodeId); }
 
-static UA_INLINE UA_AddNodesResult
+static UA_INLINE UA_StatusCode
 UA_Server_addObjectNode(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_ObjectAttributes attr) {
+                        const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId) {
     return UA_Server_addNode(server, UA_NODECLASS_OBJECT, requestedNewNodeId, parentNodeId,
                              referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
-                             &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES]); }
+                             &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId); }
 
-static UA_INLINE UA_AddNodesResult
+static UA_INLINE UA_StatusCode
 UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                             const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                            const UA_QualifiedName browseName, const UA_ObjectTypeAttributes attr) {
+                            const UA_QualifiedName browseName, const UA_ObjectTypeAttributes attr,
+                            UA_NodeId *outNewNodeId) {
     return UA_Server_addNode(server, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, parentNodeId,
-                             referenceTypeId, browseName, UA_NODEID_NULL,
-                             (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]); }
+                             referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], outNewNodeId); }
 
-static UA_INLINE UA_AddNodesResult
+static UA_INLINE UA_StatusCode
 UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                       const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                      const UA_QualifiedName browseName, const UA_ViewAttributes attr) {
+                      const UA_QualifiedName browseName, const UA_ViewAttributes attr,
+                      UA_NodeId *outNewNodeId) {
     return UA_Server_addNode(server, UA_NODECLASS_VIEW, requestedNewNodeId, parentNodeId,
-                             referenceTypeId, browseName, UA_NODEID_NULL,
-                             (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VIEWATTRIBUTES]); }
+                             referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId); }
 
-static UA_INLINE UA_AddNodesResult
+static UA_INLINE UA_StatusCode
 UA_Server_addReferenceTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                                const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                               const UA_QualifiedName browseName, const UA_ReferenceTypeAttributes attr) {
+                               const UA_QualifiedName browseName, const UA_ReferenceTypeAttributes attr,
+                               UA_NodeId *outNewNodeId) {
     return UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId, parentNodeId,
-                             referenceTypeId, browseName, UA_NODEID_NULL,
-                             (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]); }
+                             referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], outNewNodeId); }
 
-static UA_INLINE UA_AddNodesResult
+static UA_INLINE UA_StatusCode
 UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                          const UA_QualifiedName browseName, const UA_DataTypeAttributes attr) {
+                          const UA_QualifiedName browseName, const UA_DataTypeAttributes attr,
+                          UA_NodeId *outNewNodeId) {
     return UA_Server_addNode(server, UA_NODECLASS_DATATYPE, requestedNewNodeId, parentNodeId,
-                             referenceTypeId, browseName, UA_NODEID_NULL,
-                             (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]); }
+                             referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], outNewNodeId); }
 
-UA_AddNodesResult UA_EXPORT
+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_StatusCode UA_EXPORT
-UA_Server_addMonodirectionalReference(UA_Server *server, UA_NodeId sourceNodeId, UA_NodeId targetNodeId,
-                                      UA_NodeId referenceTypeId, UA_Boolean isforward);
+                                    const UA_VariableAttributes attr, const UA_DataSource dataSource,
+                                    UA_NodeId *outNewNodeId);
 
 #ifdef ENABLE_METHODCALLS
 typedef UA_StatusCode (*UA_MethodCallback)(const UA_NodeId objectId, const UA_Variant *input,
                                            UA_Variant *output, void *handle);
-UA_AddNodesResult UA_EXPORT
+UA_StatusCode UA_EXPORT
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName, const UA_MethodAttributes attr,
                         UA_MethodCallback method, void *handle,
                         UA_Int32 inputArgumentsSize, const UA_Argument* inputArguments, 
-                        UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments);
+                        UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments,
+                        UA_NodeId *outNewNodeId);
 #endif
 
 UA_StatusCode UA_EXPORT UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId);

+ 7 - 3
src/server/ua_server.c

@@ -147,12 +147,12 @@ addNodeInternal(UA_Server *server, UA_Node *node, const UA_NodeId parentNodeId,
     return res;
 }
 
-UA_AddNodesResult
+UA_StatusCode
 UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
                   const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
                   const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                   const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
-                  const UA_DataType *attributeType) {
+                  const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
 
@@ -170,9 +170,13 @@ UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
     if(result.statusCode == UA_STATUSCODE_GOOD)
         Service_AddNodes_single(server, &adminSession, &item, attrCopy, &result);
 
+    if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
+        *outNewNodeId = result.addedNodeId;
+    else
+        UA_AddNodesResult_deleteMembers(&result);
     UA_AddNodesItem_deleteMembers(&item);
     UA_deleteMembers(attrCopy, attributeType);
-    return result;
+    return result.statusCode;
 }
 
 /*****************/

+ 57 - 56
src/server/ua_services_nodemanagement.c

@@ -573,11 +573,11 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
 /* Add Special Nodes (not possible over the wire) */
 /**************************************************/
 
-UA_AddNodesResult
+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) {
+                                    const UA_VariableAttributes attr, const UA_DataSource dataSource, UA_NodeId *outNewNodeId) {
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
 
@@ -595,15 +595,14 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
     if(result.statusCode != UA_STATUSCODE_GOOD) {
         UA_AddNodesItem_deleteMembers(&item);
         UA_VariableAttributes_deleteMembers(&attrCopy);
-        return result;
+        return result.statusCode;
     }
 
     UA_VariableNode *node = UA_VariableNode_new();
     if(!node) {
-        result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         UA_AddNodesItem_deleteMembers(&item);
         UA_VariableAttributes_deleteMembers(&attrCopy);
-        return result;
+        return UA_STATUSCODE_BADOUTOFMEMORY;
     }
 
     moveStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
@@ -622,17 +621,23 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
 
     if(result.statusCode != UA_STATUSCODE_GOOD)
         UA_VariableNode_delete(node);
-    return result;
+
+    if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
+        *outNewNodeId = result.addedNodeId;
+    else
+        UA_AddNodesResult_deleteMembers(&result);
+    return result.statusCode;
 }
 
 #ifdef ENABLE_METHODCALLS
-UA_AddNodesResult UA_EXPORT
+UA_StatusCode UA_EXPORT
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName, const UA_MethodAttributes attr,
                         UA_MethodCallback method, void *handle,
                         UA_Int32 inputArgumentsSize, const UA_Argument* inputArguments, 
-                        UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments) {
+                        UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments,
+                        UA_NodeId *outNewNodeId) {
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
     
@@ -649,7 +654,7 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
     if(result.statusCode != UA_STATUSCODE_GOOD) {
         UA_AddNodesItem_deleteMembers(&item);
         UA_MethodAttributes_deleteMembers(&attrCopy);
-        return result;
+        return result.statusCode;
     }
 
     UA_MethodNode *node = UA_MethodNode_new();
@@ -657,7 +662,7 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
         result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         UA_AddNodesItem_deleteMembers(&item);
         UA_MethodAttributes_deleteMembers(&attrCopy);
-        return result;
+        return result.statusCode;
     }
     
     moveStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
@@ -670,55 +675,51 @@ 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;
-    }
     
-    /* Only proceed with creating in/outputArguments if the method and both arguments are not
-     * UA_NULL; otherwise this is a pretty strong indicator that this node was generated,
-     * in which case these arguments will be created later and individually.
-     */
-    if(method == UA_NULL && inputArguments == UA_NULL && outputArguments == UA_NULL &&
-       inputArgumentsSize <= 0 && outputArgumentsSize <= 0)
-        return result;
-
-    UA_ExpandedNodeId parent;
-    UA_ExpandedNodeId_init(&parent);
-    parent.nodeId = result.addedNodeId;
+    if(result.statusCode == UA_STATUSCODE_GOOD && method != UA_NULL) {
+        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);
-
-    return result;
+        /* 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)
+        *outNewNodeId = result.addedNodeId;
+    else
+        UA_AddNodesResult_deleteMembers(&result);
+    return result.statusCode;
 }
 #endif
 

+ 5 - 6
tests/check_services_attributes.c

@@ -34,7 +34,7 @@ static UA_Server* makeTestSequence(void) {
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, vattr);
+                              UA_NODEID_NULL, vattr, NULL);
 
     /* ObjectNode */
     UA_ObjectAttributes obj_attr;
@@ -46,7 +46,7 @@ static UA_Server* makeTestSequence(void) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Demo"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE),
-                            obj_attr);
+                            obj_attr, NULL);
 
     /* ViewNode */
     UA_ViewAttributes view_attr;
@@ -56,7 +56,7 @@ static UA_Server* makeTestSequence(void) {
     UA_Server_addViewNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWNODE),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
-                          UA_QUALIFIEDNAME_ALLOC(0, "Viewtest"), view_attr);
+                          UA_QUALIFIEDNAME_ALLOC(0, "Viewtest"), view_attr, NULL);
 
 #ifdef ENABLE_METHODCALLS
 	/* MethodNode */
@@ -68,7 +68,7 @@ static UA_Server* makeTestSequence(void) {
                             UA_NODEID_NUMERIC(0, 3),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                             UA_QUALIFIEDNAME_ALLOC(0, "Methodtest"), ma,
-                            NULL, NULL, -1, NULL, -1, NULL);
+                            NULL, NULL, -1, NULL, -1, NULL, NULL);
 #endif
 
 	return server;
@@ -958,8 +958,7 @@ int main(void) {
 	Suite *s;
 	s = testSuite_services_attributes();
 	SRunner *sr = srunner_create(s);
-	srunner_set_log(sr, "test.log");
-	srunner_set_fork_status(sr, CK_NOFORK);
+	// srunner_set_fork_status(sr, CK_NOFORK);
 	srunner_run_all(sr, CK_NORMAL);
 
 	number_failed += srunner_ntests_failed(sr);

+ 3 - 5
tests/check_services_nodemanagement.c

@@ -31,11 +31,9 @@ START_TEST(AddVariableNode) {
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_AddNodesResult res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
-                                                      parentReferenceNodeId, myIntegerName,
-                                                      UA_NODEID_NULL, attr);
-    ck_assert_int_eq(UA_STATUSCODE_GOOD, res.statusCode);
-    UA_AddNodesResult_deleteMembers(&res);
+    UA_StatusCode res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
+                                                  myIntegerName, UA_NODEID_NULL, attr, NULL);
+    ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
     UA_Server_delete(server);
 } END_TEST
 

+ 2 - 3
tools/pyUANamespace/open62541_MacroHelper.py

@@ -126,11 +126,10 @@ class open62541_MacroHelper():
     else:
       code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(0, \"" + str(node.browseName()) + "\");")
 
-    code.append("UA_AddNodesResult res = UA_Server_add%sNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName" % nodetype)
+    code.append("UA_Server_add%sNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName" % nodetype)
     if nodetype in ["Object", "Variable"]:
       code.append("       , typeDefinition")
-    code.append("       , attr);")
-    code.append("UA_AddNodesResult_deleteMembers(&res);")
+    code.append("       , attr, NULL);")
       
     return code