fix(server): name session and subscription diagnostics in ns=1 (Part 3, 8.3)

The server defines these names, so they don't belong to namespace 0. The
children keep the ns=0 BrowseNames of their types (Part 3, 6.4.1).
This commit is contained in:
Andreas Ebner
2026-10-15 08:07:33 +02:00
committed by Andreas Ebner
parent 447957ee4e
commit 3350689aed
3 changed files with 59 additions and 3 deletions
+8
View File
@@ -3,6 +3,14 @@ refactorings and bug fixes are not reported here.
# Development
### Session and subscription diagnostics are named in the server namespace
The per-session objects below `SessionsDiagnosticsSummary` and the
per-subscription variables below the `SubscriptionDiagnosticsArray` variables
have the BrowseName `1:<SessionName>` and `1:<SubscriptionId>` instead of
namespace 0. Their children keep the namespace 0 BrowseNames of their types.
Browse paths to these nodes have to use namespace 1.
### Blocking and asynchronous server shutdown
`UA_Server_run_shutdown` now waits for shutdown to complete even with an external
+2 -2
View File
@@ -206,7 +206,7 @@ createSubscriptionObject(UA_Server *server, UA_Session *session,
var_attr.displayName.text = UA_STRING(subIdStr);
var_attr.dataType = UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE].typeId;
UA_NodeId refId = UA_NS0ID(HASCOMPONENT);
UA_QualifiedName browseName = UA_QUALIFIEDNAME(0, subIdStr);
UA_QualifiedName browseName = UA_QUALIFIEDNAME(1, subIdStr);
UA_NodeId typeId = UA_NS0ID(SUBSCRIPTIONDIAGNOSTICSTYPE);
UA_CallbackValueSource subDiagSource = {readSubscriptionDiagnostics, NULL};
@@ -510,7 +510,7 @@ createSessionObject(UA_Server *server, UA_Session *session) {
object_attr.displayName.text = session->sessionName;
UA_NodeId parentId = UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY);
UA_NodeId refId = UA_NS0ID(HASCOMPONENT);
UA_QualifiedName browseName = UA_QUALIFIEDNAME(0, "");
UA_QualifiedName browseName = UA_QUALIFIEDNAME(1, "");
browseName.name = session->sessionName; /* shallow copy */
UA_NodeId typeId = UA_NS0ID(SESSIONDIAGNOSTICSOBJECTTYPE);
UA_StatusCode res = addNode(server, UA_NODECLASS_OBJECT, session->sessionId,
+49 -1
View File
@@ -670,6 +670,43 @@ START_TEST(session_diagnosticsMultipleSessions) {
UA_Client_delete(client2);
} END_TEST
#ifdef UA_ENABLE_DIAGNOSTICS
/* The server-defined session object uses the server namespace, the children
* keep the BrowseNames of their InstanceDeclarations (Part 3, 6.4.1) */
START_TEST(session_diagnostics_browseNames) {
UA_Client *client = UA_Client_newForUnitTest();
UA_StatusCode res = UA_Client_connect(client, "opc.tcp://localhost:4840");
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
UA_QualifiedName bn;
res = UA_Server_readBrowseName(server, client->sessionId, &bn);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert_uint_eq(bn.namespaceIndex, 1);
UA_BrowsePathResult bpr = UA_Server_browseSimplifiedBrowsePath(server,
UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY), 1, &bn);
ck_assert_uint_eq(bpr.statusCode, UA_STATUSCODE_GOOD);
ck_assert_uint_eq(bpr.targetsSize, 1);
ck_assert(UA_NodeId_equal(&bpr.targets[0].targetId.nodeId, &client->sessionId));
UA_BrowsePathResult_clear(&bpr);
UA_QualifiedName_clear(&bn);
char *children[3] = {"SessionDiagnostics", "SessionSecurityDiagnostics",
"SubscriptionDiagnosticsArray"};
for(size_t i = 0; i < 3; i++) {
UA_QualifiedName child = UA_QUALIFIEDNAME(0, children[i]);
bpr = UA_Server_browseSimplifiedBrowsePath(server, client->sessionId,
1, &child);
ck_assert_uint_eq(bpr.statusCode, UA_STATUSCODE_GOOD);
ck_assert_uint_eq(bpr.targetsSize, 1);
UA_BrowsePathResult_clear(&bpr);
}
UA_Client_disconnect(client);
UA_Client_delete(client);
} END_TEST
#endif /* UA_ENABLE_DIAGNOSTICS */
/* === Discovery tests (moved here for organization) === */
START_TEST(client_findServers) {
UA_Client *client = UA_Client_newForUnitTest();
@@ -1309,7 +1346,7 @@ START_TEST(subscription_diagnostic_entry_valueRank_scalar) {
ck_assert(written > 0);
ck_assert((size_t)written < sizeof(subIdStr));
UA_QualifiedName bp = UA_QUALIFIEDNAME(0, subIdStr);
UA_QualifiedName bp = UA_QUALIFIEDNAME(1, subIdStr);
UA_BrowsePathResult bpr = UA_Server_browseSimplifiedBrowsePath(
server,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY),
@@ -1322,6 +1359,14 @@ START_TEST(subscription_diagnostic_entry_valueRank_scalar) {
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert_int_eq(valueRank, UA_VALUERANK_SCALAR);
/* The children keep the ns=0 BrowseNames of the SubscriptionDiagnosticsType */
UA_QualifiedName child = UA_QUALIFIEDNAME(0, "SubscriptionId");
UA_BrowsePathResult cbpr = UA_Server_browseSimplifiedBrowsePath(
server, bpr.targets[0].targetId.nodeId, 1, &child);
ck_assert_uint_eq(cbpr.statusCode, UA_STATUSCODE_GOOD);
ck_assert_uint_eq(cbpr.targetsSize, 1);
UA_BrowsePathResult_clear(&cbpr);
UA_BrowsePathResult_clear(&bpr);
UA_Client_Subscriptions_deleteSingle(client, subId);
@@ -1446,6 +1491,9 @@ static Suite *testSuite_ns0Ext(void) {
TCase *tc_sessiondiag = tcase_create("SessionDiagnostics");
tcase_add_checked_fixture(tc_sessiondiag, setup, teardown);
tcase_add_test(tc_sessiondiag, session_diagnosticsMultipleSessions);
#ifdef UA_ENABLE_DIAGNOSTICS
tcase_add_test(tc_sessiondiag, session_diagnostics_browseNames);
#endif
#ifdef UA_ENABLE_SUBSCRIPTIONS
TCase *tc_subdiag = tcase_create("SubDiag");