fix(pubsub): defer group transport validation until server startup (#8583)

* fix(pubsub): defer group transport validation until server startup

* test(pubsub): add a writer group with a UDP address before server startup
This commit is contained in:
Niels Beier
2026-10-16 13:22:31 +02:00
committed by GitHub
parent 90effffe86
commit b6fc656edc
3 changed files with 62 additions and 0 deletions
+5
View File
@@ -1033,6 +1033,11 @@ UA_ReaderGroup_connectMQTT(UA_PubSubManager *psm, UA_ReaderGroup *rg,
return res;
}
/* A fresh ConnectionManager cannot perform the validation open before
* server startup. Defer it until the PubSubManager becomes operational. */
if(psm->drv.state != UA_LIFECYCLESTATE_STARTED)
return UA_STATUSCODE_GOOD;
/* Set up the connection parameters.
* TODO: Complete the MQTT parameters. */
UA_Boolean listen = true;
+10
View File
@@ -1474,6 +1474,11 @@ UA_WriterGroup_connectUDPUnicast(UA_PubSubManager *psm, UA_WriterGroup *wg,
return UA_STATUSCODE_BADINVALIDARGUMENT;
}
/* A fresh ConnectionManager cannot open even a validation-only
* connection. Defer the transport validation until server startup. */
if(psm->drv.state != UA_LIFECYCLESTATE_STARTED)
return UA_STATUSCODE_GOOD;
/* Set up the connection parameters */
UA_Boolean listen = false;
UA_KeyValuePair kvp[5];
@@ -1532,6 +1537,11 @@ UA_WriterGroup_connectMQTT(UA_PubSubManager *psm, UA_WriterGroup *wg,
return res;
}
/* See the UDP path above. A fresh ConnectionManager cannot perform the
* validation open, so defer it until server startup. */
if(psm->drv.state != UA_LIFECYCLESTATE_STARTED)
return UA_STATUSCODE_GOOD;
/* Set up the connection parameters.
* TODO: Complete the MQTT parameters. */
UA_Boolean listen = false;
+47
View File
@@ -181,6 +181,52 @@ START_TEST(Connection_EnableBeforeStartup_PausesAndRecovers) {
ck_assert_int_eq(connection->head.state, UA_PUBSUBSTATE_OPERATIONAL);
} END_TEST
/* A WriterGroup with its own UDP address can be added before the server and
* its ConnectionManagers are started. The transport validation is deferred
* until startup. */
START_TEST(WriterGroup_UdpAddressBeforeStartup_IsAccepted) {
addMinimalPubSubConnection();
UA_NetworkAddressUrlDataType addressUrl =
{UA_STRING_NULL, UA_STRING("opc.udp://127.0.0.1:4841/")};
UA_DatagramWriterGroupTransport2DataType transport;
UA_DatagramWriterGroupTransport2DataType_init(&transport);
UA_ExtensionObject_setValue(&transport.address, &addressUrl,
&UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
UA_UadpWriterGroupMessageDataType messageSettings;
UA_UadpWriterGroupMessageDataType_init(&messageSettings);
UA_WriterGroupConfig cfg;
memset(&cfg, 0, sizeof(UA_WriterGroupConfig));
cfg.name = UA_STRING("Pre-start WG");
cfg.publishingInterval = 100.0;
cfg.writerGroupId = 1;
cfg.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
UA_ExtensionObject_setValue(&cfg.messageSettings, &messageSettings,
&UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]);
UA_ExtensionObject_setValue(&cfg.transportSettings, &transport,
&UA_TYPES[UA_TYPES_DATAGRAMWRITERGROUPTRANSPORT2DATATYPE]);
UA_StatusCode res =
UA_Server_addWriterGroup(server, connectionIdent, &cfg, &writerGroupIdent);
ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
/* The deferred validation does not prevent the group from running after
* the startup */
res = UA_Server_run_startup(server);
ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
res = UA_Server_enablePubSubConnection(server, connectionIdent);
ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
res = UA_Server_enableWriterGroup(server, writerGroupIdent);
ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
UA_PubSubState st = UA_PUBSUBSTATE_DISABLED;
res = UA_Server_getWriterGroupState(server, writerGroupIdent, &st);
ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
ck_assert_int_eq(st, UA_PUBSUBSTATE_OPERATIONAL);
} END_TEST
/* WriterGroup: enabling while the parent PubSubConnection is in
* DISABLED state must land the WriterGroup in the PAUSED state. This
* exercises the "if(connection->head.state != UA_PUBSUBSTATE_OPERATIONAL)"
@@ -545,6 +591,7 @@ stateMachineSuite(void) {
TCase *tc_wg_state = tcase_create("WriterGroup state-machine branches");
tcase_add_checked_fixture(tc_wg_state, setup, teardown);
tcase_add_test(tc_wg_state, WriterGroup_UdpAddressBeforeStartup_IsAccepted);
tcase_add_test(tc_wg_state, WriterGroup_EnableWhileConnectionDisabled_GoesToPaused);
tcase_add_test(tc_wg_state, WriterGroup_BeforeStateChangeCallbackIsInvoked);
tcase_add_test(tc_wg_state, WriterGroup_EnableWhenDeleteFlagSet_Fails);