open62541 / open62541

Open source implementation of OPC UA (OPC Unified Architecture) aka IEC 62541 licensed under Mozilla Public License v2.0
http://open62541.org
Mozilla Public License 2.0
2.59k stars 1.24k forks source link

Node destructors not called. #1655

Open the-om opened 6 years ago

the-om commented 6 years ago

Description

I was trying to attach a node-type destructor to my server variables. However I noticed that the destructor only gets called when variable nodes are explicitly removed via UA_server_deleteNode. Destructors are not called when the server is just stopped and shut down. Is there a possibility to have destructors called without having to keep track of variables myself?

Background Information / Reproduction Steps

#include <signal.h>
#include <cstdio>
#include <open62541/open62541.h>

UA_Boolean running = true;
UA_Logger logger = UA_Log_Stdout;
UA_NodeId custom_vartype_id = UA_NODEID_NULL;

void makeCustomVarType(UA_Server* server) {
    UA_VariableTypeAttributes vartype_attribs = UA_VariableTypeAttributes_default;
    UA_StatusCode status;
    status = UA_Server_addVariableTypeNode(
        server,
        UA_NODEID_NUMERIC(1, 0),                           // requested id
        UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE),   // parent
        UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),         // reference type
        UA_QUALIFIEDNAME(1, (char*)"Custom VariableType"), // browse name
        UA_NODEID_NULL,                                    // type definition
        vartype_attribs,
        NULL,
        &custom_vartype_id
    );
    UA_VariableTypeAttributes_deleteMembers(&vartype_attribs);
    UA_NodeTypeLifecycle const_dest = { 0 };
    const_dest.constructor = [](UA_Server*, const UA_NodeId*, void*, const UA_NodeId*, void*, const UA_NodeId*, void**)
        -> UA_StatusCode
    {
        std::puts("!construct!");
        return UA_STATUSCODE_GOOD;
    };
    const_dest.destructor = [](UA_Server*, const UA_NodeId*, void*, const UA_NodeId*, void*, const UA_NodeId*, void**) {
        std::puts("!destruct!");
    };
    status = UA_Server_setNodeTypeLifecycle(server, custom_vartype_id, const_dest);
}

void addIntVariable(UA_Server* server) {
    // add a variable node to the adresspace
    UA_VariableAttributes attr = UA_VariableAttributes_default;
    attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", "the answer");
    attr.description = UA_LOCALIZEDTEXT_ALLOC("en-US", "the answer");
    attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
    UA_Int32 myInteger = 42;
    UA_Variant_setScalarCopy(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;

    UA_StatusCode status = UA_Server_addVariableNode(
        server,
        UA_NODEID_NUMERIC(1, 0),
        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), // parent
        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),     // reference type
        UA_QUALIFIEDNAME(1, (char*)"the answer"),     // browse name
        custom_vartype_id,                            // type definition
        attr,
        NULL,
        NULL
    );

    /* allocations on the heap need to be freed */
    UA_VariableAttributes_deleteMembers(&attr);
}

static void stopHandler(int sign) {
    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
    running = false;
}

int main() {
    signal(SIGINT, stopHandler);
    signal(SIGTERM, stopHandler);

    UA_ServerConfig *config = UA_ServerConfig_new_minimal(5731, nullptr);
    UA_Server *server = UA_Server_new(config);

    makeCustomVarType(server);
    addIntVariable(server);

    UA_StatusCode retval = UA_Server_run(server, &running);
    UA_Server_delete(server);
    UA_ServerConfig_delete(config);
    return (int)retval;
}

Checklist

Please provide the following information:

jpfr commented 6 years ago

The fix was started in #1656 and is already usable.

the-om commented 6 years ago

Seems to work! Thank you for the quick fix!

gusentom commented 2 years ago

seems to work not, I have tried to implement a node type destructor and it will not be called - is there a working example available?

I took a look into ua_services_nodemanagement.c and intrumented the following method

static void deconstructNodeSet(UA_Server *server, UA_Session *session, UA_ReferenceTypeSet *hierarchRefsSet, RefTree *refTree) {

it looks like there is no lifecycle information available, the pointers are NULL.

I am working with the actual origin/master