1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
# CLAUDE.md — OPC UA Discovery Project
## Project Overview
C project exploring OPC UA discovery using the open62541 library (git submodule at `deps/open62541`). CMake build system (C11). Source files live in `src/`, certificates in `certs/`, helper scripts in `tools/`.
## Build
```sh
cmake --build build --parallel
```
If the build directory doesn't exist yet or dependencies need reconfiguring:
```sh
cmake -B build
cmake --build build --parallel
```
open62541 is built automatically via `cmake/BuildDeps.cmake` with `UA_ENABLE_ENCRYPTION=OPENSSL` and `UA_ENABLE_DISCOVERY=ON`, installed to `build/deps/open62541-install`. The open62541 build directory is `build/deps/open62541`.
After building, verify that `compile_commands.json` is symlinked from `build/` to the project root.
### Building Documentation
To build the open62541 HTML documentation (requires `python3-sphinx`, `python3-sphinx-rtd-theme`, `graphviz`):
```sh
cmake -B build -DBUILD_DOC=ON
cmake --build build --target doc
```
Output goes to `build/deps/open62541/doc/index.html`.
## Code Style
- Follow the `.clang-format` file in the project root (GNU-based style).
- Key points: 2-space indent, braces on own line (`BreakBeforeBraces: GNU`), space before parens (`SpaceBeforeParens: Always`), pointer star on the right (`PointerAlignment: Right`), 79-column limit, return type on its own line for definitions.
- Do **not** reformat code you didn't change.
## Workflow Preferences
- **Ask before committing.** Never commit without explicit confirmation.
- **Ask when ambiguous.** If a task or requirement is unclear, ask rather than guess.
- **Plan mode:** Ask before entering plan mode — don't assume it's needed.
- **Validation:** After making changes, confirm the project compiles with `cmake --build build --parallel`. When asked to run or test, start all three programs (LDS, ServerRegister, ClientFindServers) using the commands in the **Running** section below, then verify the client output.
- **Verbosity:** Give detailed explanations of what was done and why.
## Certificates
Generate DER certificates with `tools/generate_certificate.sh <certs_dir> <name>`. This creates `<name>_cert.der` and `<name>_key.der` in the given directory. Four identities are needed:
```sh
tools/generate_certificate.sh certs ServerLDS
tools/generate_certificate.sh certs ServerRegister
tools/generate_certificate.sh certs ServerRegisterClient
tools/generate_certificate.sh certs ClientFindServers
```
Existing certs live in `certs/`. Only regenerate if missing.
## Running
All three programs run from the project root. Start them in order in separate terminals:
**1. Local Discovery Server (LDS)**
```sh
build/ServerLDS 4840 "urn:bobink.ServerLDS" \
certs/ServerLDS_cert.der certs/ServerLDS_key.der \
60 \
certs/ServerRegisterClient_cert.der certs/ClientFindServers_cert.der
```
Args: `<port> <applicationUri> <cert> <key> <cleanup-timeout-seconds> [trustlist...]`
The trustlist must include the client certs that will connect over encrypted channels: `ServerRegisterClient_cert.der` (used by `ServerRegister`) and `ClientFindServers_cert.der` (used by `ClientFindServers`). Cleanup timeout must be > 10.
**2. Register Server**
```sh
build/ServerRegister 4841 "urn:bobink.ServerRegister" \
certs/ServerRegister_cert.der certs/ServerRegister_key.der \
certs/ServerRegisterClient_cert.der certs/ServerRegisterClient_key.der \
"opc.tcp://localhost:4840" 10 \
SignAndEncrypt Aes128_Sha256_RsaOaep \
certs/ServerLDS_cert.der certs/ClientFindServers_cert.der
```
Args: `<port> <applicationUri> <server-cert> <server-key> <client-cert> <client-key> <discovery-endpoint> <register-interval-seconds> <security-mode> <security-policy> [trustlist...]`
Uses separate server/client certificate pairs. The client cert+key are for the secure channel to the LDS. Re-registers periodically at the given interval. Trustlist should include the LDS cert and any client certs that will query this server's endpoints (e.g. `ClientFindServers_cert.der`).
**3. Find Servers Client**
```sh
build/ClientFindServers "opc.tcp://localhost:4840" \
"urn:bobink.ClientFindServers" \
certs/ClientFindServers_cert.der certs/ClientFindServers_key.der \
SignAndEncrypt Aes128_Sha256_RsaOaep \
certs/ServerLDS_cert.der certs/ServerRegister_cert.der
```
Args: `<discovery-server-endpoint> <applicationUri> <cert> <key> <security-mode> <security-policy> [trustlist...]`
Queries the LDS and prints all registered servers and their endpoints. The trustlist should include the certs of all servers whose endpoints will be queried.
**Security options** (for both ServerRegister and ClientFindServers):
| Security modes | Security policies |
|----------------|-------------------|
| `None` | `None` |
| `Sign` | `Basic256Sha256` |
| `SignAndEncrypt` | `Aes256_Sha256_RsaPss` |
| | `Aes128_Sha256_RsaOaep` |
| | `ECC_nistP256` |
## Project Structure
| Path | Purpose |
|------|---------|
| `src/common.h` / `src/common.c` | Shared helpers: `loadFile()`, `createSecureServer()`, `createSecureClientConfig()`, `parseSecurityMode()`, `resolveSecurityPolicyUri()` |
| `src/server_lds.c` | Local Discovery Server |
| `src/server_register.c` | Server that registers with LDS |
| `src/client_find_servers.c` | Client that queries LDS and displays endpoints |
| `certs/` | TLS certificates for server, client, and LDS |
| `tools/` | Helper scripts |
| `cmake/BuildDeps.cmake` | Configures, builds, and installs open62541 |
| `deps/open62541` | open62541 git submodule |
|