VLink  2.0.0
A high-performance communication middleware
c_api.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2026 by Thun Lu. All rights reserved.
3  * Author: Thun Lu <thun.lu@zohomail.cn>
4  * Repo: https://github.com/thun-res/vlink
5  * _ __ __ _ __
6  * | | / / / / (_) ____ / /__
7  * | | / / / / / / / __ \ / //_/
8  * | |/ / / /___ / / / / / / / ,<
9  * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 /**
25  * @file c_api.h
26  * @brief Pure C binding over the VLink communication middleware.
27  *
28  * @details
29  * Exposes a stable, language-agnostic C surface across the three VLink
30  * communication models. Every public function wraps a corresponding C++
31  * template instantiation that uses @c vlink::Bytes as its payload type, so the
32  * C ABI never has to leak C++ type information.
33  *
34  * @par Model Mapping
35  *
36  * | Model | C++ class | C handle types |
37  * | ------- | ---------------------------- | ---------------------------------------------------------- |
38  * | Event | @c Publisher / @c Subscriber | @c vlink_publisher_handle_t / @c vlink_subscriber_handle_t |
39  * | Method | @c Server / @c Client | @c vlink_server_handle_t / @c vlink_client_handle_t |
40  * | Field | @c Setter / @c Getter | @c vlink_setter_handle_t / @c vlink_getter_handle_t |
41  *
42  * @par C / C++ Boundary
43  * @code
44  * +-----------------------+ +---------------------------------+
45  * | User C / C++ code | | vlink C++ core templates |
46  * | | | Publisher<Bytes>, Server<...>, |
47  * | vlink_publish(...) | | Setter<Bytes>, Security, ... |
48  * | vlink_invoke(...) | +----------------+----------------+
49  * | vlink_set(...) | ^
50  * +-----------+-----------+ |
51  * | handle.native_handle (opaque) |
52  * v |
53  * +-----------------------+ shallow Bytes::wrap |
54  * | c_api.h boundary +-------------------------+
55  * | (this file) |
56  * +-----------------------+
57  * @endcode
58  *
59  * @par Return Code Family
60  *
61  * | Code | Meaning |
62  * | ------------------------------- | -------------------------------------------------- |
63  * | @c VLINK_RET_NO_ERROR (0) | Success. |
64  * | @c VLINK_RET_UNEXPECTED_ERROR | Condition not met yet (e.g. no subscribers). |
65  * | @c VLINK_RET_INVALID_ERROR | Null pointer / invalid handle / bad arguments. |
66  * | @c VLINK_RET_MEMORY_ERROR | Allocation failure or output buffer too small. |
67  * | @c VLINK_RET_RUNTIME_ERROR | Runtime state error or C++ construction exception. |
68  * | @c VLINK_RET_TRANSFER_ERROR | Publish / listen / invoke operation failed. |
69  * | @c VLINK_RET_UNKNOWN_ERROR (-1) | Unclassified internal error. |
70  *
71  * @par Server Reply Protocol
72  * The @c vlink_server_handle_t::reserved array coordinates the synchronous
73  * request-reply flow. Inside @c vlink_req_callback_t a call to @c vlink_reply()
74  * stores the response. When the callback returns, the relayed reply is sent to
75  * the client. Calling @c vlink_reply() after the callback returns fails with
76  * @c VLINK_RET_RUNTIME_ERROR because no request is in progress.
77  * @code
78  * static void on_request(const uint8_t* data, size_t size, void* user_data) {
79  * vlink_server_handle_t* handle = (vlink_server_handle_t*) user_data;
80  * vlink_reply(handle, resp_data, resp_size);
81  * }
82  *
83  * vlink_schema_info_t schema = {"demo.raw.Text", VLINK_SCHEMA_RAW};
84  * vlink_create_server(url, &schema, &handle, on_request, &handle);
85  * @endcode
86  *
87  * @par Example -- Event (Publisher / Subscriber)
88  * @code
89  * vlink_publisher_handle_t pub;
90  * vlink_schema_info_t schema = {"demo.proto.PointCloud", VLINK_SCHEMA_PROTOBUF};
91  * vlink_create_publisher("dds://my/topic", &schema, &pub);
92  * vlink_wait_for_subscribers(pub, 1000);
93  * vlink_publish(pub, data_buf, data_size);
94  * vlink_destroy_publisher(&pub);
95  *
96  * static void on_message(const uint8_t* data, size_t size, void* user_data) { (void)data; }
97  * vlink_subscriber_handle_t sub;
98  * vlink_create_subscriber("dds://my/topic", &schema, &sub, on_message, NULL);
99  * @endcode
100  *
101  * @par Example -- Method (Server / Client)
102  * @code
103  * vlink_client_handle_t cli;
104  * vlink_schema_info_t schema = {"demo.raw.Echo", VLINK_SCHEMA_RAW};
105  * vlink_create_client("dds://echo", &schema, &cli);
106  * vlink_wait_for_server(cli, 1000);
107  * vlink_invoke(cli, req_buf, req_size, on_response, NULL);
108  * @endcode
109  *
110  * @par Example -- Field (Setter / Getter)
111  * @code
112  * vlink_getter_handle_t getter;
113  * vlink_schema_info_t schema = {"demo.proto.State", VLINK_SCHEMA_PROTOBUF};
114  * vlink_create_getter("dds://state/topic", &schema, &getter, NULL, NULL);
115  *
116  * uint8_t buf[4096];
117  * size_t sz = sizeof(buf);
118  * if (vlink_get(getter, buf, &sz) == VLINK_RET_NO_ERROR) {
119  * // buf[0..sz-1] holds the latest value
120  * }
121  * @endcode
122  *
123  * @note
124  * - Internally the C API uses @c vlink::Publisher<vlink::Bytes> and equivalents.
125  * The @c vlink_schema_info_t aggregate configures @c ser + @c schema atomically.
126  * - Every create/destroy pair must be balanced; handles are not thread-safe for
127  * concurrent create/destroy calls.
128  * - @c vlink_get() copies the latest value into the caller-supplied buffer and
129  * returns @c VLINK_RET_MEMORY_ERROR when the buffer is smaller than the payload.
130  * - @c vlink_publish_by_force() publishes even with no matched subscribers,
131  * useful for transient-local-durability scenarios.
132  */
133 
134 #pragma once
135 
136 // NOLINTBEGIN
137 
138 #undef VLINK_C_API_EXPORT
139 #ifdef VLINK_C_API_LIBRARY_STATIC
140 #define VLINK_C_API_EXPORT
141 #elif defined(_WIN32) || defined(__CYGWIN__)
142 #ifdef VLINK_C_API_LIBRARY
143 #define VLINK_C_API_EXPORT __declspec(dllexport)
144 #else
145 #define VLINK_C_API_EXPORT __declspec(dllimport)
146 #endif
147 #else
148 #define VLINK_C_API_EXPORT __attribute__((visibility("default")))
149 #endif
150 
151 #include <stdbool.h>
152 #include <stddef.h>
153 #include <stdint.h>
154 
155 #ifdef __cplusplus
156 extern "C" {
157 #endif
158 
159 /**
160  * @name Common types and return codes
161  * @{
162  */
163 
164 /**
165  * @brief Return code for VLink C API functions that report @c vlink_ret_t.
166  *
167  * @details
168  * @c VLINK_RET_NO_ERROR is the only success code. Positive values classify
169  * recoverable API states or errors and @c VLINK_RET_UNKNOWN_ERROR (-1) indicates
170  * an unclassified internal error. Always check the symbolic value -- do not
171  * treat every non-negative result as success.
172  */
173 typedef enum {
174  VLINK_RET_UNKNOWN_ERROR = -1, /**< Unclassified or unexpected internal error. */
175  VLINK_RET_NO_ERROR = 0, /**< Operation succeeded. */
176  VLINK_RET_UNEXPECTED_ERROR = 1, /**< Condition not yet met (e.g. no subscribers matched). */
177  VLINK_RET_INVALID_ERROR = 2, /**< Null pointer argument or otherwise invalid handle / arguments. */
178  VLINK_RET_MEMORY_ERROR = 3, /**< Allocation failure or caller-provided buffer is too small. */
179  VLINK_RET_RUNTIME_ERROR = 4, /**< Runtime state error or C++ construction exception. */
180  VLINK_RET_TRANSFER_ERROR = 5, /**< Publish, listen, or invoke operation failed. */
181 } vlink_ret_t;
182 
183 /**
184  * @brief Coarse runtime schema family used for raw C API nodes.
185  *
186  * @details
187  * The numeric values are kept in sync with @c vlink::SchemaType (see
188  * @c include/vlink/impl/types.h), so the C API implementation can cast between
189  * the two enums safely. Always reference the symbolic names -- the underlying
190  * mapping is intentionally opaque at source level.
191  */
192 typedef enum {
193  VLINK_SCHEMA_UNKNOWN = 0, /**< Schema family is not specified. */
194  VLINK_SCHEMA_RAW = 1, /**< Opaque / raw payload. */
195  VLINK_SCHEMA_ZEROCOPY = 2, /**< VLink zero-copy payload. */
196  VLINK_SCHEMA_PROTOBUF = 3, /**< Protocol Buffers payload. */
197  VLINK_SCHEMA_FLATBUFFERS = 4, /**< FlatBuffers payload. */
199 
200 /**
201  * @brief Bundled runtime schema metadata supplied at node creation.
202  *
203  * @details
204  * Mirrors the C++ pair of @c ser_type + @c schema_type so callers can configure
205  * both atomically before the underlying node is initialised. Both fields must
206  * either be provided together or left unset (@c ser == @c NULL / empty and
207  * @c schema == @c VLINK_SCHEMA_UNKNOWN).
208  */
209 typedef struct {
210  const char* ser; /**< Concrete type name / serialisation identifier, or @c NULL. */
211  vlink_schema_t schema; /**< Coarse schema family. */
213 
214 /** @} */
215 
216 /**
217  * @name Opaque node handles
218  *
219  * @details
220  * Each handle is a small POD struct holding @c native_handle (a pointer to the
221  * underlying heap-allocated C++ instance) plus a @c reserved scratch area used
222  * by the C API for internal state -- security context, request/reply
223  * coordination, etc. Treat every @c reserved slot as opaque: the layout is
224  * private and may change between releases.
225  *
226  * @{
227  */
228 
229 /**
230  * @brief Opaque handle for a @c Publisher node.
231  *
232  * @details
233  * Created by @c vlink_create_publisher() and destroyed by
234  * @c vlink_destroy_publisher(). @c native_handle references a heap-allocated
235  * @c vlink::Publisher<vlink::Bytes>.
236  */
237 typedef struct {
238  void* native_handle; /**< Internal C++ Publisher object pointer. */
239  void* reserved[8]; /**< Reserved for internal state; do not touch.*/
241 
242 /**
243  * @brief Opaque handle for a @c Subscriber node.
244  *
245  * @details
246  * Created by @c vlink_create_subscriber() and destroyed by
247  * @c vlink_destroy_subscriber(). @c native_handle references a heap-allocated
248  * @c vlink::Subscriber<vlink::Bytes>.
249  */
250 typedef struct {
251  void* native_handle; /**< Internal C++ Subscriber object pointer. */
252  void* reserved[8]; /**< Reserved for internal state; do not touch.*/
254 
255 /**
256  * @brief Opaque handle for a @c Server node.
257  *
258  * @details
259  * Created by @c vlink_create_server() and destroyed by
260  * @c vlink_destroy_server(). @c native_handle references a heap-allocated
261  * @c vlink::Server<vlink::Bytes, vlink::Bytes>. The @c reserved array holds the
262  * coordination data used to implement the synchronous request-reply protocol;
263  * its layout is intentionally private.
264  */
265 typedef struct {
266  void* native_handle; /**< Internal C++ Server object pointer. */
267  void* reserved[8]; /**< Internal coordination state; do not touch. */
269 
270 /**
271  * @brief Opaque handle for a @c Client node.
272  *
273  * @details
274  * Created by @c vlink_create_client() and destroyed by
275  * @c vlink_destroy_client(). @c native_handle references a heap-allocated
276  * @c vlink::Client<vlink::Bytes, vlink::Bytes>.
277  */
278 typedef struct {
279  void* native_handle; /**< Internal C++ Client object pointer. */
280  void* reserved[8]; /**< Reserved for internal state; do not touch. */
282 
283 /**
284  * @brief Opaque handle for a @c Setter node.
285  *
286  * @details
287  * Created by @c vlink_create_setter() and destroyed by
288  * @c vlink_destroy_setter(). @c native_handle references a heap-allocated
289  * @c vlink::Setter<vlink::Bytes>.
290  */
291 typedef struct {
292  void* native_handle; /**< Internal C++ Setter object pointer. */
293  void* reserved[8]; /**< Reserved for internal state; do not touch. */
295 
296 /**
297  * @brief Opaque handle for a @c Getter node.
298  *
299  * @details
300  * Created by @c vlink_create_getter() and destroyed by
301  * @c vlink_destroy_getter(). @c native_handle references a heap-allocated
302  * @c vlink::Getter<vlink::Bytes>.
303  */
304 typedef struct {
305  void* native_handle; /**< Internal C++ Getter object pointer. */
306  void* reserved[8]; /**< Reserved for internal state; do not touch. */
308 
309 /** @} */
310 
311 /**
312  * @name Callback typedefs
313  * @{
314  */
315 
316 /**
317  * @brief Callback fired when the connection state of a Publisher or Client changes.
318  *
319  * @param is_connected @c true when at least one peer is matched, @c false otherwise.
320  * @param user_data Opaque pointer supplied at registration time.
321  *
322  * @note Invoked from a VLink-internal event thread; keep the body short and
323  * avoid blocking calls.
324  */
325 typedef void (*vlink_connect_callback_t)(const bool is_connected, void* user_data);
326 
327 /**
328  * @brief Callback fired when a Subscriber or Getter receives a message.
329  *
330  * @param data Pointer to the received payload bytes.
331  * @param size Number of bytes available at @p data.
332  * @param user_data Opaque pointer supplied at creation time.
333  *
334  * @note Invoked on the underlying receive thread. The @p data buffer is only
335  * valid for the duration of the callback -- copy if you need to retain it.
336  */
337 typedef void (*vlink_msg_callback_t)(const uint8_t* data, const size_t size, void* user_data);
338 
339 /**
340  * @brief Callback fired when a Server receives an RPC request.
341  *
342  * @details
343  * Invoked synchronously on the Server's dispatch thread while an internal mutex
344  * is held. Call @c vlink_reply() from inside this callback to provide a
345  * non-empty response before it returns. Without a @c vlink_reply() call the
346  * request completes with an empty payload. Calling @c vlink_reply() after the
347  * callback returns fails with @c VLINK_RET_RUNTIME_ERROR because no request is
348  * in progress.
349  *
350  * @param data Pointer to the request payload bytes.
351  * @param size Number of bytes available at @p data.
352  * @param user_data Opaque pointer supplied at creation time.
353  */
354 typedef void (*vlink_req_callback_t)(const uint8_t* data, const size_t size, void* user_data);
355 
356 /**
357  * @brief Callback fired when a Client receives an RPC response.
358  *
359  * @param data Pointer to the response payload bytes; may be @c NULL when
360  * the server did not provide a response.
361  * @param size Number of bytes available at @p data.
362  * @param user_data Opaque pointer supplied at invocation time.
363  */
364 typedef void (*vlink_resp_callback_t)(const uint8_t* data, const size_t size, void* user_data);
365 
366 /** @} */
367 
368 /* Forward declaration of the Security configuration aggregate. The full
369  * definition lives further down with the Security API; this forward declaration
370  * lets the @c vlink_create_secure_*() node creation entry points reference
371  * @c const vlink_security_config_t* before the struct body is in scope. */
374 
375 ////////////////////////////////////////////////////////////////
376 /// Publisher
377 ////////////////////////////////////////////////////////////////
378 
379 /**
380  * @name Event model -- Publisher
381  * @{
382  */
383 
384 /**
385  * @brief Creates a Publisher node and initialises it on the given URL.
386  *
387  * @details
388  * Allocates a @c vlink::Publisher<vlink::Bytes> on the heap and stores its
389  * pointer in @p handle. Supply @p schema_info to configure @c ser + @c schema
390  * before the underlying node is initialised; pass @c NULL to leave both unset.
391  *
392  * @param url VLink topic URL (e.g. @c "dds://my/topic"). Must not be @c NULL.
393  * @param schema_info Optional bundled @c ser + @c schema metadata.
394  * @param handle Output handle. Must not be @c NULL.
395  * @return @c VLINK_RET_NO_ERROR on success; @c VLINK_RET_INVALID_ERROR when
396  * @p url or @p handle is @c NULL, when @p schema_info is only
397  * partially filled, or when @c schema_info->schema is invalid;
398  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
399  * @c VLINK_RET_RUNTIME_ERROR if construction throws.
400  *
401  * @note Caller owns the handle and must release it through
402  * @c vlink_destroy_publisher(). Not thread-safe with concurrent
403  * create/destroy on the same handle.
404  */
405 VLINK_C_API_EXPORT int vlink_create_publisher(const char* url, const vlink_schema_info_t* schema_info,
406  vlink_publisher_handle_t* handle);
407 
408 /**
409  * @brief Destroys a Publisher node and releases every associated resource.
410  *
411  * @param handle Publisher handle to destroy. Must not be @c NULL.
412  * @return @c VLINK_RET_NO_ERROR on success; @c VLINK_RET_INVALID_ERROR
413  * when @p handle or its @c native_handle is @c NULL.
414  *
415  * @note Must not be called concurrently with any other operation on the same
416  * handle.
417  */
419 
420 /**
421  * @brief Checks whether at least one Subscriber has matched this Publisher.
422  *
423  * @param handle Publisher handle.
424  * @return @c VLINK_RET_NO_ERROR if subscribers are present;
425  * @c VLINK_RET_UNEXPECTED_ERROR when none are matched yet;
426  * @c VLINK_RET_INVALID_ERROR on bad handle.
427  *
428  * @note Thread-safe.
429  */
431 
432 /**
433  * @brief Blocks until at least one Subscriber matches or @p timeout_ms expires.
434  *
435  * @param handle Publisher handle.
436  * @param timeout_ms Maximum wait time in milliseconds.
437  * @return @c VLINK_RET_NO_ERROR if a subscriber matched;
438  * @c VLINK_RET_UNEXPECTED_ERROR on timeout;
439  * @c VLINK_RET_INVALID_ERROR on bad handle.
440  *
441  * @note Blocks the calling thread.
442  */
444 
445 /**
446  * @brief Registers a callback fired whenever the Subscriber connection state changes.
447  *
448  * @param handle Publisher handle.
449  * @param connect_callback Callback to invoke on every state change.
450  * @param user_data Opaque pointer forwarded to @p connect_callback.
451  * @return @c VLINK_RET_NO_ERROR on success;
452  * @c VLINK_RET_INVALID_ERROR on bad handle or a @c NULL
453  * @p connect_callback.
454  *
455  * @note The callback runs on the Publisher's internal event thread.
456  */
458  const vlink_connect_callback_t connect_callback, void* user_data);
459 
460 /**
461  * @brief Publishes a message to every matched Subscriber.
462  *
463  * @details
464  * The implementation wraps @p data in a shallow-copy @c vlink::Bytes -- zero-copy
465  * when the transport supports it. Returns @c VLINK_RET_TRANSFER_ERROR when no
466  * subscribers are matched and the publisher does not allow forced delivery.
467  *
468  * @param handle Publisher handle.
469  * @param data Payload to publish. Must remain valid until the call returns.
470  * @param size Number of bytes in @p data.
471  * @return @c VLINK_RET_NO_ERROR on success;
472  * @c VLINK_RET_TRANSFER_ERROR when publishing fails;
473  * @c VLINK_RET_INVALID_ERROR on bad handle or
474  * @p data == @c NULL with @p size > 0.
475  *
476  * @note Thread-safe with respect to other publishes on the same handle.
477  */
478 VLINK_C_API_EXPORT int vlink_publish(const vlink_publisher_handle_t handle, const uint8_t* data, const size_t size);
479 
480 /**
481  * @brief Publishes a message even when no Subscribers are matched.
482  *
483  * @details
484  * Identical to @c vlink_publish() but passes @c force=true to the underlying
485  * publisher, bypassing the subscriber-presence check. Useful for
486  * transient-local-durability or late-joining subscriber scenarios.
487  *
488  * @param handle Publisher handle.
489  * @param data Payload to publish.
490  * @param size Number of bytes in @p data.
491  * @return @c VLINK_RET_NO_ERROR on success;
492  * @c VLINK_RET_TRANSFER_ERROR on failure;
493  * @c VLINK_RET_INVALID_ERROR on bad handle or
494  * @p data == @c NULL with @p size > 0.
495  *
496  * @note Same threading guarantees as @c vlink_publish().
497  */
499  const size_t size);
500 
501 /** @} */
502 
503 ////////////////////////////////////////////////////////////////
504 /// Subscriber
505 ////////////////////////////////////////////////////////////////
506 
507 /**
508  * @name Event model -- Subscriber
509  * @{
510  */
511 
512 /**
513  * @brief Creates a Subscriber node, initialises it, and registers the message callback.
514  *
515  * @details
516  * Allocates a @c vlink::Subscriber<vlink::Bytes> and immediately calls
517  * @c listen() with @p msg_callback. The callback runs on the Subscriber's
518  * internal receive thread.
519  *
520  * @param url VLink topic URL. Must not be @c NULL.
521  * @param schema_info Optional bundled @c ser + @c schema metadata.
522  * @param handle Output handle. Must not be @c NULL.
523  * @param msg_callback Message handler. Must not be @c NULL.
524  * @param user_data Opaque pointer forwarded to @p msg_callback.
525  * @return @c VLINK_RET_NO_ERROR on success;
526  * @c VLINK_RET_INVALID_ERROR for @c NULL arguments,
527  * partially-filled @p schema_info, or invalid
528  * @c schema_info->schema;
529  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
530  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
531  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
532  *
533  * @note Caller owns the handle and must release it with
534  * @c vlink_destroy_subscriber().
535  */
536 VLINK_C_API_EXPORT int vlink_create_subscriber(const char* url, const vlink_schema_info_t* schema_info,
538  const vlink_msg_callback_t msg_callback, void* user_data);
539 
540 /**
541  * @brief Atomically creates a Subscriber, installs @c Security, and calls @c listen().
542  *
543  * @details
544  * Builds the @c vlink::Security from @p security_cfg @b before the internal
545  * @c listen() registration completes, so every inbound frame is run through
546  * @c Security::decrypt(). Security configuration is one-shot at creation -- no
547  * separate runtime entry point exists.
548  *
549  * On failure (bad URL/schema/cfg, non-decrypt-capable security state, listen
550  * failure) no resources leak; any internal handle stored before the failure is
551  * cleared.
552  *
553  * @param url VLink subscriber URL. Must not be @c NULL.
554  * @param schema_info Optional bundled @c ser + @c schema metadata.
555  * @param handle Output handle. Must not be @c NULL.
556  * @param msg_callback Message handler. Must not be @c NULL.
557  * @param user_data Opaque pointer forwarded to @p msg_callback.
558  * @param security_cfg Security configuration. Must not be @c NULL. A
559  * zero-initialised configuration uses the built-in default
560  * symmetric slot with replay protection disabled;
561  * otherwise a decrypt-capable slot is required.
562  * @return @c VLINK_RET_NO_ERROR on success;
563  * @c VLINK_RET_INVALID_ERROR on bad arguments (including a
564  * non-decrypt-capable @p security_cfg);
565  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
566  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
567  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
568  *
569  * @note Caller owns the handle and must release it with
570  * @c vlink_destroy_subscriber().
571  */
574  const vlink_msg_callback_t msg_callback, void* user_data,
575  const vlink_security_config_t* security_cfg);
576 
577 /**
578  * @brief Destroys a Subscriber node and releases every associated resource.
579  *
580  * @param handle Subscriber handle to destroy. Must not be @c NULL.
581  * @return @c VLINK_RET_NO_ERROR on success;
582  * @c VLINK_RET_INVALID_ERROR on bad handle.
583  *
584  * @note Must not be called concurrently with any other operation on the same
585  * handle.
586  */
588 
589 /** @} */
590 
591 ////////////////////////////////////////////////////////////////
592 /// Server
593 ////////////////////////////////////////////////////////////////
594 
595 /**
596  * @name Method model -- Server
597  * @{
598  */
599 
600 /**
601  * @brief Creates a Server node, initialises it, and registers the request callback.
602  *
603  * @details
604  * Allocates a @c vlink::Server<vlink::Bytes, vlink::Bytes> and calls @c listen()
605  * with an internal handler that wraps @p req_callback. The internal handler
606  * serialises request/reply state during each invocation. Call @c vlink_reply()
607  * from inside @p req_callback to set a response before the callback returns.
608  *
609  * @param url VLink service URL. Must not be @c NULL.
610  * @param schema_info Optional bundled @c ser + @c schema metadata.
611  * @param handle Output handle. Must not be @c NULL.
612  * @param req_callback Request handler. Must not be @c NULL.
613  * @param user_data Opaque pointer forwarded to @p req_callback.
614  * @return @c VLINK_RET_NO_ERROR on success;
615  * @c VLINK_RET_INVALID_ERROR for @c NULL arguments,
616  * partially-filled @p schema_info, or invalid
617  * @c schema_info->schema;
618  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
619  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
620  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
621  *
622  * @note Caller owns the handle and must release it with @c vlink_destroy_server().
623  */
624 VLINK_C_API_EXPORT int vlink_create_server(const char* url, const vlink_schema_info_t* schema_info,
625  vlink_server_handle_t* handle, const vlink_req_callback_t req_callback,
626  void* user_data);
627 
628 /**
629  * @brief Atomically creates a Server, installs @c Security, and calls @c listen().
630  *
631  * @details
632  * Builds the @c vlink::Security from @p security_cfg @b before the internal
633  * @c listen() registration completes. Inbound requests are decrypted through
634  * @c Security::decrypt(); replies written via @c vlink_reply() are encrypted
635  * through @c Security::encrypt(). Without a @c vlink_reply() call, or with
636  * @c size == @c 0, the request still completes with an empty response so the C
637  * API reply protocol is preserved. When @c security_cfg->advanced.aad_context
638  * is empty the wrapper binds security to @c url|ser|schema; absent
639  * @p schema_info defaults to the C API @c Bytes binding @c url||VLINK_SCHEMA_RAW.
640  * Security configuration is one-shot at creation -- no separate runtime entry
641  * point exists.
642  *
643  * @param url VLink service URL. Must not be @c NULL.
644  * @param schema_info Optional bundled @c ser + @c schema metadata.
645  * @param handle Output handle. Must not be @c NULL.
646  * @param req_callback Request handler. Must not be @c NULL.
647  * @param user_data Opaque pointer forwarded to @p req_callback.
648  * @param security_cfg Security configuration. Must not be @c NULL. A
649  * zero-initialised configuration uses the built-in default
650  * symmetric slot with replay protection disabled;
651  * otherwise both encrypt- and decrypt-capable slots are
652  * required.
653  * @return @c VLINK_RET_NO_ERROR on success;
654  * @c VLINK_RET_INVALID_ERROR on bad arguments;
655  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
656  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
657  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
658  *
659  * @note Caller owns the handle and must release it with @c vlink_destroy_server().
660  */
661 VLINK_C_API_EXPORT int vlink_create_secure_server(const char* url, const vlink_schema_info_t* schema_info,
662  vlink_server_handle_t* handle,
663  const vlink_req_callback_t req_callback, void* user_data,
664  const vlink_security_config_t* security_cfg);
665 
666 /**
667  * @brief Destroys a Server node and frees every internal resource, including the
668  * request/reply coordination state.
669  *
670  * @param handle Server handle to destroy. Must not be @c NULL.
671  * @return @c VLINK_RET_NO_ERROR on success;
672  * @c VLINK_RET_INVALID_ERROR on bad handle.
673  *
674  * @note Must not be called concurrently with any other operation on the same
675  * handle.
676  */
678 
679 /**
680  * @brief Provides the response data for the current in-progress RPC request.
681  *
682  * @details
683  * Must be called from inside @c vlink_req_callback_t while the internal request
684  * context is active. The response is copied into owned internal storage, or
685  * encrypted into owned internal storage for secure servers. A @p size of @c 0
686  * is accepted and produces the protocol's empty response.
687  *
688  * @param handle Server handle. Must not be @c NULL.
689  * @param data Response payload bytes.
690  * @param size Number of bytes in @p data.
691  * @return @c VLINK_RET_NO_ERROR on success;
692  * @c VLINK_RET_INVALID_ERROR on bad handle or
693  * @p data == @c NULL with @p size > 0;
694  * @c VLINK_RET_RUNTIME_ERROR when no pending request is in
695  * progress;
696  * @c VLINK_RET_MEMORY_ERROR if internal allocation fails;
697  * @c VLINK_RET_TRANSFER_ERROR if secure response encryption
698  * fails.
699  *
700  * @note Only valid inside the @c vlink_req_callback_t.
701  */
702 VLINK_C_API_EXPORT int vlink_reply(vlink_server_handle_t* handle, const uint8_t* data, const size_t size);
703 
704 /** @} */
705 
706 ////////////////////////////////////////////////////////////////
707 /// Client
708 ////////////////////////////////////////////////////////////////
709 
710 /**
711  * @name Method model -- Client
712  * @{
713  */
714 
715 /**
716  * @brief Creates a Client node and initialises it on the given URL.
717  *
718  * @param url VLink service URL. Must not be @c NULL.
719  * @param schema_info Optional bundled @c ser + @c schema metadata.
720  * @param handle Output handle. Must not be @c NULL.
721  * @return @c VLINK_RET_NO_ERROR on success;
722  * @c VLINK_RET_INVALID_ERROR for @c NULL @p url / @p handle,
723  * partially-filled @p schema_info, or invalid
724  * @c schema_info->schema;
725  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
726  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
727  *
728  * @note Caller owns the handle and must release it with @c vlink_destroy_client().
729  */
730 VLINK_C_API_EXPORT int vlink_create_client(const char* url, const vlink_schema_info_t* schema_info,
731  vlink_client_handle_t* handle);
732 
733 /**
734  * @brief Destroys a Client node and releases every associated resource.
735  *
736  * @param handle Client handle to destroy. Must not be @c NULL.
737  * @return @c VLINK_RET_NO_ERROR on success;
738  * @c VLINK_RET_INVALID_ERROR on bad handle.
739  *
740  * @note Must not be called concurrently with any other operation on the same
741  * handle.
742  */
744 
745 /**
746  * @brief Checks whether the Client is connected to a Server.
747  *
748  * @param handle Client handle.
749  * @return @c VLINK_RET_NO_ERROR if connected;
750  * @c VLINK_RET_UNEXPECTED_ERROR if not yet connected;
751  * @c VLINK_RET_INVALID_ERROR on bad handle.
752  *
753  * @note Thread-safe.
754  */
756 
757 /**
758  * @brief Blocks until a Server is available or @p timeout_ms expires.
759  *
760  * @param handle Client handle.
761  * @param timeout_ms Maximum wait time in milliseconds.
762  * @return @c VLINK_RET_NO_ERROR if connected;
763  * @c VLINK_RET_UNEXPECTED_ERROR on timeout;
764  * @c VLINK_RET_INVALID_ERROR on bad handle.
765  *
766  * @note Blocks the calling thread.
767  */
768 VLINK_C_API_EXPORT int vlink_wait_for_server(const vlink_client_handle_t handle, const int timeout_ms);
769 
770 /**
771  * @brief Registers a callback fired whenever the Server connection state changes.
772  *
773  * @param handle Client handle.
774  * @param connect_callback Callback to invoke on every state change.
775  * @param user_data Opaque pointer forwarded to @p connect_callback.
776  * @return @c VLINK_RET_NO_ERROR on success;
777  * @c VLINK_RET_INVALID_ERROR on bad handle or a @c NULL
778  * @p connect_callback.
779  *
780  * @note The callback runs on the Client's internal event thread.
781  */
783  const vlink_connect_callback_t connect_callback, void* user_data);
784 
785 /**
786  * @brief Sends an RPC request and registers a callback for the response.
787  *
788  * @details
789  * Internally invokes @c vlink::Client::invoke() with a shallow-copy @c Bytes
790  * wrapping @p data. @p resp_callback fires asynchronously on the underlying
791  * @c vlink::Client callback context once the Server reply arrives. Pass
792  * @c NULL for @p resp_callback when the response is not needed. Secure clients
793  * treat an empty transport response as the protocol's empty response and do not
794  * route it through @c Security::decrypt().
795  *
796  * @param handle Client handle.
797  * @param data Request payload. Must remain valid until the call returns.
798  * @param size Number of bytes in @p data.
799  * @param resp_callback Callback invoked with the response, or @c NULL.
800  * @param user_data Opaque pointer forwarded to @p resp_callback.
801  * @return @c VLINK_RET_NO_ERROR on success;
802  * @c VLINK_RET_TRANSFER_ERROR if encryption or invoke
803  * fails;
804  * @c VLINK_RET_INVALID_ERROR on bad handle or
805  * @p data == @c NULL with @p size > 0.
806  *
807  * @note Thread-safe. The @p resp_callback may fire on a transport-managed
808  * thread.
809  */
810 VLINK_C_API_EXPORT int vlink_invoke(const vlink_client_handle_t handle, const uint8_t* data, const size_t size,
811  const vlink_resp_callback_t resp_callback, void* user_data);
812 
813 /** @} */
814 
815 ////////////////////////////////////////////////////////////////
816 /// Setter
817 ////////////////////////////////////////////////////////////////
818 
819 /**
820  * @name Field model -- Setter
821  * @{
822  */
823 
824 /**
825  * @brief Creates a Setter node and initialises it on the given URL.
826  *
827  * @param url VLink field URL. Must not be @c NULL.
828  * @param schema_info Optional bundled @c ser + @c schema metadata.
829  * @param handle Output handle. Must not be @c NULL.
830  * @return @c VLINK_RET_NO_ERROR on success;
831  * @c VLINK_RET_INVALID_ERROR for @c NULL @p url / @p handle,
832  * partially-filled @p schema_info, or invalid
833  * @c schema_info->schema;
834  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
835  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
836  *
837  * @note Caller owns the handle and must release it with @c vlink_destroy_setter().
838  */
839 VLINK_C_API_EXPORT int vlink_create_setter(const char* url, const vlink_schema_info_t* schema_info,
840  vlink_setter_handle_t* handle);
841 
842 /**
843  * @brief Destroys a Setter node and releases every associated resource.
844  *
845  * @param handle Setter handle to destroy. Must not be @c NULL.
846  * @return @c VLINK_RET_NO_ERROR on success;
847  * @c VLINK_RET_INVALID_ERROR on bad handle.
848  *
849  * @note Must not be called concurrently with any other operation on the same
850  * handle.
851  */
853 
854 /**
855  * @brief Publishes the latest field value.
856  *
857  * @details
858  * The new value overwrites the previous one held by every matched Getter. The
859  * input buffer is only read during the @c vlink_set() call. The underlying
860  * @c Setter<vlink::Bytes> keeps its latest-value cache as an owned @c Bytes
861  * copy, so callers may reuse or release @p data once the function returns.
862  *
863  * @param handle Setter handle.
864  * @param data New field value bytes. Must remain valid for the call.
865  * @param size Number of bytes in @p data.
866  * @return @c VLINK_RET_NO_ERROR on success;
867  * @c VLINK_RET_TRANSFER_ERROR if secure encryption fails;
868  * @c VLINK_RET_INVALID_ERROR on bad handle or
869  * @p data == @c NULL with @p size > 0.
870  *
871  * @note Thread-safe with respect to other @c vlink_set() calls on the same handle.
872  */
873 VLINK_C_API_EXPORT int vlink_set(const vlink_setter_handle_t handle, const uint8_t* data, const size_t size);
874 
875 /** @} */
876 
877 ////////////////////////////////////////////////////////////////
878 /// Getter
879 ////////////////////////////////////////////////////////////////
880 
881 /**
882  * @name Field model -- Getter
883  * @{
884  */
885 
886 /**
887  * @brief Creates a Getter node, initialises it, and optionally registers a change callback.
888  *
889  * @details
890  * Allocates a @c vlink::Getter<vlink::Bytes>. When @p msg_callback is non-NULL,
891  * @c listen() is called and the callback fires on every value update. When
892  * @p msg_callback is @c NULL the Getter operates in polling mode -- use
893  * @c vlink_get() to retrieve the latest value.
894  *
895  * @param url VLink field URL. Must not be @c NULL.
896  * @param schema_info Optional bundled @c ser + @c schema metadata.
897  * @param handle Output handle. Must not be @c NULL.
898  * @param msg_callback Push-mode callback, or @c NULL for poll mode.
899  * @param user_data Opaque pointer forwarded to @p msg_callback.
900  * @return @c VLINK_RET_NO_ERROR on success;
901  * @c VLINK_RET_INVALID_ERROR for @c NULL @p url / @p handle,
902  * partially-filled @p schema_info, or invalid
903  * @c schema_info->schema;
904  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
905  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
906  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
907  *
908  * @note Caller owns the handle and must release it with @c vlink_destroy_getter().
909  */
910 VLINK_C_API_EXPORT int vlink_create_getter(const char* url, const vlink_schema_info_t* schema_info,
911  vlink_getter_handle_t* handle, const vlink_msg_callback_t msg_callback,
912  void* user_data);
913 
914 /**
915  * @brief Atomically creates a Getter, installs @c Security, and calls @c listen().
916  *
917  * @details
918  * Builds the @c vlink::Security from @p security_cfg @b before the internal
919  * push-mode @c listen() registration completes. Polling-mode Getters
920  * (@p msg_callback == @c NULL) see the attached @c Security from the very first
921  * @c vlink_get() call. A secure polling Getter caches the last authenticated
922  * ciphertext/plaintext pair internally so repeated @c vlink_get() calls for the
923  * same latest field value return the cached plaintext without tripping replay
924  * protection. Fresh inbound frames still flow through @c Security::decrypt().
925  * Security configuration is one-shot at creation -- no separate runtime entry
926  * point exists.
927  *
928  * @param url VLink field URL. Must not be @c NULL.
929  * @param schema_info Optional bundled @c ser + @c schema metadata.
930  * @param handle Output handle. Must not be @c NULL.
931  * @param msg_callback Push-mode callback, or @c NULL for poll mode.
932  * @param user_data Opaque pointer forwarded to @p msg_callback.
933  * @param security_cfg Security configuration. Must not be @c NULL. A
934  * zero-initialised configuration uses the built-in default
935  * symmetric slot with replay protection disabled;
936  * otherwise a decrypt-capable slot is required.
937  * @return @c VLINK_RET_NO_ERROR on success;
938  * @c VLINK_RET_INVALID_ERROR on bad arguments;
939  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
940  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
941  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
942  *
943  * @note Caller owns the handle and must release it with @c vlink_destroy_getter().
944  */
945 VLINK_C_API_EXPORT int vlink_create_secure_getter(const char* url, const vlink_schema_info_t* schema_info,
946  vlink_getter_handle_t* handle,
947  const vlink_msg_callback_t msg_callback, void* user_data,
948  const vlink_security_config_t* security_cfg);
949 
950 /**
951  * @brief Destroys a Getter node and releases every associated resource.
952  *
953  * @param handle Getter handle to destroy. Must not be @c NULL.
954  * @return @c VLINK_RET_NO_ERROR on success;
955  * @c VLINK_RET_INVALID_ERROR on bad handle.
956  *
957  * @note Must not be called concurrently with any other operation on the same
958  * handle.
959  */
961 
962 /**
963  * @brief Retrieves the latest field value into a caller-provided buffer.
964  *
965  * @details
966  * Copies the current cached value into @p data. On entry @c *size must hold
967  * the buffer capacity; on success it is updated to the actual byte count. When
968  * the buffer is too small the function returns @c VLINK_RET_MEMORY_ERROR and
969  * writes the required byte count into @c *size so the caller can allocate and
970  * retry. @p data is left unmodified in the error case.
971  *
972  * @param handle Getter handle.
973  * @param data Output buffer. Must not be @c NULL.
974  * @param size In/out: buffer capacity on entry; actual or required size on
975  * exit. Must not be @c NULL.
976  * @return @c VLINK_RET_NO_ERROR on success;
977  * @c VLINK_RET_TRANSFER_ERROR if no value is available yet;
978  * @c VLINK_RET_MEMORY_ERROR if @c *size is too small (required
979  * size written back);
980  * @c VLINK_RET_INVALID_ERROR on bad arguments.
981  *
982  * @note Thread-safe.
983  */
984 VLINK_C_API_EXPORT int vlink_get(const vlink_getter_handle_t handle, uint8_t* data, size_t* size);
985 
986 /** @} */
987 
988 ////////////////////////////////////////////////////////////////
989 /// Security
990 ////////////////////////////////////////////////////////////////
991 
992 /**
993  * @name Security -- standalone Security handle and node-side helpers
994  * @{
995  */
996 
997 /**
998  * @brief Opaque handle for a standalone @c Security instance.
999  *
1000  * @details
1001  * Wraps a heap-allocated @c vlink::Security that performs authenticated,
1002  * message-level encryption. Construct via @c vlink_security_create() and
1003  * destroy via @c vlink_security_destroy(). The same handle drives both
1004  * @c vlink_security_encrypt() and @c vlink_security_decrypt() as long as the
1005  * configuration supplies the matching key material for each direction.
1006  */
1007 typedef struct vlink_security* vlink_security_handle_t;
1008 
1009 /**
1010  * @brief Optional user-provided encrypt/decrypt callback for @c vlink_security_config_t.
1011  *
1012  * @details
1013  * Installing both @c encrypt_callback and @c decrypt_callback overrides the
1014  * built-in AEAD path entirely. Implementations must allocate @c *out with
1015  * @c malloc (or another allocator compatible with @c free) and write the byte
1016  * count into @c *out_size. The C API releases the buffer with @c free() after
1017  * copying its contents into the destination supplied to
1018  * @c vlink_security_encrypt() / @c vlink_security_decrypt(). Custom
1019  * encrypt/decrypt callbacks attached to the same security handle are serialised
1020  * by VLink; callbacks shared across handles must protect their own shared state.
1021  *
1022  * @param in Plaintext (encrypt) or ciphertext (decrypt) input pointer.
1023  * @param in_size Number of bytes available at @p in.
1024  * @param out Output parameter receiving a freshly allocated buffer.
1025  * @param out_size Output parameter receiving the byte count of @p out.
1026  * @param user Opaque pointer supplied via @c callback_user_data.
1027  * @return @c 0 on success, non-zero on failure.
1028  *
1029  * @note On Windows the buffer returned through @p out is released inside the
1030  * vlink shared library using its own CRT @c free(). The callback
1031  * implementation MUST therefore allocate @p *out with the matching CRT
1032  * (e.g. the @c msvcrt / UCRT @c malloc linked into the vlink DLL).
1033  * Mixing CRTs across DLL boundaries leads to heap corruption. When in
1034  * doubt, build the callback host with the same toolchain/runtime as the
1035  * vlink shared library, or expose your own @c free helper through
1036  * @c callback_user_data.
1037  */
1038 typedef int (*vlink_security_callback_t)(const uint8_t* in, size_t in_size, uint8_t** out, size_t* out_size,
1039  void* user);
1040 
1041 /**
1042  * @brief Low-frequency security options: AAD, replay protection, and signing keys.
1043  */
1044 typedef struct {
1045  const char* aad_context; /**< AEAD context binding (<=65535 bytes), or @c NULL. */
1046  uint32_t replay_window; /**< Replay window size; @c 0 disables replay checks. */
1047  const char* signing_key_pem; /**< Local RSA private key (PEM) for RSA-PSS signing, or @c NULL. */
1048  const char* verify_key_pem; /**< Peer RSA public key (PEM) for RSA-PSS verification, or @c NULL. */
1050 
1051 /**
1052  * @brief Configuration aggregate for @c vlink_security_create() and the
1053  * @c vlink_create_secure_*() entry points.
1054  *
1055  * @details
1056  * Each field maps onto the field of the same name on @c vlink::Security::Config.
1057  * String fields are null-terminated; @c NULL or empty strings disable the
1058  * matching explicit field. When every explicit cryptographic field is empty,
1059  * the configuration maps to the built-in default symmetric slot, provided
1060  * built-in algorithms are enabled. A zero-initialised aggregate leaves
1061  * @c advanced.replay_window at @c 0, so replay checks are disabled until the
1062  * caller sets the field or calls @c vlink_security_config_init().
1063  * @c pbkdf2_salt is a raw byte buffer of @c pbkdf2_salt_size bytes; pass
1064  * @c NULL / @c 0 to leave it empty. Setting @c pbkdf2_iterations to @c 0
1065  * selects the default (200000).
1066  *
1067  * @par Mode Selection
1068  * - When both @c encrypt_callback and @c decrypt_callback are non-NULL the
1069  * custom-callback path overrides every other slot.
1070  * - When @c public_key_pem / @c private_key_pem are installed the RSA hybrid
1071  * path drives outbound / inbound messages.
1072  * - Otherwise the symmetric path is used with a key derived from @c key,
1073  * @c passphrase + @c pbkdf2_salt, or the built-in default.
1074  *
1075  * @note @c key / @c passphrase are the symmetric key sources. @c advanced
1076  * holds low-frequency options such as AAD, replay protection, and signing.
1077  */
1079  const char* key; /**< Raw symmetric seed (SHA-256 truncated), or @c NULL. */
1080  const char* passphrase; /**< Low-entropy passphrase fed into PBKDF2-HMAC-SHA256, or @c NULL.*/
1081  const uint8_t* pbkdf2_salt; /**< PBKDF2 salt (>=16 bytes), or @c NULL. */
1082  size_t pbkdf2_salt_size; /**< Byte count of @c pbkdf2_salt. */
1083  uint32_t pbkdf2_iterations; /**< PBKDF2 iteration count; @c 0 means default (200000). */
1084  const char* public_key_pem; /**< Peer RSA public key (PEM) for outbound encryption, or @c NULL. */
1085  const char* private_key_pem; /**< Local RSA private key (PEM) for inbound decryption, or @c NULL.*/
1086  vlink_security_callback_t encrypt_callback; /**< Custom encrypt callback, or @c NULL. */
1087  vlink_security_callback_t decrypt_callback; /**< Custom decrypt callback, or @c NULL. */
1088  void* callback_user_data; /**< Opaque pointer forwarded to both callbacks. */
1089  vlink_security_advanced_config_t advanced; /**< Low-frequency security options. */
1090 };
1091 
1092 /**
1093  * @brief Zero-initialises @p cfg and applies the C API default PBKDF2 / replay settings.
1094  *
1095  * @details
1096  * Convenience initialiser that avoids relying on @c {0} aggregate initialisation
1097  * in client code. Once it returns, every string pointer is @c NULL, the salt
1098  * buffer is empty, both callbacks and @c callback_user_data are @c NULL,
1099  * @c pbkdf2_iterations equals 200000, and @c advanced.replay_window equals 4096.
1100  * Set @c advanced.replay_window back to @c 0 to disable replay checks
1101  * explicitly. Safe to call on a stack variable before populating fields.
1102  * Passing the initialised configuration to a Security constructor uses the
1103  * built-in default symmetric slot when built-in algorithms are enabled.
1104  *
1105  * @par Example
1106  * @code
1107  * vlink_security_config_t cfg;
1108  * vlink_security_config_init(&cfg);
1109  * cfg.passphrase = "correct horse battery staple";
1110  * cfg.pbkdf2_salt = my_salt_bytes;
1111  * cfg.pbkdf2_salt_size = my_salt_size;
1112  * @endcode
1113  *
1114  * @param cfg Configuration aggregate to initialise. No-op when @p cfg is @c NULL.
1115  *
1116  * @note Safe to call on a freshly declared stack variable.
1117  */
1119 
1120 /**
1121  * @brief Creates a standalone @c Security instance from @p cfg.
1122  *
1123  * @details
1124  * Allocates a @c vlink::Security on the heap. When @p cfg is @c NULL the call
1125  * returns @c NULL and logs a warning. A zero-initialised @p cfg uses the
1126  * built-in default symmetric slot when built-in algorithms are enabled, but it
1127  * leaves @c advanced.replay_window at @c 0 so replay protection is disabled.
1128  * Call @c vlink_security_config_init() to obtain the C API default PBKDF2/replay
1129  * settings. Invalid PEM fields or weak RSA keys are logged via @c VLOG_W and
1130  * the offending slot is left empty as long as at least one other slot validated.
1131  *
1132  * @par Example
1133  * @code
1134  * vlink_security_config_t cfg;
1135  * vlink_security_config_init(&cfg);
1136  * cfg.passphrase = "correct horse battery staple";
1137  * cfg.pbkdf2_salt = my_salt_bytes;
1138  * cfg.pbkdf2_salt_size = my_salt_size;
1139  *
1140  * vlink_security_handle_t sec = vlink_security_create(&cfg);
1141  *
1142  * uint8_t* cipher = NULL;
1143  * size_t cipher_size = 0;
1144  * vlink_security_encrypt(sec, plain, plain_size, &cipher, &cipher_size);
1145  * vlink_security_free_buffer(cipher);
1146  *
1147  * vlink_security_destroy(sec);
1148  * @endcode
1149  *
1150  * @param cfg Configuration aggregate. A zero-initialised aggregate uses the
1151  * built-in default symmetric slot with replay protection disabled;
1152  * otherwise provide a callback pair, symmetric key/passphrase, or
1153  * RSA PEM.
1154  * @return New @c vlink_security_handle_t handle; @c NULL on @c NULL @p cfg,
1155  * on a configuration with no usable cryptographic slot after
1156  * validation, on allocation failure, or on a C++ construction
1157  * exception.
1158  *
1159  * @note Caller owns the handle and must release it via @c vlink_security_destroy().
1160  */
1162 
1163 /**
1164  * @brief Destroys a standalone @c Security instance.
1165  *
1166  * @details
1167  * Safe to call with @c NULL @p sec (no-op). Symmetric key material is zeroised
1168  * in place inside the @c vlink::Security destructor before the buffer is freed.
1169  *
1170  * @param sec Handle returned by @c vlink_security_create(), or @c NULL.
1171  */
1173 
1174 /**
1175  * @brief Encrypts a plaintext buffer using the active mode configured on @p sec.
1176  *
1177  * @details
1178  * The ciphertext lands in a freshly allocated buffer that the caller owns;
1179  * release it with @c vlink_security_free_buffer(). Following the underlying
1180  * @c Security::encrypt() contract, empty inputs (@c in == @c NULL or
1181  * @c in_size == @c 0) are rejected with @c VLINK_RET_INVALID_ERROR.
1182  *
1183  * @param sec Security handle.
1184  * @param in Plaintext input bytes.
1185  * @param in_size Number of bytes available at @p in.
1186  * @param out Output pointer receiving the allocated ciphertext buffer.
1187  * Must not be @c NULL.
1188  * @param out_size Output pointer receiving the ciphertext byte count. Must
1189  * not be @c NULL.
1190  * @return @c VLINK_RET_NO_ERROR on success;
1191  * @c VLINK_RET_INVALID_ERROR on bad arguments;
1192  * @c VLINK_RET_MEMORY_ERROR if output allocation fails;
1193  * @c VLINK_RET_TRANSFER_ERROR if @c Security::encrypt() fails.
1194  *
1195  * @note Caller owns @c *out and must release it via @c vlink_security_free_buffer().
1196  */
1197 VLINK_C_API_EXPORT int vlink_security_encrypt(vlink_security_handle_t sec, const uint8_t* in, const size_t in_size,
1198  uint8_t** out, size_t* out_size);
1199 
1200 /**
1201  * @brief Decrypts a ciphertext buffer using the active mode configured on @p sec.
1202  *
1203  * @details
1204  * The plaintext lands in a freshly allocated buffer that the caller owns;
1205  * release it with @c vlink_security_free_buffer(). Empty inputs are rejected
1206  * with @c VLINK_RET_INVALID_ERROR (a valid built-in ciphertext carries an
1207  * envelope, tag, and at least one ciphertext byte). Authentication failures --
1208  * tampered ciphertext, wrong key, invalid signature, or replay -- are reported
1209  * as @c VLINK_RET_TRANSFER_ERROR.
1210  *
1211  * @param sec Security handle.
1212  * @param in Ciphertext input bytes.
1213  * @param in_size Number of bytes available at @p in.
1214  * @param out Output pointer receiving the allocated plaintext buffer.
1215  * Must not be @c NULL.
1216  * @param out_size Output pointer receiving the plaintext byte count. Must not
1217  * be @c NULL.
1218  * @return @c VLINK_RET_NO_ERROR on success;
1219  * @c VLINK_RET_INVALID_ERROR on bad arguments;
1220  * @c VLINK_RET_MEMORY_ERROR if output allocation fails;
1221  * @c VLINK_RET_TRANSFER_ERROR if @c Security::decrypt() fails.
1222  *
1223  * @note Caller owns @c *out and must release it via @c vlink_security_free_buffer().
1224  */
1225 VLINK_C_API_EXPORT int vlink_security_decrypt(vlink_security_handle_t sec, const uint8_t* in, const size_t in_size,
1226  uint8_t** out, size_t* out_size);
1227 
1228 /**
1229  * @brief Releases a buffer returned by @c vlink_security_encrypt() or
1230  * @c vlink_security_decrypt().
1231  *
1232  * @details
1233  * Safe to call with @c NULL @p buf (no-op). Buffers obtained from any other
1234  * source must not be freed through this function.
1235  *
1236  * @param buf Buffer pointer previously written by an encrypt/decrypt call.
1237  */
1239 
1240 /**
1241  * @brief Atomically creates a Publisher and installs @c Security.
1242  *
1243  * @details
1244  * Builds the @c vlink::Security from @p security_cfg @b before @c init() returns,
1245  * so the encrypt path is wired the first time @c vlink_publish() is called.
1246  * Security configuration is one-shot at creation -- no separate
1247  * @c enable_security() entry point exists.
1248  *
1249  * @param url VLink topic URL. Must not be @c NULL.
1250  * @param schema_info Optional bundled @c ser + @c schema metadata.
1251  * @param handle Output handle. Must not be @c NULL.
1252  * @param security_cfg Security configuration. Must not be @c NULL. A
1253  * zero-initialised configuration uses the built-in default
1254  * symmetric slot with replay protection disabled;
1255  * otherwise an encrypt-capable slot is required.
1256  * @return @c VLINK_RET_NO_ERROR on success;
1257  * @c VLINK_RET_INVALID_ERROR on bad arguments (including a
1258  * non-encrypt-capable @p security_cfg);
1259  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1260  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1261  *
1262  * @note Caller owns the handle and must release it with @c vlink_destroy_publisher().
1263  */
1265  vlink_publisher_handle_t* handle,
1266  const vlink_security_config_t* security_cfg);
1267 
1268 /**
1269  * @brief Atomically creates a Client and installs @c Security.
1270  *
1271  * @details
1272  * Builds the @c vlink::Security from @p security_cfg @b before @c init() returns,
1273  * so outbound requests through @c vlink_invoke() are encrypted from the very
1274  * first call and inbound responses are decrypted before @c vlink_resp_callback_t
1275  * fires.
1276  *
1277  * @param url VLink service URL. Must not be @c NULL.
1278  * @param schema_info Optional bundled @c ser + @c schema metadata.
1279  * @param handle Output handle. Must not be @c NULL.
1280  * @param security_cfg Security configuration. Must not be @c NULL. A
1281  * zero-initialised configuration uses the built-in default
1282  * symmetric slot with replay protection disabled;
1283  * otherwise both encrypt- and decrypt-capable slots are
1284  * required.
1285  * @return @c VLINK_RET_NO_ERROR on success;
1286  * @c VLINK_RET_INVALID_ERROR on bad arguments;
1287  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1288  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1289  *
1290  * @note Caller owns the handle and must release it with @c vlink_destroy_client().
1291  */
1293  vlink_client_handle_t* handle,
1294  const vlink_security_config_t* security_cfg);
1295 
1296 /**
1297  * @brief Atomically creates a Setter and installs @c Security.
1298  *
1299  * @details
1300  * Builds the @c vlink::Security from @p security_cfg @b before @c init() returns,
1301  * so the encrypt path is wired the first time @c vlink_set() is called. The
1302  * Setter's normal latest-value cache owns the encrypted @c Bytes payload, so
1303  * late-joining Getters receive the current value without depending on the
1304  * caller's input buffer.
1305  *
1306  * @param url VLink field URL. Must not be @c NULL.
1307  * @param schema_info Optional bundled @c ser + @c schema metadata.
1308  * @param handle Output handle. Must not be @c NULL.
1309  * @param security_cfg Security configuration. Must not be @c NULL. A
1310  * zero-initialised configuration uses the built-in default
1311  * symmetric slot with replay protection disabled;
1312  * otherwise an encrypt-capable slot is required.
1313  * @return @c VLINK_RET_NO_ERROR on success;
1314  * @c VLINK_RET_INVALID_ERROR on bad arguments;
1315  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1316  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1317  *
1318  * @note Caller owns the handle and must release it with @c vlink_destroy_setter().
1319  */
1321  vlink_setter_handle_t* handle,
1322  const vlink_security_config_t* security_cfg);
1323 
1324 /** @} */
1325 
1326 /**
1327  * @name Transport-layer TLS (SSL options)
1328  * @{
1329  */
1330 
1331 /**
1332  * @brief Transport-layer TLS configuration aggregate.
1333  *
1334  * @details
1335  * Mirrors @c vlink::SslOptions. Populated by the caller and passed to the
1336  * @c vlink_create_*_with_ssl_options() entry points. String fields are
1337  * null-terminated; @c NULL or empty strings disable the matching slot.
1338  * @c verify_peer uses C semantics -- non-zero enables peer-certificate
1339  * verification, @c 0 disables it. Transport backends consider TLS enabled once
1340  * at least @c ca_file or @c cert_file is non-empty.
1341  *
1342  * @note This is the transport-layer (channel) TLS configuration. For
1343  * application-layer per-message AEAD encryption see
1344  * @c vlink_security_config_t.
1345  */
1346 typedef struct {
1347  int verify_peer; /**< Non-zero = verify peer certificate (default); @c 0 = skip. */
1348  const char* ca_file; /**< CA certificate file path (PEM), or @c NULL. */
1349  const char* cert_file; /**< Client certificate file path (PEM), or @c NULL. */
1350  const char* key_file; /**< Client private key file path (PEM), or @c NULL. */
1351  const char* key_password; /**< Passphrase for the encrypted private key, or @c NULL. */
1352  const char* server_name; /**< SNI server name override, or @c NULL. */
1353  const char* ciphers; /**< Cipher suite string (OpenSSL format), or @c NULL. */
1355 
1356 /**
1357  * @brief Zero-initialises @p opt and applies the canonical TLS defaults.
1358  *
1359  * @details
1360  * After the call every string pointer is @c NULL and @c verify_peer equals @c 1
1361  * (matching @c vlink::SslOptions defaults). Safe to call on a stack variable
1362  * before populating the fields you actually need.
1363  *
1364  * @par Example
1365  * @code
1366  * vlink_ssl_options_t opt;
1367  * vlink_ssl_options_init(&opt);
1368  * opt.ca_file = "/etc/certs/ca.pem";
1369  * opt.cert_file = "/etc/certs/client.pem";
1370  * opt.key_file = "/etc/certs/client-key.pem";
1371  * vlink_create_publisher_with_ssl_options("mqtt://sensor/data", &schema, &pub, &opt);
1372  * @endcode
1373  *
1374  * @param opt Options aggregate to initialise. No-op when @p opt is @c NULL.
1375  */
1377 
1378 /**
1379  * @brief Creates a Publisher and applies TLS options before transport initialisation.
1380  *
1381  * @param url VLink topic URL. Must not be @c NULL.
1382  * @param schema_info Optional bundled @c ser + @c schema metadata.
1383  * @param handle Output handle. Must not be @c NULL.
1384  * @param opt TLS options. Must not be @c NULL.
1385  * @return @c VLINK_RET_NO_ERROR on success;
1386  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1387  * @p opt == @c NULL;
1388  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1389  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1390  *
1391  * @note Caller owns the handle and must release it with @c vlink_destroy_publisher().
1392  */
1394  vlink_publisher_handle_t* handle,
1395  const vlink_ssl_options_t* opt);
1396 
1397 /**
1398  * @brief Creates a Subscriber and applies TLS options before transport initialisation.
1399  *
1400  * @param url VLink topic URL. Must not be @c NULL.
1401  * @param schema_info Optional bundled @c ser + @c schema metadata.
1402  * @param handle Output handle. Must not be @c NULL.
1403  * @param msg_callback Message handler. Must not be @c NULL.
1404  * @param user_data Opaque pointer forwarded to @p msg_callback.
1405  * @param opt TLS options. Must not be @c NULL.
1406  * @return @c VLINK_RET_NO_ERROR on success;
1407  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1408  * @p opt == @c NULL;
1409  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1410  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
1411  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1412  *
1413  * @note Caller owns the handle and must release it with @c vlink_destroy_subscriber().
1414  */
1416  vlink_subscriber_handle_t* handle,
1417  const vlink_msg_callback_t msg_callback,
1418  void* user_data, const vlink_ssl_options_t* opt);
1419 
1420 /**
1421  * @brief Creates a Server and applies TLS options before transport initialisation.
1422  *
1423  * @param url VLink service URL. Must not be @c NULL.
1424  * @param schema_info Optional bundled @c ser + @c schema metadata.
1425  * @param handle Output handle. Must not be @c NULL.
1426  * @param req_callback Request handler. Must not be @c NULL.
1427  * @param user_data Opaque pointer forwarded to @p req_callback.
1428  * @param opt TLS options. Must not be @c NULL.
1429  * @return @c VLINK_RET_NO_ERROR on success;
1430  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1431  * @p opt == @c NULL;
1432  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1433  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
1434  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1435  *
1436  * @note Caller owns the handle and must release it with @c vlink_destroy_server().
1437  */
1439  vlink_server_handle_t* handle,
1440  const vlink_req_callback_t req_callback, void* user_data,
1441  const vlink_ssl_options_t* opt);
1442 
1443 /**
1444  * @brief Creates a Client and applies TLS options before transport initialisation.
1445  *
1446  * @param url VLink service URL. Must not be @c NULL.
1447  * @param schema_info Optional bundled @c ser + @c schema metadata.
1448  * @param handle Output handle. Must not be @c NULL.
1449  * @param opt TLS options. Must not be @c NULL.
1450  * @return @c VLINK_RET_NO_ERROR on success;
1451  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1452  * @p opt == @c NULL;
1453  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1454  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1455  *
1456  * @note Caller owns the handle and must release it with @c vlink_destroy_client().
1457  */
1459  vlink_client_handle_t* handle,
1460  const vlink_ssl_options_t* opt);
1461 
1462 /**
1463  * @brief Creates a Setter and applies TLS options before transport initialisation.
1464  *
1465  * @param url VLink field URL. Must not be @c NULL.
1466  * @param schema_info Optional bundled @c ser + @c schema metadata.
1467  * @param handle Output handle. Must not be @c NULL.
1468  * @param opt TLS options. Must not be @c NULL.
1469  * @return @c VLINK_RET_NO_ERROR on success;
1470  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1471  * @p opt == @c NULL;
1472  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1473  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1474  *
1475  * @note Caller owns the handle and must release it with @c vlink_destroy_setter().
1476  */
1478  vlink_setter_handle_t* handle,
1479  const vlink_ssl_options_t* opt);
1480 
1481 /**
1482  * @brief Creates a Getter and applies TLS options before transport initialisation.
1483  *
1484  * @param url VLink field URL. Must not be @c NULL.
1485  * @param schema_info Optional bundled @c ser + @c schema metadata.
1486  * @param handle Output handle. Must not be @c NULL.
1487  * @param msg_callback Push-mode callback, or @c NULL for poll mode.
1488  * @param user_data Opaque pointer forwarded to @p msg_callback.
1489  * @param opt TLS options. Must not be @c NULL.
1490  * @return @c VLINK_RET_NO_ERROR on success;
1491  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1492  * @p opt == @c NULL;
1493  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1494  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
1495  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1496  *
1497  * @note Caller owns the handle and must release it with @c vlink_destroy_getter().
1498  */
1500  vlink_getter_handle_t* handle,
1501  const vlink_msg_callback_t msg_callback, void* user_data,
1502  const vlink_ssl_options_t* opt);
1503 
1504 /**
1505  * @brief Creates a secure Publisher and applies TLS options before transport initialisation.
1506  *
1507  * @param url VLink topic URL. Must not be @c NULL.
1508  * @param schema_info Optional bundled @c ser + @c schema metadata.
1509  * @param handle Output handle. Must not be @c NULL.
1510  * @param security_cfg Security configuration. Must not be @c NULL.
1511  * @param opt TLS options. Must not be @c NULL.
1512  * @return @c VLINK_RET_NO_ERROR on success;
1513  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1514  * @p security_cfg == @c NULL or @p opt == @c NULL;
1515  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1516  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1517  *
1518  * @note Caller owns the handle and must release it with @c vlink_destroy_publisher().
1519  */
1521  const vlink_schema_info_t* schema_info,
1522  vlink_publisher_handle_t* handle,
1523  const vlink_security_config_t* security_cfg,
1524  const vlink_ssl_options_t* opt);
1525 
1526 /**
1527  * @brief Creates a secure Subscriber and applies TLS options before transport initialisation.
1528  *
1529  * @param url VLink subscriber URL. Must not be @c NULL.
1530  * @param schema_info Optional bundled @c ser + @c schema metadata.
1531  * @param handle Output handle. Must not be @c NULL.
1532  * @param msg_callback Message handler. Must not be @c NULL.
1533  * @param user_data Opaque pointer forwarded to @p msg_callback.
1534  * @param security_cfg Security configuration. Must not be @c NULL.
1535  * @param opt TLS options. Must not be @c NULL.
1536  * @return @c VLINK_RET_NO_ERROR on success;
1537  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1538  * @p security_cfg == @c NULL or @p opt == @c NULL;
1539  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1540  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
1541  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1542  *
1543  * @note Caller owns the handle and must release it with @c vlink_destroy_subscriber().
1544  */
1546  const char* url, const vlink_schema_info_t* schema_info, vlink_subscriber_handle_t* handle,
1547  const vlink_msg_callback_t msg_callback, void* user_data, const vlink_security_config_t* security_cfg,
1548  const vlink_ssl_options_t* opt);
1549 
1550 /**
1551  * @brief Creates a secure Server and applies TLS options before transport initialisation.
1552  *
1553  * @param url VLink service URL. Must not be @c NULL.
1554  * @param schema_info Optional bundled @c ser + @c schema metadata.
1555  * @param handle Output handle. Must not be @c NULL.
1556  * @param req_callback Request handler. Must not be @c NULL.
1557  * @param user_data Opaque pointer forwarded to @p req_callback.
1558  * @param security_cfg Security configuration. Must not be @c NULL.
1559  * @param opt TLS options. Must not be @c NULL.
1560  * @return @c VLINK_RET_NO_ERROR on success;
1561  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1562  * @p security_cfg == @c NULL or @p opt == @c NULL;
1563  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1564  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
1565  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1566  *
1567  * @note Caller owns the handle and must release it with @c vlink_destroy_server().
1568  */
1570  const char* url, const vlink_schema_info_t* schema_info, vlink_server_handle_t* handle,
1571  const vlink_req_callback_t req_callback, void* user_data, const vlink_security_config_t* security_cfg,
1572  const vlink_ssl_options_t* opt);
1573 
1574 /**
1575  * @brief Creates a secure Client and applies TLS options before transport initialisation.
1576  *
1577  * @param url VLink service URL. Must not be @c NULL.
1578  * @param schema_info Optional bundled @c ser + @c schema metadata.
1579  * @param handle Output handle. Must not be @c NULL.
1580  * @param security_cfg Security configuration. Must not be @c NULL.
1581  * @param opt TLS options. Must not be @c NULL.
1582  * @return @c VLINK_RET_NO_ERROR on success;
1583  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1584  * @p security_cfg == @c NULL or @p opt == @c NULL;
1585  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1586  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1587  *
1588  * @note Caller owns the handle and must release it with @c vlink_destroy_client().
1589  */
1591  const vlink_schema_info_t* schema_info,
1592  vlink_client_handle_t* handle,
1593  const vlink_security_config_t* security_cfg,
1594  const vlink_ssl_options_t* opt);
1595 
1596 /**
1597  * @brief Creates a secure Setter and applies TLS options before transport initialisation.
1598  *
1599  * @param url VLink field URL. Must not be @c NULL.
1600  * @param schema_info Optional bundled @c ser + @c schema metadata.
1601  * @param handle Output handle. Must not be @c NULL.
1602  * @param security_cfg Security configuration. Must not be @c NULL.
1603  * @param opt TLS options. Must not be @c NULL.
1604  * @return @c VLINK_RET_NO_ERROR on success;
1605  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1606  * @p security_cfg == @c NULL or @p opt == @c NULL;
1607  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1608  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1609  *
1610  * @note Caller owns the handle and must release it with @c vlink_destroy_setter().
1611  */
1613  const vlink_schema_info_t* schema_info,
1614  vlink_setter_handle_t* handle,
1615  const vlink_security_config_t* security_cfg,
1616  const vlink_ssl_options_t* opt);
1617 
1618 /**
1619  * @brief Creates a secure Getter and applies TLS options before transport initialisation.
1620  *
1621  * @param url VLink field URL. Must not be @c NULL.
1622  * @param schema_info Optional bundled @c ser + @c schema metadata.
1623  * @param handle Output handle. Must not be @c NULL.
1624  * @param msg_callback Push-mode callback, or @c NULL for poll mode.
1625  * @param user_data Opaque pointer forwarded to @p msg_callback.
1626  * @param security_cfg Security configuration. Must not be @c NULL.
1627  * @param opt TLS options. Must not be @c NULL.
1628  * @return @c VLINK_RET_NO_ERROR on success;
1629  * @c VLINK_RET_INVALID_ERROR on bad arguments including
1630  * @p security_cfg == @c NULL or @p opt == @c NULL;
1631  * @c VLINK_RET_MEMORY_ERROR on pool allocation failure;
1632  * @c VLINK_RET_TRANSFER_ERROR if @c listen() fails;
1633  * @c VLINK_RET_RUNTIME_ERROR on construction exception.
1634  *
1635  * @note Caller owns the handle and must release it with @c vlink_destroy_getter().
1636  */
1638  const char* url, const vlink_schema_info_t* schema_info, vlink_getter_handle_t* handle,
1639  const vlink_msg_callback_t msg_callback, void* user_data, const vlink_security_config_t* security_cfg,
1640  const vlink_ssl_options_t* opt);
1641 
1642 /**
1643  * @brief Applies TLS options to a Publisher handle.
1644  *
1645  * @details
1646  * Forwards @p opt to @c Node::set_ssl_options() on the underlying transport,
1647  * which writes the corresponding @c ssl.* property entries. The transport
1648  * backend reads those entries during connection setup. Handles returned by
1649  * this C API are already initialised, so this setter returns
1650  * @c VLINK_RET_RUNTIME_ERROR for normal C handles. Use the matching
1651  * @c vlink_create_*_with_ssl_options() function when TLS must affect the
1652  * initial transport connection.
1653  *
1654  * @param handle Publisher handle. Must not be @c NULL.
1655  * @param opt Options aggregate. Must not be @c NULL.
1656  * @return @c VLINK_RET_NO_ERROR on success for an uninitialised internal
1657  * handle;
1658  * @c VLINK_RET_INVALID_ERROR on bad arguments;
1659  * @c VLINK_RET_RUNTIME_ERROR once the handle has been initialised.
1660  */
1662  const vlink_ssl_options_t* opt);
1663 
1664 /**
1665  * @brief Applies TLS options to a Subscriber handle.
1666  *
1667  * @param handle Subscriber handle. Must not be @c NULL.
1668  * @param opt Options aggregate. Must not be @c NULL.
1669  * @return Same status codes as @c vlink_publisher_set_ssl_options().
1670  */
1672  const vlink_ssl_options_t* opt);
1673 
1674 /**
1675  * @brief Applies TLS options to a Server handle.
1676  *
1677  * @param handle Server handle. Must not be @c NULL.
1678  * @param opt Options aggregate. Must not be @c NULL.
1679  * @return Same status codes as @c vlink_publisher_set_ssl_options().
1680  */
1682 
1683 /**
1684  * @brief Applies TLS options to a Client handle.
1685  *
1686  * @param handle Client handle. Must not be @c NULL.
1687  * @param opt Options aggregate. Must not be @c NULL.
1688  * @return Same status codes as @c vlink_publisher_set_ssl_options().
1689  */
1691 
1692 /**
1693  * @brief Applies TLS options to a Setter handle.
1694  *
1695  * @param handle Setter handle. Must not be @c NULL.
1696  * @param opt Options aggregate. Must not be @c NULL.
1697  * @return Same status codes as @c vlink_publisher_set_ssl_options().
1698  */
1700 
1701 /**
1702  * @brief Applies TLS options to a Getter handle.
1703  *
1704  * @param handle Getter handle. Must not be @c NULL.
1705  * @param opt Options aggregate. Must not be @c NULL.
1706  * @return Same status codes as @c vlink_publisher_set_ssl_options().
1707  */
1709 
1710 /** @} */
1711 
1712 #ifdef __cplusplus
1713 }
1714 #endif
1715 
1716 // NOLINTEND
VLINK_C_API_EXPORT int vlink_create_setter_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_setter_handle_t *handle, const vlink_ssl_options_t *opt)
Creates a Setter and applies TLS options before transport initialisation.
VLINK_C_API_EXPORT int vlink_create_secure_publisher_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_publisher_handle_t *handle, const vlink_security_config_t *security_cfg, const vlink_ssl_options_t *opt)
Creates a secure Publisher and applies TLS options before transport initialisation.
VLINK_C_API_EXPORT int vlink_create_client_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_client_handle_t *handle, const vlink_ssl_options_t *opt)
Creates a Client and applies TLS options before transport initialisation.
void(* vlink_connect_callback_t)(const bool is_connected, void *user_data)
Callback fired when the connection state of a Publisher or Client changes.
Definition: c_api.h:325
VLINK_C_API_EXPORT int vlink_invoke(const vlink_client_handle_t handle, const uint8_t *data, const size_t size, const vlink_resp_callback_t resp_callback, void *user_data)
Sends an RPC request and registers a callback for the response.
VLINK_C_API_EXPORT int vlink_create_secure_getter(const char *url, const vlink_schema_info_t *schema_info, vlink_getter_handle_t *handle, const vlink_msg_callback_t msg_callback, void *user_data, const vlink_security_config_t *security_cfg)
Atomically creates a Getter, installs Security, and calls listen().
VLINK_C_API_EXPORT int vlink_publish(const vlink_publisher_handle_t handle, const uint8_t *data, const size_t size)
Publishes a message to every matched Subscriber.
vlink_ret_t
Return code for VLink C API functions that report vlink_ret_t.
Definition: c_api.h:173
@ VLINK_RET_UNKNOWN_ERROR
Definition: c_api.h:174
@ VLINK_RET_NO_ERROR
Definition: c_api.h:175
@ VLINK_RET_RUNTIME_ERROR
Definition: c_api.h:179
@ VLINK_RET_INVALID_ERROR
Definition: c_api.h:177
@ VLINK_RET_MEMORY_ERROR
Definition: c_api.h:178
@ VLINK_RET_TRANSFER_ERROR
Definition: c_api.h:180
@ VLINK_RET_UNEXPECTED_ERROR
Definition: c_api.h:176
VLINK_C_API_EXPORT int vlink_create_setter(const char *url, const vlink_schema_info_t *schema_info, vlink_setter_handle_t *handle)
Creates a Setter node and initialises it on the given URL.
VLINK_C_API_EXPORT int vlink_client_set_ssl_options(vlink_client_handle_t *handle, const vlink_ssl_options_t *opt)
Applies TLS options to a Client handle.
vlink_schema_t
Coarse runtime schema family used for raw C API nodes.
Definition: c_api.h:192
@ VLINK_SCHEMA_ZEROCOPY
Definition: c_api.h:195
@ VLINK_SCHEMA_RAW
Definition: c_api.h:194
@ VLINK_SCHEMA_FLATBUFFERS
Definition: c_api.h:197
@ VLINK_SCHEMA_PROTOBUF
Definition: c_api.h:196
@ VLINK_SCHEMA_UNKNOWN
Definition: c_api.h:193
VLINK_C_API_EXPORT int vlink_create_secure_subscriber(const char *url, const vlink_schema_info_t *schema_info, vlink_subscriber_handle_t *handle, const vlink_msg_callback_t msg_callback, void *user_data, const vlink_security_config_t *security_cfg)
Atomically creates a Subscriber, installs Security, and calls listen().
struct vlink_security * vlink_security_handle_t
Opaque handle for a standalone Security instance.
Definition: c_api.h:1007
VLINK_C_API_EXPORT int vlink_has_server(const vlink_client_handle_t handle)
Checks whether the Client is connected to a Server.
VLINK_C_API_EXPORT int vlink_create_secure_subscriber_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_subscriber_handle_t *handle, const vlink_msg_callback_t msg_callback, void *user_data, const vlink_security_config_t *security_cfg, const vlink_ssl_options_t *opt)
Creates a secure Subscriber and applies TLS options before transport initialisation.
VLINK_C_API_EXPORT int vlink_publisher_set_ssl_options(vlink_publisher_handle_t *handle, const vlink_ssl_options_t *opt)
Applies TLS options to a Publisher handle.
VLINK_C_API_EXPORT int vlink_create_getter_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_getter_handle_t *handle, const vlink_msg_callback_t msg_callback, void *user_data, const vlink_ssl_options_t *opt)
Creates a Getter and applies TLS options before transport initialisation.
void(* vlink_req_callback_t)(const uint8_t *data, const size_t size, void *user_data)
Callback fired when a Server receives an RPC request.
Definition: c_api.h:354
VLINK_C_API_EXPORT int vlink_security_encrypt(vlink_security_handle_t sec, const uint8_t *in, const size_t in_size, uint8_t **out, size_t *out_size)
Encrypts a plaintext buffer using the active mode configured on sec.
VLINK_C_API_EXPORT int vlink_create_secure_client_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_client_handle_t *handle, const vlink_security_config_t *security_cfg, const vlink_ssl_options_t *opt)
Creates a secure Client and applies TLS options before transport initialisation.
VLINK_C_API_EXPORT int vlink_publish_by_force(const vlink_publisher_handle_t handle, const uint8_t *data, const size_t size)
Publishes a message even when no Subscribers are matched.
VLINK_C_API_EXPORT int vlink_create_subscriber_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_subscriber_handle_t *handle, const vlink_msg_callback_t msg_callback, void *user_data, const vlink_ssl_options_t *opt)
Creates a Subscriber and applies TLS options before transport initialisation.
VLINK_C_API_EXPORT int vlink_create_secure_publisher(const char *url, const vlink_schema_info_t *schema_info, vlink_publisher_handle_t *handle, const vlink_security_config_t *security_cfg)
Atomically creates a Publisher and installs Security.
#define VLINK_C_API_EXPORT
Definition: c_api.h:148
VLINK_C_API_EXPORT int vlink_create_publisher(const char *url, const vlink_schema_info_t *schema_info, vlink_publisher_handle_t *handle)
Creates a Publisher node and initialises it on the given URL.
VLINK_C_API_EXPORT int vlink_create_server_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_server_handle_t *handle, const vlink_req_callback_t req_callback, void *user_data, const vlink_ssl_options_t *opt)
Creates a Server and applies TLS options before transport initialisation.
VLINK_C_API_EXPORT int vlink_create_getter(const char *url, const vlink_schema_info_t *schema_info, vlink_getter_handle_t *handle, const vlink_msg_callback_t msg_callback, void *user_data)
Creates a Getter node, initialises it, and optionally registers a change callback.
VLINK_C_API_EXPORT int vlink_detect_subscribers(const vlink_publisher_handle_t handle, const vlink_connect_callback_t connect_callback, void *user_data)
Registers a callback fired whenever the Subscriber connection state changes.
VLINK_C_API_EXPORT int vlink_detect_server(const vlink_client_handle_t handle, const vlink_connect_callback_t connect_callback, void *user_data)
Registers a callback fired whenever the Server connection state changes.
VLINK_C_API_EXPORT int vlink_create_secure_setter(const char *url, const vlink_schema_info_t *schema_info, vlink_setter_handle_t *handle, const vlink_security_config_t *security_cfg)
Atomically creates a Setter and installs Security.
VLINK_C_API_EXPORT void vlink_ssl_options_init(vlink_ssl_options_t *opt)
Zero-initialises opt and applies the canonical TLS defaults.
VLINK_C_API_EXPORT int vlink_subscriber_set_ssl_options(vlink_subscriber_handle_t *handle, const vlink_ssl_options_t *opt)
Applies TLS options to a Subscriber handle.
VLINK_C_API_EXPORT vlink_security_handle_t vlink_security_create(const vlink_security_config_t *cfg)
Creates a standalone Security instance from cfg.
int(* vlink_security_callback_t)(const uint8_t *in, size_t in_size, uint8_t **out, size_t *out_size, void *user)
Optional user-provided encrypt/decrypt callback for vlink_security_config_t.
Definition: c_api.h:1038
VLINK_C_API_EXPORT int vlink_create_secure_server(const char *url, const vlink_schema_info_t *schema_info, vlink_server_handle_t *handle, const vlink_req_callback_t req_callback, void *user_data, const vlink_security_config_t *security_cfg)
Atomically creates a Server, installs Security, and calls listen().
VLINK_C_API_EXPORT void vlink_security_config_init(vlink_security_config_t *cfg)
Zero-initialises cfg and applies the C API default PBKDF2 / replay settings.
VLINK_C_API_EXPORT int vlink_create_subscriber(const char *url, const vlink_schema_info_t *schema_info, vlink_subscriber_handle_t *handle, const vlink_msg_callback_t msg_callback, void *user_data)
Creates a Subscriber node, initialises it, and registers the message callback.
VLINK_C_API_EXPORT int vlink_create_secure_server_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_server_handle_t *handle, const vlink_req_callback_t req_callback, void *user_data, const vlink_security_config_t *security_cfg, const vlink_ssl_options_t *opt)
Creates a secure Server and applies TLS options before transport initialisation.
VLINK_C_API_EXPORT int vlink_getter_set_ssl_options(vlink_getter_handle_t *handle, const vlink_ssl_options_t *opt)
Applies TLS options to a Getter handle.
VLINK_C_API_EXPORT int vlink_destroy_publisher(vlink_publisher_handle_t *handle)
Destroys a Publisher node and releases every associated resource.
VLINK_C_API_EXPORT void vlink_security_destroy(vlink_security_handle_t sec)
Destroys a standalone Security instance.
void(* vlink_resp_callback_t)(const uint8_t *data, const size_t size, void *user_data)
Callback fired when a Client receives an RPC response.
Definition: c_api.h:364
VLINK_C_API_EXPORT int vlink_wait_for_subscribers(const vlink_publisher_handle_t handle, const int timeout_ms)
Blocks until at least one Subscriber matches or timeout_ms expires.
VLINK_C_API_EXPORT int vlink_wait_for_server(const vlink_client_handle_t handle, const int timeout_ms)
Blocks until a Server is available or timeout_ms expires.
VLINK_C_API_EXPORT int vlink_create_secure_getter_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_getter_handle_t *handle, const vlink_msg_callback_t msg_callback, void *user_data, const vlink_security_config_t *security_cfg, const vlink_ssl_options_t *opt)
Creates a secure Getter and applies TLS options before transport initialisation.
VLINK_C_API_EXPORT int vlink_setter_set_ssl_options(vlink_setter_handle_t *handle, const vlink_ssl_options_t *opt)
Applies TLS options to a Setter handle.
VLINK_C_API_EXPORT int vlink_create_secure_setter_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_setter_handle_t *handle, const vlink_security_config_t *security_cfg, const vlink_ssl_options_t *opt)
Creates a secure Setter and applies TLS options before transport initialisation.
VLINK_C_API_EXPORT int vlink_reply(vlink_server_handle_t *handle, const uint8_t *data, const size_t size)
Provides the response data for the current in-progress RPC request.
VLINK_C_API_EXPORT int vlink_get(const vlink_getter_handle_t handle, uint8_t *data, size_t *size)
Retrieves the latest field value into a caller-provided buffer.
void(* vlink_msg_callback_t)(const uint8_t *data, const size_t size, void *user_data)
Callback fired when a Subscriber or Getter receives a message.
Definition: c_api.h:337
VLINK_C_API_EXPORT int vlink_create_publisher_with_ssl_options(const char *url, const vlink_schema_info_t *schema_info, vlink_publisher_handle_t *handle, const vlink_ssl_options_t *opt)
Creates a Publisher and applies TLS options before transport initialisation.
VLINK_C_API_EXPORT int vlink_create_secure_client(const char *url, const vlink_schema_info_t *schema_info, vlink_client_handle_t *handle, const vlink_security_config_t *security_cfg)
Atomically creates a Client and installs Security.
VLINK_C_API_EXPORT int vlink_security_decrypt(vlink_security_handle_t sec, const uint8_t *in, const size_t in_size, uint8_t **out, size_t *out_size)
Decrypts a ciphertext buffer using the active mode configured on sec.
VLINK_C_API_EXPORT int vlink_destroy_server(vlink_server_handle_t *handle)
Destroys a Server node and frees every internal resource, including the request/reply coordination st...
VLINK_C_API_EXPORT int vlink_server_set_ssl_options(vlink_server_handle_t *handle, const vlink_ssl_options_t *opt)
Applies TLS options to a Server handle.
VLINK_C_API_EXPORT int vlink_destroy_client(vlink_client_handle_t *handle)
Destroys a Client node and releases every associated resource.
VLINK_C_API_EXPORT int vlink_create_client(const char *url, const vlink_schema_info_t *schema_info, vlink_client_handle_t *handle)
Creates a Client node and initialises it on the given URL.
VLINK_C_API_EXPORT void vlink_security_free_buffer(uint8_t *buf)
Releases a buffer returned by vlink_security_encrypt() or vlink_security_decrypt().
VLINK_C_API_EXPORT int vlink_create_server(const char *url, const vlink_schema_info_t *schema_info, vlink_server_handle_t *handle, const vlink_req_callback_t req_callback, void *user_data)
Creates a Server node, initialises it, and registers the request callback.
VLINK_C_API_EXPORT int vlink_has_subscribers(const vlink_publisher_handle_t handle)
Checks whether at least one Subscriber has matched this Publisher.
VLINK_C_API_EXPORT int vlink_destroy_subscriber(vlink_subscriber_handle_t *handle)
Destroys a Subscriber node and releases every associated resource.
VLINK_C_API_EXPORT int vlink_destroy_setter(vlink_setter_handle_t *handle)
Destroys a Setter node and releases every associated resource.
VLINK_C_API_EXPORT int vlink_destroy_getter(vlink_getter_handle_t *handle)
Destroys a Getter node and releases every associated resource.
VLINK_C_API_EXPORT int vlink_set(const vlink_setter_handle_t handle, const uint8_t *data, const size_t size)
Publishes the latest field value.