From c35eb35bb63a97b7c46e879819757a9cb48165b5 Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Tue, 17 Feb 2026 02:27:51 +0100 Subject: Initial commit: OPC UA discovery project CMake-based C project using open62541 for OPC UA discovery. Includes Local Discovery Server, register server, and find servers client with OpenSSL encryption support. --- src/server_register.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 src/server_register.c (limited to 'src/server_register.c') diff --git a/src/server_register.c b/src/server_register.c new file mode 100644 index 0000000..e1defd0 --- /dev/null +++ b/src/server_register.c @@ -0,0 +1,170 @@ +/** + * @file server_register.c + * @brief OPC UA Server that registers with a Local Discovery Server. + * + * This program runs an OPC UA server configured with security and periodically + * registers itself with a remote LDS using the RegisterServer2 service. It + * uses separate certificate pairs for the server and for the client connection + * to the LDS. On shutdown, it deregisters from the LDS. + */ + +#include "common.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +UA_Boolean running = true; + +static void +stopHandler (int sign) +{ + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c"); + running = false; +} + +/* ======================================================================== + * Main + * ======================================================================== */ + +int +main (int argc, char **argv) +{ + signal (SIGINT, stopHandler); + signal (SIGTERM, stopHandler); + + if (argc < 11) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Usage: %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " [, ...]\n" + "\n" + "Security modes : None, Sign, SignAndEncrypt\n" + "Security policies: None, Basic256Sha256, " + "Aes256_Sha256_RsaPss,\n" + " Aes128_Sha256_RsaOaep, ECC_nistP256", + argv[0]); + return EXIT_FAILURE; + } + + UA_UInt16 port = (UA_UInt16)atoi (argv[1]); + const char *applicationUri = argv[2]; + const char *clientCertPath = argv[5]; + const char *clientKeyPath = argv[6]; + const char *discoveryEndpoint = argv[7]; + int registerInterval = atoi (argv[8]); + + UA_MessageSecurityMode securityMode = parseSecurityMode (argv[9]); + if (securityMode == UA_MESSAGESECURITYMODE_INVALID) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Unknown security mode: %s", argv[9]); + return EXIT_FAILURE; + } + + const char *securityPolicyUri = resolveSecurityPolicyUri (argv[10]); + if (!securityPolicyUri) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Unknown security policy: %s", argv[10]); + return EXIT_FAILURE; + } + + size_t trustSize = (argc > 11) ? (size_t)argc - 11 : 0; + + UA_StatusCode retval; + UA_Server *server = createSecureServer ( + port, applicationUri, argv[3], argv[4], argv + 11, trustSize, &retval); + if (!server) + return EXIT_FAILURE; + + UA_ServerConfig *serverConfig = UA_Server_getConfig (server); + + serverConfig->applicationDescription.applicationType + = UA_APPLICATIONTYPE_SERVER; + + UA_Server_run_startup (server); + + /* UA_Server_registerDiscovery consumes (clears) the client config, + so a fresh zero-initialized config is needed for every call. */ + UA_ClientConfig clientConfig; + memset (&clientConfig, 0, sizeof (UA_ClientConfig)); + retval = createSecureClientConfig ( + &clientConfig, applicationUri, clientCertPath, clientKeyPath, argv + 11, + trustSize, securityMode, securityPolicyUri); + if (retval != UA_STATUSCODE_GOOD) + { + UA_Server_run_shutdown (server); + UA_Server_delete (server); + return EXIT_FAILURE; + } + + UA_String discoveryUrl = UA_STRING_ALLOC (discoveryEndpoint); + retval = UA_Server_registerDiscovery (server, &clientConfig, discoveryUrl, + UA_STRING_NULL); + UA_String_clear (&discoveryUrl); + if (retval != UA_STATUSCODE_GOOD) + UA_LOG_WARNING (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Initial register failed: %s", + UA_StatusCode_name (retval)); + + time_t lastRegister = time (NULL); + + while (running) + { + UA_Server_run_iterate (server, true); + + time_t now = time (NULL); + if (now - lastRegister >= registerInterval) + { + memset (&clientConfig, 0, sizeof (UA_ClientConfig)); + retval = createSecureClientConfig ( + &clientConfig, applicationUri, clientCertPath, clientKeyPath, + argv + 11, trustSize, securityMode, securityPolicyUri); + if (retval == UA_STATUSCODE_GOOD) + { + UA_String reregUrl = UA_STRING_ALLOC (discoveryEndpoint); + retval = UA_Server_registerDiscovery (server, &clientConfig, + reregUrl, UA_STRING_NULL); + UA_String_clear (&reregUrl); + if (retval != UA_STATUSCODE_GOOD) + UA_LOG_WARNING (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Re-register failed: %s", + UA_StatusCode_name (retval)); + } + lastRegister = now; + } + } + + memset (&clientConfig, 0, sizeof (UA_ClientConfig)); + retval = createSecureClientConfig ( + &clientConfig, applicationUri, clientCertPath, clientKeyPath, argv + 11, + trustSize, securityMode, securityPolicyUri); + if (retval == UA_STATUSCODE_GOOD) + { + UA_String deregUrl = UA_STRING_ALLOC (discoveryEndpoint); + retval = UA_Server_deregisterDiscovery (server, &clientConfig, deregUrl); + UA_String_clear (&deregUrl); + if (retval != UA_STATUSCODE_GOOD) + UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Could not unregister from discovery server: %s", + UA_StatusCode_name (retval)); + } + + UA_Server_run_shutdown (server); + UA_Server_delete (server); + return EXIT_SUCCESS; +} -- cgit v1.2.3