aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThomas Vanbesien <tvanbesi@proton.me>2026-02-17 11:07:37 +0100
committerThomas Vanbesien <tvanbesi@proton.me>2026-02-17 11:07:37 +0100
commita54421dd976fd8081e96c11c2621076876c9986b (patch)
treea7614934364bc692dd94ee13a3ec6d242521194b /src
parentd1e229c80a6e51ccc5b21d001271c41d6cda30bf (diff)
downloadBobinkCOpcUa-a54421dd976fd8081e96c11c2621076876c9986b.tar.gz
BobinkCOpcUa-a54421dd976fd8081e96c11c2621076876c9986b.zip
Replace CLI arguments with config-file parser and add integration tests
Introduce a reusable key=value config parser (config.h/c) and convert all three programs to read their settings from config files instead of positional command-line arguments. Add example config files in config/ and 6 CTest integration tests covering None/Basic256Sha256/Aes128 with anonymous and user authentication. Remove the now-obsolete launch.sh.
Diffstat (limited to 'src')
-rw-r--r--src/client_find_servers.c80
-rw-r--r--src/config.c252
-rw-r--r--src/config.h120
-rw-r--r--src/server_lds.c74
-rw-r--r--src/server_register.c145
5 files changed, 551 insertions, 120 deletions
diff --git a/src/client_find_servers.c b/src/client_find_servers.c
index 21d48ca..e50623f 100644
--- a/src/client_find_servers.c
+++ b/src/client_find_servers.c
@@ -10,6 +10,7 @@
*/
#include "common.h"
+#include "config.h"
#include <open62541/client_highlevel.h>
#include <open62541/plugin/log_stdout.h>
@@ -210,64 +211,71 @@ readServerTime (UA_Client *client,
int
main (int argc, char **argv)
{
- if (argc < 8)
+ if (argc != 2)
{
UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Usage: %s <discovery-server-endpoint>\n"
- " <applicationUri>\n"
- " <certificate.der> <private-key.der>\n"
- " <security-mode> <security-policy>\n"
- " <auth-mode> [<username> <password>]\n"
- " [<trustlist1.der>, ...]\n"
- "\n"
- "Security modes : None, Sign, SignAndEncrypt\n"
- "Security policies: None, Basic256Sha256, "
- "Aes256_Sha256_RsaPss,\n"
- " Aes128_Sha256_RsaOaep, ECC_nistP256\n"
- "Auth modes : anonymous, user",
- argv[0]);
+ "Usage: %s <config-file>", argv[0]);
return EXIT_FAILURE;
}
- const char *discoveryServerEndpoint = argv[1];
- const char *applicationUri = argv[2];
- const char *certPath = argv[3];
- const char *keyPath = argv[4];
+ Config cfg;
+ if (configLoad (argv[1], &cfg) != 0)
+ return EXIT_FAILURE;
+
+ const char *discoveryServerEndpoint
+ = configRequire (&cfg, "discoveryEndpoint", "ClientFindServers");
+ const char *applicationUri
+ = configRequire (&cfg, "applicationUri", "ClientFindServers");
+ const char *certPath
+ = configRequire (&cfg, "certificate", "ClientFindServers");
+ const char *keyPath
+ = configRequire (&cfg, "privateKey", "ClientFindServers");
+ const char *securityModeStr
+ = configRequire (&cfg, "securityMode", "ClientFindServers");
+ const char *securityPolicyStr
+ = configRequire (&cfg, "securityPolicy", "ClientFindServers");
+ const char *authMode = configRequire (&cfg, "authMode", "ClientFindServers");
+
+ if (!discoveryServerEndpoint || !applicationUri || !certPath || !keyPath
+ || !securityModeStr || !securityPolicyStr || !authMode)
+ {
+ configFree (&cfg);
+ return EXIT_FAILURE;
+ }
- UA_MessageSecurityMode securityMode = parseSecurityMode (argv[5]);
+ UA_MessageSecurityMode securityMode = parseSecurityMode (securityModeStr);
if (securityMode == UA_MESSAGESECURITYMODE_INVALID)
{
UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Unknown security mode: %s", argv[5]);
+ "Unknown security mode: %s", securityModeStr);
+ configFree (&cfg);
return EXIT_FAILURE;
}
- const char *securityPolicyUri = resolveSecurityPolicyUri (argv[6]);
+ const char *securityPolicyUri = resolveSecurityPolicyUri (securityPolicyStr);
if (!securityPolicyUri)
{
UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Unknown security policy: %s", argv[6]);
+ "Unknown security policy: %s", securityPolicyStr);
+ configFree (&cfg);
return EXIT_FAILURE;
}
- int idx = 7;
- const char *authMode = argv[idx++];
const char *username = NULL, *password = NULL;
if (strcmp (authMode, "anonymous") == 0)
{
- /* No extra args needed */
+ /* No credentials needed */
}
else if (strcmp (authMode, "user") == 0)
{
- if (idx + 2 > argc)
+ username = configRequire (&cfg, "username", "ClientFindServers");
+ password = configRequire (&cfg, "password", "ClientFindServers");
+ if (!username || !password)
{
- UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Auth mode 'user' requires <username> <password>");
+ configFree (&cfg);
return EXIT_FAILURE;
}
- username = argv[idx++];
- password = argv[idx++];
}
else
{
@@ -275,11 +283,13 @@ main (int argc, char **argv)
"Unknown auth mode: %s "
"(expected 'anonymous' or 'user')",
authMode);
+ configFree (&cfg);
return EXIT_FAILURE;
}
- char **trustPaths = argv + idx;
- size_t trustSize = (idx < argc) ? (size_t)(argc - idx) : 0;
+ char **trustPaths = NULL;
+ size_t trustSize = 0;
+ configGetAll (&cfg, "trustList", &trustPaths, &trustSize);
UA_Client *client = UA_Client_new ();
UA_StatusCode retval = createSecureClientConfig (
@@ -288,6 +298,8 @@ main (int argc, char **argv)
if (retval != UA_STATUSCODE_GOOD)
{
UA_Client_delete (client);
+ free (trustPaths);
+ configFree (&cfg);
return EXIT_FAILURE;
}
@@ -300,6 +312,8 @@ main (int argc, char **argv)
if (retval != UA_STATUSCODE_GOOD)
{
UA_Client_delete (client);
+ free (trustPaths);
+ configFree (&cfg);
return EXIT_FAILURE;
}
@@ -313,6 +327,8 @@ main (int argc, char **argv)
UA_Array_delete (applicationDescriptionArray,
applicationDescriptionArraySize,
&UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
+ free (trustPaths);
+ configFree (&cfg);
return EXIT_SUCCESS;
}
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..163f601
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,252 @@
+/**
+ * @file config.c
+ * @brief Simple key=value configuration file parser implementation.
+ */
+
+#include "config.h"
+
+#include <open62541/plugin/log_stdout.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Enough for typical config files; doubles on overflow. */
+#define CONFIG_INITIAL_CAPACITY 16
+
+/* Sufficient for file paths and URIs. */
+#define CONFIG_LINE_MAX 1024
+
+/* ========================================================================
+ * Static Helpers
+ * ======================================================================== */
+
+/**
+ * @brief Trims leading and trailing whitespace in place.
+ *
+ * Modifies the string by writing a NUL terminator after the last
+ * non-whitespace character and returns a pointer past any leading
+ * whitespace.
+ */
+static char *
+trim (char *s)
+{
+ while (*s == ' ' || *s == '\t')
+ s++;
+ size_t len = strlen (s);
+ while (len > 0 && (s[len - 1] == ' ' || s[len - 1] == '\t'))
+ len--;
+ s[len] = '\0';
+ return s;
+}
+
+/**
+ * @brief Appends a key-value pair to the config's dynamic array.
+ *
+ * Grows the array by doubling capacity when full.
+ *
+ * @return 0 on success, -1 on allocation failure.
+ */
+static int
+configAppend (Config *cfg, const char *key, const char *value)
+{
+ if (cfg->count == cfg->capacity)
+ {
+ size_t newCap = cfg->capacity * 2;
+ ConfigEntry *tmp = realloc (cfg->entries, newCap * sizeof (ConfigEntry));
+ if (!tmp)
+ {
+ UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Config: out of memory");
+ return -1;
+ }
+ cfg->entries = tmp;
+ cfg->capacity = newCap;
+ }
+
+ cfg->entries[cfg->count].key = strdup (key);
+ cfg->entries[cfg->count].value = strdup (value);
+ if (!cfg->entries[cfg->count].key || !cfg->entries[cfg->count].value)
+ {
+ UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Config: out of memory");
+ return -1;
+ }
+ cfg->count++;
+ return 0;
+}
+
+/* ========================================================================
+ * Public API
+ * ======================================================================== */
+
+int
+configLoad (const char *path, Config *cfg)
+{
+ memset (cfg, 0, sizeof (Config));
+
+ cfg->entries = malloc (CONFIG_INITIAL_CAPACITY * sizeof (ConfigEntry));
+ if (!cfg->entries)
+ {
+ UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Config: out of memory");
+ return -1;
+ }
+ cfg->capacity = CONFIG_INITIAL_CAPACITY;
+
+ FILE *fp = fopen (path, "r");
+ if (!fp)
+ {
+ UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Config: cannot open '%s'", path);
+ free (cfg->entries);
+ memset (cfg, 0, sizeof (Config));
+ return -1;
+ }
+
+ char line[CONFIG_LINE_MAX];
+ int lineNum = 0;
+
+ while (fgets (line, sizeof (line), fp))
+ {
+ lineNum++;
+
+ /* Strip trailing newline / carriage return. */
+ size_t len = strlen (line);
+ while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
+ line[--len] = '\0';
+
+ /* Skip blank lines and comments. */
+ char *trimmed = trim (line);
+ if (*trimmed == '\0' || *trimmed == '#')
+ continue;
+
+ /* Find the '=' separator. */
+ char *eq = strchr (trimmed, '=');
+ if (!eq)
+ {
+ UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Config: syntax error at %s:%d "
+ "(missing '=')",
+ path, lineNum);
+ fclose (fp);
+ configFree (cfg);
+ return -1;
+ }
+
+ *eq = '\0';
+ char *key = trim (trimmed);
+ char *value = trim (eq + 1);
+
+ if (*key == '\0')
+ {
+ UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Config: empty key at %s:%d", path, lineNum);
+ fclose (fp);
+ configFree (cfg);
+ return -1;
+ }
+
+ if (configAppend (cfg, key, value) != 0)
+ {
+ fclose (fp);
+ configFree (cfg);
+ return -1;
+ }
+ }
+
+ fclose (fp);
+ return 0;
+}
+
+const char *
+configGet (const Config *cfg, const char *key)
+{
+ for (size_t i = 0; i < cfg->count; i++)
+ {
+ if (strcmp (cfg->entries[i].key, key) == 0)
+ return cfg->entries[i].value;
+ }
+ return NULL;
+}
+
+const char *
+configRequire (const Config *cfg, const char *key, const char *program)
+{
+ const char *val = configGet (cfg, key);
+ if (!val)
+ UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "%s: missing required config key '%s'", program, key);
+ return val;
+}
+
+int
+configRequireInt (const Config *cfg, const char *key, const char *program)
+{
+ const char *val = configRequire (cfg, key, program);
+ if (!val)
+ return -1;
+
+ char *endptr;
+ long num = strtol (val, &endptr, 10);
+ if (*endptr != '\0')
+ {
+ UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "%s: config key '%s' is not a valid integer: '%s'",
+ program, key, val);
+ return -1;
+ }
+ return (int)num;
+}
+
+void
+configGetAll (const Config *cfg, const char *key, char ***out, size_t *size)
+{
+ /* First pass: count matches. */
+ size_t count = 0;
+ for (size_t i = 0; i < cfg->count; i++)
+ {
+ if (strcmp (cfg->entries[i].key, key) == 0)
+ count++;
+ }
+
+ if (count == 0)
+ {
+ *out = NULL;
+ *size = 0;
+ return;
+ }
+
+ /* Second pass: collect pointers. */
+ char **arr = malloc (count * sizeof (char *));
+ if (!arr)
+ {
+ UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Config: out of memory");
+ *out = NULL;
+ *size = 0;
+ return;
+ }
+
+ size_t idx = 0;
+ for (size_t i = 0; i < cfg->count; i++)
+ {
+ if (strcmp (cfg->entries[i].key, key) == 0)
+ arr[idx++] = cfg->entries[i].value;
+ }
+
+ *out = arr;
+ *size = count;
+}
+
+void
+configFree (Config *cfg)
+{
+ for (size_t i = 0; i < cfg->count; i++)
+ {
+ free (cfg->entries[i].key);
+ free (cfg->entries[i].value);
+ }
+ free (cfg->entries);
+ memset (cfg, 0, sizeof (Config));
+}
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..ee29ada
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,120 @@
+/**
+ * @file config.h
+ * @brief Simple key=value configuration file parser.
+ *
+ * Parses configuration files with one key=value pair per line.
+ * Lines starting with '#' are comments. Blank lines are ignored.
+ * Repeated keys are allowed (used for list-valued settings like
+ * trustList).
+ */
+
+#ifndef DISCOVERY_CONFIG_H
+#define DISCOVERY_CONFIG_H
+
+#include <stddef.h>
+
+/**
+ * @brief A single key=value entry from a config file.
+ *
+ * Both key and value are heap-allocated, null-terminated strings
+ * with leading/trailing whitespace trimmed.
+ */
+typedef struct
+{
+ char *key;
+ char *value;
+} ConfigEntry;
+
+/**
+ * @brief A parsed configuration file.
+ *
+ * Holds a dynamic array of ConfigEntry items. Duplicate keys are
+ * allowed (used for list-valued settings like trustList).
+ */
+typedef struct
+{
+ ConfigEntry *entries;
+ size_t count;
+ size_t capacity;
+} Config;
+
+/**
+ * @brief Parses a configuration file into a Config structure.
+ *
+ * Each non-blank, non-comment line must contain '=' separating key
+ * and value. Whitespace is trimmed around both key and value.
+ *
+ * @param path Path to the configuration file.
+ * @param cfg Output: the parsed configuration. Must be freed
+ * with configFree() when no longer needed.
+ * @return 0 on success, -1 on error (logged via UA_LOG_ERROR).
+ */
+int configLoad (const char *path, Config *cfg);
+
+/**
+ * @brief Looks up a single-valued key.
+ *
+ * Returns the value of the first entry matching @p key, or NULL
+ * if the key is not present.
+ *
+ * @param cfg The parsed configuration.
+ * @param key The key to search for.
+ * @return The value string (owned by cfg), or NULL.
+ */
+const char *configGet (const Config *cfg, const char *key);
+
+/**
+ * @brief Looks up a required single-valued key.
+ *
+ * Like configGet(), but logs a FATAL error and returns NULL when
+ * the key is missing.
+ *
+ * @param cfg The parsed configuration.
+ * @param key The key to search for.
+ * @param program Program name (for error messages).
+ * @return The value string (owned by cfg), or NULL if missing.
+ */
+const char *configRequire (const Config *cfg, const char *key,
+ const char *program);
+
+/**
+ * @brief Looks up a required integer-valued key.
+ *
+ * Parses the value of @p key as an integer. If the key is
+ * missing or the value is not a valid integer, logs a FATAL
+ * error and returns -1.
+ *
+ * @param cfg The parsed configuration.
+ * @param key The key to search for.
+ * @param program Program name (for error messages).
+ * @return The parsed integer, or -1 on error.
+ */
+int configRequireInt (const Config *cfg, const char *key, const char *program);
+
+/**
+ * @brief Collects all values for a repeated key.
+ *
+ * Allocates an array of char* pointers to the values stored
+ * in @p cfg. The caller must free the array itself (but not
+ * the strings, which are owned by cfg).
+ *
+ * @param cfg The parsed configuration.
+ * @param key The key to collect (e.g. "trustList").
+ * @param out Output: heap-allocated array of string pointers.
+ * Set to NULL if the key is not present.
+ * @param size Output: number of entries in @p out.
+ */
+void configGetAll (const Config *cfg, const char *key, char ***out,
+ size_t *size);
+
+/**
+ * @brief Frees all memory owned by a Config structure.
+ *
+ * After this call the Config is zeroed and must not be used
+ * unless configLoad() is called again.
+ *
+ * @param cfg The configuration to free.
+ */
+void configFree (Config *cfg);
+
+#endif /* DISCOVERY_CONFIG_H */
diff --git a/src/server_lds.c b/src/server_lds.c
index fc51596..c6960d5 100644
--- a/src/server_lds.c
+++ b/src/server_lds.c
@@ -9,6 +9,7 @@
*/
#include "common.h"
+#include "config.h"
#include <open62541/plugin/accesscontrol_default.h>
#include <open62541/plugin/log_stdout.h>
@@ -17,6 +18,7 @@
#include <signal.h>
#include <stdlib.h>
+#include <string.h>
UA_Boolean running = true;
@@ -33,23 +35,31 @@ main (int argc, char *argv[])
signal (SIGINT, stopHandler);
signal (SIGTERM, stopHandler);
- if (argc < 7)
+ if (argc != 2)
{
UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Usage: %s\n"
- " <port> <applicationUri>\n"
- " <server-certificate.der> <private-key.der>\n"
- " <cleanup-timeout-seconds>\n"
- " <auth-mode> [<username> <password>]\n"
- " [<trustlist1.der>, ...]\n"
- "\n"
- "Auth modes: anonymous, user",
- argv[0]);
+ "Usage: %s <config-file>", argv[0]);
return EXIT_FAILURE;
}
- UA_UInt16 port = (UA_UInt16)atoi (argv[1]);
- int cleanupTimeout = atoi (argv[5]);
+ Config cfg;
+ if (configLoad (argv[1], &cfg) != 0)
+ return EXIT_FAILURE;
+
+ int port = configRequireInt (&cfg, "port", "ServerLDS");
+ const char *applicationUri
+ = configRequire (&cfg, "applicationUri", "ServerLDS");
+ const char *certPath = configRequire (&cfg, "certificate", "ServerLDS");
+ const char *keyPath = configRequire (&cfg, "privateKey", "ServerLDS");
+ int cleanupTimeout = configRequireInt (&cfg, "cleanupTimeout", "ServerLDS");
+ const char *authMode = configRequire (&cfg, "authMode", "ServerLDS");
+
+ if (!applicationUri || !certPath || !keyPath || !authMode || port < 0
+ || cleanupTimeout < 0)
+ {
+ configFree (&cfg);
+ return EXIT_FAILURE;
+ }
/* The OPC UA specification requires the cleanup timeout to exceed the
register-server interval. open62541 enforces a floor of 10 seconds. */
@@ -58,13 +68,12 @@ main (int argc, char *argv[])
UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Cleanup timeout must be > 10 seconds (got %d)",
cleanupTimeout);
+ configFree (&cfg);
return EXIT_FAILURE;
}
- int idx = 6;
- const char *authMode = argv[idx++];
UA_Boolean allowAnonymous;
- char *username = NULL, *password = NULL;
+ const char *username = NULL, *password = NULL;
if (strcmp (authMode, "anonymous") == 0)
{
@@ -72,15 +81,14 @@ main (int argc, char *argv[])
}
else if (strcmp (authMode, "user") == 0)
{
- if (idx + 2 > argc)
+ allowAnonymous = false;
+ username = configRequire (&cfg, "username", "ServerLDS");
+ password = configRequire (&cfg, "password", "ServerLDS");
+ if (!username || !password)
{
- UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Auth mode 'user' requires <username> <password>");
+ configFree (&cfg);
return EXIT_FAILURE;
}
- allowAnonymous = false;
- username = argv[idx++];
- password = argv[idx++];
}
else
{
@@ -88,16 +96,24 @@ main (int argc, char *argv[])
"Unknown auth mode: %s "
"(expected 'anonymous' or 'user')",
authMode);
+ configFree (&cfg);
return EXIT_FAILURE;
}
- size_t trustSize = (idx < argc) ? (size_t)(argc - idx) : 0;
+ char **trustPaths = NULL;
+ size_t trustSize = 0;
+ configGetAll (&cfg, "trustList", &trustPaths, &trustSize);
UA_StatusCode retval;
- UA_Server *server = createSecureServer (port, argv[2], argv[3], argv[4],
- argv + idx, trustSize, &retval);
+ UA_Server *server
+ = createSecureServer ((UA_UInt16)port, applicationUri, certPath, keyPath,
+ trustPaths, trustSize, &retval);
if (!server)
- return EXIT_FAILURE;
+ {
+ free (trustPaths);
+ configFree (&cfg);
+ return EXIT_FAILURE;
+ }
UA_ServerConfig *serverConfig = UA_Server_getConfig (server);
@@ -108,12 +124,14 @@ main (int argc, char *argv[])
if (!allowAnonymous)
{
UA_UsernamePasswordLogin logins[1];
- logins[0].username = UA_STRING (username);
- logins[0].password = UA_STRING (password);
+ logins[0].username = UA_STRING ((char *)username);
+ logins[0].password = UA_STRING ((char *)password);
retval = UA_AccessControl_default (serverConfig, false, NULL, 1, logins);
if (retval != UA_STATUSCODE_GOOD)
{
UA_Server_delete (server);
+ free (trustPaths);
+ configFree (&cfg);
return EXIT_FAILURE;
}
}
@@ -129,5 +147,7 @@ main (int argc, char *argv[])
retval = UA_Server_run (server, &running);
UA_Server_delete (server);
+ free (trustPaths);
+ configFree (&cfg);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/src/server_register.c b/src/server_register.c
index 60a4998..ae8e959 100644
--- a/src/server_register.c
+++ b/src/server_register.c
@@ -9,6 +9,7 @@
*/
#include "common.h"
+#include "config.h"
#include <open62541/client.h>
#include <open62541/client_config_default.h>
@@ -41,59 +42,73 @@ main (int argc, char **argv)
signal (SIGINT, stopHandler);
signal (SIGTERM, stopHandler);
- if (argc < 13)
+ if (argc != 2)
{
UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Usage: %s\n"
- " <port> <applicationUri>\n"
- " <server-certificate.der> <server-private-key.der>\n"
- " <client-certificate.der> <client-private-key.der>\n"
- " <discovery-server-endpoint>\n"
- " <register-interval-seconds>\n"
- " <security-mode> <security-policy>\n"
- " <server-auth-mode> [<server-user> <server-pass>]\n"
- " <client-auth-mode> [<client-user> <client-pass>]\n"
- " [<trustlist1.der>, ...]\n"
- "\n"
- "Security modes : None, Sign, SignAndEncrypt\n"
- "Security policies: None, Basic256Sha256, "
- "Aes256_Sha256_RsaPss,\n"
- " Aes128_Sha256_RsaOaep, ECC_nistP256\n"
- "Auth modes : anonymous, user",
- argv[0]);
+ "Usage: %s <config-file>", 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]);
+ Config cfg;
+ if (configLoad (argv[1], &cfg) != 0)
+ return EXIT_FAILURE;
+
+ int port = configRequireInt (&cfg, "port", "ServerRegister");
+ const char *applicationUri
+ = configRequire (&cfg, "applicationUri", "ServerRegister");
+ const char *serverCertPath
+ = configRequire (&cfg, "serverCertificate", "ServerRegister");
+ const char *serverKeyPath
+ = configRequire (&cfg, "serverPrivateKey", "ServerRegister");
+ const char *clientCertPath
+ = configRequire (&cfg, "clientCertificate", "ServerRegister");
+ const char *clientKeyPath
+ = configRequire (&cfg, "clientPrivateKey", "ServerRegister");
+ const char *discoveryEndpoint
+ = configRequire (&cfg, "discoveryEndpoint", "ServerRegister");
+ int registerInterval
+ = configRequireInt (&cfg, "registerInterval", "ServerRegister");
+ const char *securityModeStr
+ = configRequire (&cfg, "securityMode", "ServerRegister");
+ const char *securityPolicyStr
+ = configRequire (&cfg, "securityPolicy", "ServerRegister");
+ const char *serverAuthMode
+ = configRequire (&cfg, "serverAuthMode", "ServerRegister");
+ const char *clientAuthMode
+ = configRequire (&cfg, "clientAuthMode", "ServerRegister");
+
+ if (!applicationUri || !serverCertPath || !serverKeyPath || !clientCertPath
+ || !clientKeyPath || !discoveryEndpoint || !securityModeStr
+ || !securityPolicyStr || !serverAuthMode || !clientAuthMode || port < 0
+ || registerInterval < 0)
+ {
+ configFree (&cfg);
+ return EXIT_FAILURE;
+ }
- UA_MessageSecurityMode securityMode = parseSecurityMode (argv[9]);
+ UA_MessageSecurityMode securityMode = parseSecurityMode (securityModeStr);
if (securityMode == UA_MESSAGESECURITYMODE_INVALID)
{
UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Unknown security mode: %s", argv[9]);
+ "Unknown security mode: %s", securityModeStr);
+ configFree (&cfg);
return EXIT_FAILURE;
}
- const char *securityPolicyUri = resolveSecurityPolicyUri (argv[10]);
+ const char *securityPolicyUri = resolveSecurityPolicyUri (securityPolicyStr);
if (!securityPolicyUri)
{
UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Unknown security policy: %s", argv[10]);
+ "Unknown security policy: %s", securityPolicyStr);
+ configFree (&cfg);
return EXIT_FAILURE;
}
/* Parse server-side auth mode (what clients connecting to this server
need). "anonymous" allows unauthenticated sessions; "user" requires
a username/password pair. */
- int idx = 11;
- const char *serverAuthMode = argv[idx++];
UA_Boolean serverAllowAnonymous;
- char *serverUsername = NULL, *serverPassword = NULL;
+ const char *serverUsername = NULL, *serverPassword = NULL;
if (strcmp (serverAuthMode, "anonymous") == 0)
{
@@ -101,16 +116,16 @@ main (int argc, char **argv)
}
else if (strcmp (serverAuthMode, "user") == 0)
{
- if (idx + 2 > argc)
+ serverAllowAnonymous = false;
+ serverUsername
+ = configRequire (&cfg, "serverUsername", "ServerRegister");
+ serverPassword
+ = configRequire (&cfg, "serverPassword", "ServerRegister");
+ if (!serverUsername || !serverPassword)
{
- UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Server auth mode 'user' requires "
- "<username> <password>");
+ configFree (&cfg);
return EXIT_FAILURE;
}
- serverAllowAnonymous = false;
- serverUsername = argv[idx++];
- serverPassword = argv[idx++];
}
else
{
@@ -118,34 +133,28 @@ main (int argc, char **argv)
"Unknown server auth mode: %s "
"(expected 'anonymous' or 'user')",
serverAuthMode);
+ configFree (&cfg);
return EXIT_FAILURE;
}
/* Parse client-side auth mode (how this server authenticates to the
LDS when registering). */
- if (idx >= argc)
- {
- UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Missing client auth mode");
- return EXIT_FAILURE;
- }
- const char *clientAuthMode = argv[idx++];
- char *clientUsername = NULL, *clientPassword = NULL;
+ const char *clientUsername = NULL, *clientPassword = NULL;
if (strcmp (clientAuthMode, "anonymous") == 0)
{
}
else if (strcmp (clientAuthMode, "user") == 0)
{
- if (idx + 2 > argc)
+ clientUsername
+ = configRequire (&cfg, "clientUsername", "ServerRegister");
+ clientPassword
+ = configRequire (&cfg, "clientPassword", "ServerRegister");
+ if (!clientUsername || !clientPassword)
{
- UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Client auth mode 'user' requires "
- "<username> <password>");
+ configFree (&cfg);
return EXIT_FAILURE;
}
- clientUsername = argv[idx++];
- clientPassword = argv[idx++];
}
else
{
@@ -153,16 +162,24 @@ main (int argc, char **argv)
"Unknown client auth mode: %s "
"(expected 'anonymous' or 'user')",
clientAuthMode);
+ configFree (&cfg);
return EXIT_FAILURE;
}
- size_t trustSize = (idx < argc) ? (size_t)(argc - idx) : 0;
+ char **trustPaths = NULL;
+ size_t trustSize = 0;
+ configGetAll (&cfg, "trustList", &trustPaths, &trustSize);
UA_StatusCode retval;
- UA_Server *server = createSecureServer (
- port, applicationUri, argv[3], argv[4], argv + idx, trustSize, &retval);
+ UA_Server *server
+ = createSecureServer ((UA_UInt16)port, applicationUri, serverCertPath,
+ serverKeyPath, trustPaths, trustSize, &retval);
if (!server)
- return EXIT_FAILURE;
+ {
+ free (trustPaths);
+ configFree (&cfg);
+ return EXIT_FAILURE;
+ }
UA_ServerConfig *serverConfig = UA_Server_getConfig (server);
@@ -173,12 +190,14 @@ main (int argc, char **argv)
if (!serverAllowAnonymous)
{
UA_UsernamePasswordLogin logins[1];
- logins[0].username = UA_STRING (serverUsername);
- logins[0].password = UA_STRING (serverPassword);
+ logins[0].username = UA_STRING ((char *)serverUsername);
+ logins[0].password = UA_STRING ((char *)serverPassword);
retval = UA_AccessControl_default (serverConfig, false, NULL, 1, logins);
if (retval != UA_STATUSCODE_GOOD)
{
UA_Server_delete (server);
+ free (trustPaths);
+ configFree (&cfg);
return EXIT_FAILURE;
}
}
@@ -195,12 +214,14 @@ main (int argc, char **argv)
UA_ClientConfig clientConfig;
memset (&clientConfig, 0, sizeof (UA_ClientConfig));
retval = createSecureClientConfig (
- &clientConfig, applicationUri, clientCertPath, clientKeyPath, argv + idx,
+ &clientConfig, applicationUri, clientCertPath, clientKeyPath, trustPaths,
trustSize, securityMode, securityPolicyUri);
if (retval != UA_STATUSCODE_GOOD)
{
UA_Server_run_shutdown (server);
UA_Server_delete (server);
+ free (trustPaths);
+ configFree (&cfg);
return EXIT_FAILURE;
}
if (clientUsername)
@@ -230,7 +251,7 @@ main (int argc, char **argv)
memset (&clientConfig, 0, sizeof (UA_ClientConfig));
retval = createSecureClientConfig (
&clientConfig, applicationUri, clientCertPath, clientKeyPath,
- argv + idx, trustSize, securityMode, securityPolicyUri);
+ trustPaths, trustSize, securityMode, securityPolicyUri);
if (retval == UA_STATUSCODE_GOOD)
{
if (clientUsername)
@@ -253,7 +274,7 @@ main (int argc, char **argv)
our entry immediately rather than waiting for the cleanup timeout. */
memset (&clientConfig, 0, sizeof (UA_ClientConfig));
retval = createSecureClientConfig (
- &clientConfig, applicationUri, clientCertPath, clientKeyPath, argv + idx,
+ &clientConfig, applicationUri, clientCertPath, clientKeyPath, trustPaths,
trustSize, securityMode, securityPolicyUri);
if (retval == UA_STATUSCODE_GOOD)
{
@@ -271,5 +292,7 @@ main (int argc, char **argv)
UA_Server_run_shutdown (server);
UA_Server_delete (server);
+ free (trustPaths);
+ configFree (&cfg);
return EXIT_SUCCESS;
}