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