diff options
| author | Thomas Vanbesien <tvanbesi@proton.me> | 2026-02-19 00:14:25 +0100 |
|---|---|---|
| committer | Thomas Vanbesien <tvanbesi@proton.me> | 2026-02-19 00:14:25 +0100 |
| commit | a9ebc3b434b7979163fdf83984b32f1e513dacb8 (patch) | |
| tree | c801a98f44689669c905e833371fa539f4934a1f /src/client.c | |
| parent | bdc2305c2376c8b6697b6ecfecce104c956bdfcf (diff) | |
| download | BobinkCOpcUa-a9ebc3b434b7979163fdf83984b32f1e513dacb8.tar.gz BobinkCOpcUa-a9ebc3b434b7979163fdf83984b32f1e513dacb8.zip | |
Rename client executable to bobink_opcua_client
Diffstat (limited to 'src/client.c')
| -rw-r--r-- | src/client.c | 393 |
1 files changed, 0 insertions, 393 deletions
diff --git a/src/client.c b/src/client.c deleted file mode 100644 index 35a3e6f..0000000 --- a/src/client.c +++ /dev/null @@ -1,393 +0,0 @@ -/** - * @file client.c - * @brief Unified OPC UA client for discovery and server interaction. - * - * Supports four operations selected via CLI: - * find-servers — queries a server's FindServers service - * get-endpoints — queries a server's GetEndpoints service - * read-time — connects to a server and reads the current time - * download-cert — downloads a server's certificate to a local file - * - * Encryption is optional: when certificate, privateKey, and trustStore are - * provided, the client uses the configured security policy; otherwise it - * connects without encryption. - */ - -#include "common.h" -#include "config.h" - -#include <open62541/client_config_default.h> -#include <open62541/client_highlevel.h> -#include <open62541/plugin/log_stdout.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -/* ======================================================================== - * Operation Dispatch - * ======================================================================== */ - -typedef enum -{ - OP_FIND_SERVERS, - OP_GET_ENDPOINTS, - OP_READ_TIME, - OP_DOWNLOAD_CERT, - OP_INVALID -} operation; - -static operation -_s_parse_operation (const char *name) -{ - if (strcmp (name, "find-servers") == 0) - return OP_FIND_SERVERS; - if (strcmp (name, "get-endpoints") == 0) - return OP_GET_ENDPOINTS; - if (strcmp (name, "read-time") == 0) - return OP_READ_TIME; - if (strcmp (name, "download-cert") == 0) - return OP_DOWNLOAD_CERT; - return OP_INVALID; -} - -/* ======================================================================== - * Operations - * ======================================================================== */ - -/** - * Calls the FindServers service and prints all discovered servers. - * - * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise. - */ -static int -_s_op_find_servers (UA_Client *client, const char *url) -{ - size_t array_size = 0; - UA_ApplicationDescription *array = NULL; - - UA_StatusCode retval = UA_Client_findServers (client, url, 0, NULL, 0, NULL, - &array_size, &array); - if (retval != UA_STATUSCODE_GOOD) - { - UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, - "FindServers failed: %s", UA_StatusCode_name (retval)); - return EXIT_FAILURE; - } - - for (size_t i = 0; i < array_size; i++) - print_application_description (&array[i], i); - - UA_Array_delete (array, array_size, - &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]); - return EXIT_SUCCESS; -} - -/** - * Calls the GetEndpoints service and prints all endpoints. - * - * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise. - */ -static int -_s_op_get_endpoints (UA_Client *client, const char *url) -{ - size_t array_size = 0; - UA_EndpointDescription *array = NULL; - - UA_StatusCode retval - = UA_Client_getEndpoints (client, url, &array_size, &array); - if (retval != UA_STATUSCODE_GOOD) - { - UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, - "GetEndpoints failed: %s", UA_StatusCode_name (retval)); - return EXIT_FAILURE; - } - - for (size_t i = 0; i < array_size; i++) - print_endpoint (&array[i], i); - - UA_Array_delete (array, array_size, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); - return EXIT_SUCCESS; -} - -/** - * Connects to a server and reads the current time node. - * - * Authentication (anonymous, username/password, or X509 certificate) is - * configured in the client config before this function is called. - * - * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise. - */ -static int -_s_op_read_time (UA_Client *client, const char *url) -{ - UA_StatusCode retval = UA_Client_connect (client, url); - - if (retval != UA_STATUSCODE_GOOD) - { - UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, - "Could not connect: %s", UA_StatusCode_name (retval)); - return EXIT_FAILURE; - } - - UA_Variant value; - UA_Variant_init (&value); - - const UA_NodeId nodeId = UA_NS0ID (SERVER_SERVERSTATUS_CURRENTTIME); - retval = UA_Client_readValueAttribute (client, nodeId, &value); - - int rc = EXIT_SUCCESS; - if (retval == UA_STATUSCODE_GOOD - && UA_Variant_hasScalarType (&value, &UA_TYPES[UA_TYPES_DATETIME])) - { - UA_DateTime raw_date = *(UA_DateTime *)value.data; - UA_DateTimeStruct dts = UA_DateTime_toStruct (raw_date); - UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION, - "date is: %u-%u-%u %u:%u:%u.%03u", dts.day, dts.month, - dts.year, dts.hour, dts.min, dts.sec, dts.milliSec); - } - else - { - UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, - "Could not read current time: %s", - UA_StatusCode_name (retval)); - rc = EXIT_FAILURE; - } - - UA_Variant_clear (&value); - UA_Client_disconnect (client); - return rc; -} - -/** - * Downloads the server's certificate via GetEndpoints and writes it to a file. - * - * Picks the first endpoint that carries a non-empty serverCertificate. - * - * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise. - */ -static int -_s_op_download_cert (UA_Client *client, const char *url, - const char *output_path) -{ - size_t array_size = 0; - UA_EndpointDescription *array = NULL; - - UA_StatusCode retval - = UA_Client_getEndpoints (client, url, &array_size, &array); - if (retval != UA_STATUSCODE_GOOD) - { - UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, - "GetEndpoints failed: %s", UA_StatusCode_name (retval)); - return EXIT_FAILURE; - } - - UA_ByteString *cert = NULL; - for (size_t i = 0; i < array_size; i++) - { - if (array[i].serverCertificate.length > 0) - { - cert = &array[i].serverCertificate; - break; - } - } - - if (!cert) - { - UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, - "No endpoint returned a server certificate"); - UA_Array_delete (array, array_size, - &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); - return EXIT_FAILURE; - } - - FILE *fp = fopen (output_path, "wb"); - if (!fp) - { - UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, - "Could not open output file: %s", output_path); - UA_Array_delete (array, array_size, - &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); - return EXIT_FAILURE; - } - - size_t written = fwrite (cert->data, 1, cert->length, fp); - fclose (fp); - - int rc; - if (written != cert->length) - { - UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, - "Failed to write certificate (%zu of %zu bytes)", written, - cert->length); - rc = EXIT_FAILURE; - } - else - { - UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, - "Certificate saved to %s (%zu bytes)", output_path, - cert->length); - rc = EXIT_SUCCESS; - } - - UA_Array_delete (array, array_size, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); - return rc; -} - -/* ======================================================================== - * Main - * ======================================================================== */ - -int -main (int argc, char **argv) -{ - if (argc < 4) - { - UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Usage: %s <config-file> <operation> <endpoint-url> " - "[log-level]\n" - " %s <config-file> download-cert <endpoint-url> " - "<output-file> [log-level]\n" - "Operations: find-servers, get-endpoints, read-time, " - "download-cert", - argv[0], argv[0]); - return EXIT_FAILURE; - } - - operation op = _s_parse_operation (argv[2]); - if (op == OP_INVALID) - { - UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Unknown operation: %s (expected find-servers, " - "get-endpoints, read-time, download-cert)", - argv[2]); - return EXIT_FAILURE; - } - - const char *endpoint_url = argv[3]; - const char *output_path = NULL; - const char *log_level_str = "info"; - - if (op == OP_DOWNLOAD_CERT) - { - if (argc < 5 || argc > 6) - { - UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Usage: %s <config-file> download-cert " - "<endpoint-url> <output-file> [log-level]", - argv[0]); - return EXIT_FAILURE; - } - output_path = argv[4]; - log_level_str = (argc == 6) ? argv[5] : "info"; - } - else - { - if (argc > 5) - { - UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Usage: %s <config-file> <operation> <endpoint-url> " - "[log-level]", - argv[0]); - return EXIT_FAILURE; - } - log_level_str = (argc == 5) ? argv[4] : "info"; - } - int log_level = parse_log_level (log_level_str); - if (log_level < 0) - { - UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Unknown log level: %s " - "(expected trace, debug, info, warning, error, fatal)", - log_level_str); - return EXIT_FAILURE; - } - - config cfg; - if (config_load (argv[1], &cfg) != 0) - return EXIT_FAILURE; - - /* ---- Common config keys ---- */ - - const char *application_uri - = config_require (&cfg, "applicationUri", "Client"); - if (!application_uri) - { - config_free (&cfg); - return EXIT_FAILURE; - } - - security_config sec; - if (parse_security_config (&cfg, "Client", true, &sec) != 0) - { - config_free (&cfg); - return EXIT_FAILURE; - } - - /* ---- Auth config (read-time only) ---- */ - - auth_config auth = { .mode = AUTH_ANONYMOUS }; - - if (op == OP_READ_TIME && parse_auth_config (&cfg, "Client", &auth) != 0) - { - free_trust_store (sec.trust_paths, sec.trust_size); - config_free (&cfg); - return EXIT_FAILURE; - } - - /* ---- Create client ---- */ - - UA_Client *client = UA_Client_new (); - - UA_StatusCode retval; - if (op == OP_DOWNLOAD_CERT) - retval = create_unsecure_client_config (UA_Client_getConfig (client), - application_uri, NULL); - else if (sec.cert_path) - retval = create_secure_client_config (UA_Client_getConfig (client), - application_uri, &sec, &auth); - else - retval = create_unsecure_client_config (UA_Client_getConfig (client), - application_uri, &auth); - - if (retval != UA_STATUSCODE_GOOD) - { - UA_Client_delete (client); - free_trust_store (sec.trust_paths, sec.trust_size); - config_free (&cfg); - return EXIT_FAILURE; - } - - UA_Client_getConfig (client)->logging->context - = (void *)(uintptr_t)log_level; - - /* ---- Dispatch operation ---- */ - - int rc; - switch (op) - { - case OP_FIND_SERVERS: - rc = _s_op_find_servers (client, endpoint_url); - break; - case OP_GET_ENDPOINTS: - rc = _s_op_get_endpoints (client, endpoint_url); - break; - case OP_READ_TIME: - rc = _s_op_read_time (client, endpoint_url); - break; - case OP_DOWNLOAD_CERT: - rc = _s_op_download_cert (client, endpoint_url, output_path); - break; - default: - rc = EXIT_FAILURE; - break; - } - - /* ---- Cleanup ---- */ - - UA_Client_delete (client); - free_trust_store (sec.trust_paths, sec.trust_size); - config_free (&cfg); - - return rc; -} |
