diff options
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..bd8eb2d --- /dev/null +++ b/README.md @@ -0,0 +1,175 @@ +# BobinkCOpcUa + +A small C project that demonstrates OPC UA server discovery using the [open62541](https://www.open62541.org/) library. Three programs work together: + +- **bobink_opcua_discovery_server** — Local Discovery Server that other servers register with +- **bobink_opcua_server** — a server that periodically registers itself with the LDS +- **bobink_opcua_client** — queries the LDS for servers, lists endpoints, reads the current time, or downloads a server's certificate + +## Prerequisites + +- CMake 3.17+ +- A C11 compiler (GCC or Clang) +- OpenSSL development libraries (`libssl-dev` / `openssl-devel`) +- `openssl` CLI (for generating certificates) + +## Getting started + +Clone the repository with its submodule: + +```sh +git clone --recursive https://git.tvcloud.fr/BobinkCOpcUa +cd BobinkCOpcUa +``` + +### Certificates + +Test certificates are pre-generated and committed under each test directory (e.g. `tests/secure_anonymous/certs/`). Each secure test has per-identity subdirectories (`ServerLDS/`, `ServerRegister/`, `ServerRegisterClient/`, `Client/`) containing `cert.der` and `key.der`, plus a shared `trust/` directory with all certificates. + +Programs can also run without certificates (SecurityPolicy#None only) by omitting the `certificate`, `privateKey`, and `trustStore` keys from their config files. + +To generate new certificates, use `tools/generate_certificate.sh <output_dir> <name> [uri]`. + +### Build + +```sh +cmake -B build +cmake --build build --parallel +``` + +open62541 is fetched from the submodule and built automatically — the first build takes a bit longer. + +## Running + +Start the programs in order, each in its own terminal, from the project root. Configuration files live in `tests/` (one directory per test scenario — see [Tests](#tests) below). The examples below use `tests/secure_user/`: + +```sh +# 1. Local Discovery Server +build/bobink_opcua_discovery_server tests/secure_user/server_lds.conf + +# 2. Register Server (connects to the LDS on port 14840) +build/bobink_opcua_server tests/secure_user/server_register.conf \ + tests/secure_user/server_register_client.conf opc.tcp://localhost:14840 \ + [nodes.conf] + +# 3. Find registered servers via the LDS +build/bobink_opcua_client tests/secure_user/client.conf find-servers opc.tcp://localhost:14840 + +# 4. List endpoints on the registered server +build/bobink_opcua_client tests/secure_user/client.conf get-endpoints opc.tcp://localhost:14841 + +# 5. Read the current time from the registered server +build/bobink_opcua_client tests/secure_user/client.conf read-time opc.tcp://localhost:14841 + +# 6. Download the server's certificate to a local file +build/bobink_opcua_client tests/secure_user/client.conf download-cert opc.tcp://localhost:14841 server.der +``` + +All three programs accept an optional log level as the last argument (`trace`, `debug`, `info`, `warning`, `error`, `fatal`). The default is `info`. + +## Tests + +Integration tests exercise four combinations of security and authentication: + +| Test | Security | Auth | +|----------------------|---------------------------------------|---------------------------| +| `unsecure_anonymous` | None / None | anonymous | +| `secure_anonymous` | SignAndEncrypt / Aes256_Sha256_RsaPss | anonymous | +| `secure_user` | SignAndEncrypt / Aes256_Sha256_RsaPss | user/password | +| `secure_cert` | SignAndEncrypt / Aes256_Sha256_RsaPss | X509 certificate | +| `download_cert` | SignAndEncrypt / Aes256_Sha256_RsaPss | anonymous (download-cert) | + +Run all tests: + +```sh +ctest --test-dir build --output-on-failure +``` + +### Memory leak check + +Rebuild with AddressSanitizer, run the tests, then switch back: + +```sh +# ASan build +cmake -B build \ + -DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \ + -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address" +cmake --build build --parallel + +ASAN_OPTIONS="detect_leaks=1" ctest --test-dir build --output-on-failure + +# Restore normal build +cmake -B build -DCMAKE_C_FLAGS="" -DCMAKE_EXE_LINKER_FLAGS="" +cmake --build build --parallel +``` + +## Configuration + +Programs are configured through plain text files (`key = value`, one per line). See the `tests/` directories for working examples. + +Three authentication modes are supported via the `authMode` key: + +- **anonymous** — no user identity +- **user** — username and password (requires `username` and `password` keys) +- **cert** — X509 certificate identity token (reuses the application certificate; requires encryption to be configured) + +## Nodes Configuration + +`bobink_opcua_server` accepts an optional nodes config file that populates the server's address space with variable nodes. Pass it as the fourth positional argument (before the optional log level): + +```sh +build/bobink_opcua_server server.conf client.conf opc.tcp://localhost:14840 nodes.conf +``` + +The config file only declares the node structure (name, type, access level). Values are not specified in the config — the server assigns random values at startup and updates them every five seconds. This is intended for testing OPC UA monitoring and subscriptions. + +The file uses the same `key = value` format with dot-indexed keys: + +``` +node.0.name = Temperature +node.0.description = Current temperature reading +node.0.type = double +node.0.accessLevel = read + +node.1.name = DeviceName +node.1.type = string +node.1.accessLevel = readwrite + +node.2.name = Measurements +node.2.description = Recent measurements +node.2.type = double[] +node.2.accessLevel = read +``` + +Each node gets a string NodeId in namespace 1 (`ns=1;s=<name>`). The `name` field is also used as the display name and browse name. Array nodes are created with 5 elements. + +### Fields + +| Field | Required | Description | +|---------------|----------|---------------------------------------------------------| +| `name` | yes | Display name, browse name, and string NodeId | +| `description` | no | Human-readable description | +| `type` | yes | Data type (see table below); append `[]` for a 1D array | +| `accessLevel` | yes | `read` or `readwrite` | + +### Supported Types + +| Type name | OPC UA type | +|--------------|-------------| +| `bool` | Boolean | +| `int16` | Int16 | +| `uint16` | UInt16 | +| `int32` | Int32 | +| `uint32` | UInt32 | +| `int64` | Int64 | +| `uint64` | UInt64 | +| `float` | Float | +| `double` | Double | +| `string` | String | +| `sbyte` | SByte | +| `byte` | Byte | +| `datetime` | DateTime | +| `guid` | Guid | +| `bytestring` | ByteString | + +Append `[]` to any type name for a 1D array (e.g. `double[]`, `string[]`). |
