Add safety functions to exported FFI methods

Signed-off-by: Lee Smet <lee.smet@hotmail.com>
This commit is contained in:
Lee Smet committed 2026-04-28 15:49:56 +02:00
1 parent 9466a61c4a
commit 672c6b6b4f
4 files changed
+473 -7

No files matched your search

+245 -3
View File
@@ -216,82 +216,324 @@ const char *mycelium_last_error_message(void);
Start a mycelium node. Returns an opaque handle on success, or NULL on
failure — call `mycelium_last_error_message` for details. The returned
handle must eventually be released with `mycelium_node_free`.
# Safety
`cfg` must point to a fully-initialised `mycelium_start_config_t`.
Pointer fields inside (`peers`, `peer_discovery_mode`,
`peer_discovery_interfaces`, `tun_name`) follow the conventions in the
module-level safety docs. The struct and any strings it points at are
not retained beyond the call — the caller may free them as soon as
this function returns.
*/
struct mycelium_node_t *mycelium_start(const struct mycelium_start_config_t *cfg);
/*
Halt the node and release its internal resources. The handle remains
valid for `mycelium_is_running` queries (which will return false) until
`mycelium_node_free` is called. No-op on a NULL or already-stopped node.
`mycelium_node_free` is called. No-op on an already-stopped node.
# Safety
`node` must be NULL or a live handle returned by `mycelium_start`.
*/
int32_t mycelium_stop(struct mycelium_node_t *node);
/*
Write `true`/`false` into `out` reflecting whether the node is running.
# Safety
`node` must be a live handle returned by `mycelium_start`. `out` must
point to a writable, properly aligned `bool`.
*/
int32_t mycelium_is_running(struct mycelium_node_t *node, bool *out);
/*
Populate `out` with the node's subnet and public key. The returned
strings are owned by the caller and must be released with
`mycelium_node_info_free`.
# Safety
`node` must be a live handle returned by `mycelium_start`. `out` must
point to a writable, properly aligned `mycelium_node_info_t`. Any
previous contents of `*out` are overwritten without being freed —
callers must release prior contents first or pass a fresh struct.
*/
int32_t mycelium_get_node_info(struct mycelium_node_t *node, struct mycelium_node_info_t *out);
/*
Look up the public key of the peer that owns the given mycelium IP.
On success writes a newly-allocated string to `*out` (empty if no
match); release with `mycelium_string_free`.
# Safety
`node` must be a live handle returned by `mycelium_start`. `ip` must
be a NUL-terminated C string. `out` must point to a writable
`*mut c_char`.
*/
int32_t mycelium_get_public_key_from_ip(struct mycelium_node_t *node, const char *ip, char **out);
/*
Populate `out` with one entry per known peer. Release the array with
`mycelium_peer_info_array_free`.
# Safety
`node` must be a live handle returned by `mycelium_start`. `out` must
point to a writable, properly aligned `mycelium_peer_info_array_t`;
any previous contents are overwritten without being freed.
*/
int32_t mycelium_get_peers(struct mycelium_node_t *node, struct mycelium_peer_info_array_t *out);
/*
Add a peer endpoint. Writes `true` to `*out` if the peer was newly
added, `false` if it was already known.
# Safety
`node` must be a live handle returned by `mycelium_start`. `endpoint`
must be a NUL-terminated C string. `out` must point to a writable
`bool`.
*/
int32_t mycelium_add_peer(struct mycelium_node_t *node, const char *endpoint, bool *out);
/*
Remove a peer endpoint. Writes `true` to `*out` if the peer existed
and was removed, `false` if no such peer was registered.
# Safety
`node` must be a live handle returned by `mycelium_start`. `endpoint`
must be a NUL-terminated C string. `out` must point to a writable
`bool`.
*/
int32_t mycelium_remove_peer(struct mycelium_node_t *node, const char *endpoint, bool *out);
/*
Populate `out` with the currently selected (in-use) routes. Release
the array with `mycelium_route_array_free`.
# Safety
`node` must be a live handle returned by `mycelium_start`. `out` must
point to a writable, properly aligned `mycelium_route_array_t`; any
previous contents are overwritten without being freed.
*/
int32_t mycelium_get_selected_routes(struct mycelium_node_t *node,
struct mycelium_route_array_t *out);
/*
Populate `out` with the routing table's fallback (non-selected) routes.
Release the array with `mycelium_route_array_free`.
# Safety
`node` must be a live handle returned by `mycelium_start`. `out` must
point to a writable, properly aligned `mycelium_route_array_t`; any
previous contents are overwritten without being freed.
*/
int32_t mycelium_get_fallback_routes(struct mycelium_node_t *node,
struct mycelium_route_array_t *out);
/*
Populate `out` with subnets the router is currently querying. Release
the array with `mycelium_queried_subnet_array_free`.
# Safety
`node` must be a live handle returned by `mycelium_start`. `out` must
point to a writable, properly aligned `mycelium_queried_subnet_array_t`;
any previous contents are overwritten without being freed.
*/
int32_t mycelium_get_queried_subnets(struct mycelium_node_t *node,
struct mycelium_queried_subnet_array_t *out);
/*
Populate `out` with aggregated packet statistics. Release with
`mycelium_packet_stats_free`.
# Safety
`node` must be a live handle returned by `mycelium_start`. `out` must
point to a writable, properly aligned `mycelium_packet_stats_t`; any
previous contents are overwritten without being freed.
*/
int32_t mycelium_get_packet_stats(struct mycelium_node_t *node,
struct mycelium_packet_stats_t *out);
/*
Generate a fresh 32-byte node secret key into `out`. Stateless — no
node handle required.
# Safety
`out` must point to a writable, properly aligned
`mycelium_secret_key_t`.
*/
int32_t mycelium_generate_secret_key(struct mycelium_secret_key_t *out);
/*
Derive the mycelium address (text form) of the public key for the
given secret key. Writes a newly-allocated string to `*out`; release
with `mycelium_string_free`. Stateless — no node handle required.
# Safety
`key` must point to an initialised `mycelium_secret_key_t`. `out` must
point to a writable `*mut c_char`.
*/
int32_t mycelium_address_from_secret_key(const struct mycelium_secret_key_t *key, char **out);
/*
Begin the periodic SOCKS5 proxy probe scan.
# Safety
`node` must be a live handle returned by `mycelium_start`.
*/
int32_t mycelium_start_proxy_probe(struct mycelium_node_t *node);
/*
Stop the periodic SOCKS5 proxy probe scan.
# Safety
`node` must be a live handle returned by `mycelium_start`.
*/
int32_t mycelium_stop_proxy_probe(struct mycelium_node_t *node);
/*
List the currently known SOCKS5 proxy endpoints (formatted as
`addr:port` strings). Release with `mycelium_string_array_free`.
# Safety
`node` must be a live handle returned by `mycelium_start`. `out` must
point to a writable, properly aligned `mycelium_string_array_t`; any
previous contents are overwritten without being freed.
*/
int32_t mycelium_list_proxies(struct mycelium_node_t *node, struct mycelium_string_array_t *out);
/*
Connect to a remote SOCKS5 proxy. Writes the negotiated remote address
to `*out` as a newly-allocated string; release with
`mycelium_string_free`.
# Safety
`node` must be a live handle returned by `mycelium_start`. `remote`
must be a NUL-terminated C string. `out` must point to a writable
`*mut c_char`.
*/
int32_t mycelium_proxy_connect(struct mycelium_node_t *node, const char *remote, char **out);
/*
Disconnect from the currently connected SOCKS5 proxy, if any.
# Safety
`node` must be a live handle returned by `mycelium_start`.
*/
int32_t mycelium_proxy_disconnect(struct mycelium_node_t *node);
/*
Release a node handle returned by `mycelium_start`. If the node is still
running it is stopped first. Safe to call with NULL.
# Safety
`node` must be NULL or a pointer previously returned by `mycelium_start`
that has not already been passed to this function. Double-free or
use-after-free is undefined behaviour.
*/
void mycelium_node_free(struct mycelium_node_t *node);
/*
Free a single C string returned by the library. Safe to call with NULL.
# Safety
`ptr` must be NULL or a value returned by a `mycelium_*` entry point
that hands the caller ownership of a `char *` (e.g.
`mycelium_get_public_key_from_ip`, `mycelium_address_from_secret_key`,
`mycelium_proxy_connect`). Strings retrieved via `mycelium_last_error_message`
are owned by the library and must NOT be passed here.
*/
void mycelium_string_free(char *ptr);
/*
Free a string array returned by the library. The struct itself is
caller-allocated; this releases the contents (each item plus the array).
Free a string array returned by the library. The outer struct is
caller-allocated; this releases the items and the backing storage, then
resets `items` to NULL and `len` to 0.
# Safety
`arr` must be NULL or point to a `mycelium_string_array_t` populated by
a successful library call (currently only `mycelium_list_proxies`).
Calling this twice on the same struct is safe — the second call sees
`items == NULL` and does nothing.
*/
void mycelium_string_array_free(struct mycelium_string_array_t *arr);
/*
Free a `mycelium_node_info_t` populated by `mycelium_get_node_info`.
Releases the inner `subnet` and `pubkey` strings and resets them to
NULL.
# Safety
`info` must be NULL or point to a struct populated by a successful call
to `mycelium_get_node_info`. Calling this twice on the same struct is
safe — the second call sees the fields already NULL.
*/
void mycelium_node_info_free(struct mycelium_node_info_t *info);
/*
Free a peer-info array populated by `mycelium_get_peers`. Releases each
item's strings, then the backing array, then resets the struct.
# Safety
`arr` must be NULL or point to a `mycelium_peer_info_array_t` populated
by a successful call to `mycelium_get_peers`. Idempotent.
*/
void mycelium_peer_info_array_free(struct mycelium_peer_info_array_t *arr);
/*
Free a route array populated by `mycelium_get_selected_routes` or
`mycelium_get_fallback_routes`.
# Safety
`arr` must be NULL or point to a `mycelium_route_array_t` populated by
a successful call to one of those two functions. Idempotent.
*/
void mycelium_route_array_free(struct mycelium_route_array_t *arr);
/*
Free a queried-subnet array populated by `mycelium_get_queried_subnets`.
# Safety
`arr` must be NULL or point to a `mycelium_queried_subnet_array_t`
populated by a successful call to `mycelium_get_queried_subnets`.
Idempotent.
*/
void mycelium_queried_subnet_array_free(struct mycelium_queried_subnet_array_t *arr);
/*
Free a `mycelium_packet_stats_t` populated by
`mycelium_get_packet_stats`. Releases both the by-source and
by-destination arrays.
# Safety
`stats` must be NULL or point to a `mycelium_packet_stats_t` populated
by a successful call to `mycelium_get_packet_stats`. Idempotent.
*/
void mycelium_packet_stats_free(struct mycelium_packet_stats_t *stats);
#endif /* MYCELIUM_H */
+141 -2
View File
@@ -11,7 +11,6 @@
//! the out-parameter.
#![allow(non_camel_case_types)]
#![allow(clippy::missing_safety_doc)]
use core::ffi::c_char;
use std::ffi::CStr;
@@ -124,6 +123,15 @@ macro_rules! with_running_node {
/// Start a mycelium node. Returns an opaque handle on success, or NULL on
/// failure — call `mycelium_last_error_message` for details. The returned
/// handle must eventually be released with `mycelium_node_free`.
///
/// # Safety
///
/// `cfg` must point to a fully-initialised `mycelium_start_config_t`.
/// Pointer fields inside (`peers`, `peer_discovery_mode`,
/// `peer_discovery_interfaces`, `tun_name`) follow the conventions in the
/// module-level safety docs. The struct and any strings it points at are
/// not retained beyond the call — the caller may free them as soon as
/// this function returns.
#[no_mangle]
pub unsafe extern "C" fn mycelium_start(
cfg: *const mycelium_start_config_t,
@@ -231,7 +239,11 @@ pub unsafe extern "C" fn mycelium_start(
/// Halt the node and release its internal resources. The handle remains
/// valid for `mycelium_is_running` queries (which will return false) until
/// `mycelium_node_free` is called. No-op on a NULL or already-stopped node.
/// `mycelium_node_free` is called. No-op on an already-stopped node.
///
/// # Safety
///
/// `node` must be NULL or a live handle returned by `mycelium_start`.
#[no_mangle]
pub unsafe extern "C" fn mycelium_stop(node: *mut mycelium_node_t) -> i32 {
error::clear();
@@ -257,6 +269,11 @@ pub unsafe extern "C" fn mycelium_stop(node: *mut mycelium_node_t) -> i32 {
}
/// Write `true`/`false` into `out` reflecting whether the node is running.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `out` must
/// point to a writable, properly aligned `bool`.
#[no_mangle]
pub unsafe extern "C" fn mycelium_is_running(node: *mut mycelium_node_t, out: *mut bool) -> i32 {
error::clear();
@@ -279,6 +296,16 @@ pub unsafe extern "C" fn mycelium_is_running(node: *mut mycelium_node_t, out: *m
// Identity / introspection
// ---------------------------------------------------------------------------
/// Populate `out` with the node's subnet and public key. The returned
/// strings are owned by the caller and must be released with
/// `mycelium_node_info_free`.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `out` must
/// point to a writable, properly aligned `mycelium_node_info_t`. Any
/// previous contents of `*out` are overwritten without being freed —
/// callers must release prior contents first or pass a fresh struct.
#[no_mangle]
pub unsafe extern "C" fn mycelium_get_node_info(
node: *mut mycelium_node_t,
@@ -300,6 +327,15 @@ pub unsafe extern "C" fn mycelium_get_node_info(
})
}
/// Look up the public key of the peer that owns the given mycelium IP.
/// On success writes a newly-allocated string to `*out` (empty if no
/// match); release with `mycelium_string_free`.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `ip` must
/// be a NUL-terminated C string. `out` must point to a writable
/// `*mut c_char`.
#[no_mangle]
pub unsafe extern "C" fn mycelium_get_public_key_from_ip(
node: *mut mycelium_node_t,
@@ -339,6 +375,14 @@ pub unsafe extern "C" fn mycelium_get_public_key_from_ip(
// Peers
// ---------------------------------------------------------------------------
/// Populate `out` with one entry per known peer. Release the array with
/// `mycelium_peer_info_array_free`.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `out` must
/// point to a writable, properly aligned `mycelium_peer_info_array_t`;
/// any previous contents are overwritten without being freed.
#[no_mangle]
pub unsafe extern "C" fn mycelium_get_peers(
node: *mut mycelium_node_t,
@@ -365,6 +409,14 @@ pub unsafe extern "C" fn mycelium_get_peers(
})
}
/// Add a peer endpoint. Writes `true` to `*out` if the peer was newly
/// added, `false` if it was already known.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `endpoint`
/// must be a NUL-terminated C string. `out` must point to a writable
/// `bool`.
#[no_mangle]
pub unsafe extern "C" fn mycelium_add_peer(
node: *mut mycelium_node_t,
@@ -391,6 +443,14 @@ pub unsafe extern "C" fn mycelium_add_peer(
})
}
/// Remove a peer endpoint. Writes `true` to `*out` if the peer existed
/// and was removed, `false` if no such peer was registered.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `endpoint`
/// must be a NUL-terminated C string. `out` must point to a writable
/// `bool`.
#[no_mangle]
pub unsafe extern "C" fn mycelium_remove_peer(
node: *mut mycelium_node_t,
@@ -421,6 +481,14 @@ pub unsafe extern "C" fn mycelium_remove_peer(
// Routes
// ---------------------------------------------------------------------------
/// Populate `out` with the currently selected (in-use) routes. Release
/// the array with `mycelium_route_array_free`.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `out` must
/// point to a writable, properly aligned `mycelium_route_array_t`; any
/// previous contents are overwritten without being freed.
#[no_mangle]
pub unsafe extern "C" fn mycelium_get_selected_routes(
node: *mut mycelium_node_t,
@@ -447,6 +515,14 @@ pub unsafe extern "C" fn mycelium_get_selected_routes(
})
}
/// Populate `out` with the routing table's fallback (non-selected) routes.
/// Release the array with `mycelium_route_array_free`.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `out` must
/// point to a writable, properly aligned `mycelium_route_array_t`; any
/// previous contents are overwritten without being freed.
#[no_mangle]
pub unsafe extern "C" fn mycelium_get_fallback_routes(
node: *mut mycelium_node_t,
@@ -473,6 +549,14 @@ pub unsafe extern "C" fn mycelium_get_fallback_routes(
})
}
/// Populate `out` with subnets the router is currently querying. Release
/// the array with `mycelium_queried_subnet_array_free`.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `out` must
/// point to a writable, properly aligned `mycelium_queried_subnet_array_t`;
/// any previous contents are overwritten without being freed.
#[no_mangle]
pub unsafe extern "C" fn mycelium_get_queried_subnets(
node: *mut mycelium_node_t,
@@ -508,6 +592,14 @@ pub unsafe extern "C" fn mycelium_get_queried_subnets(
// Packet statistics
// ---------------------------------------------------------------------------
/// Populate `out` with aggregated packet statistics. Release with
/// `mycelium_packet_stats_free`.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `out` must
/// point to a writable, properly aligned `mycelium_packet_stats_t`; any
/// previous contents are overwritten without being freed.
#[no_mangle]
pub unsafe extern "C" fn mycelium_get_packet_stats(
node: *mut mycelium_node_t,
@@ -547,6 +639,13 @@ pub unsafe extern "C" fn mycelium_get_packet_stats(
// Key utilities (no node required)
// ---------------------------------------------------------------------------
/// Generate a fresh 32-byte node secret key into `out`. Stateless — no
/// node handle required.
///
/// # Safety
///
/// `out` must point to a writable, properly aligned
/// `mycelium_secret_key_t`.
#[no_mangle]
pub unsafe extern "C" fn mycelium_generate_secret_key(out: *mut mycelium_secret_key_t) -> i32 {
error::clear();
@@ -560,6 +659,14 @@ pub unsafe extern "C" fn mycelium_generate_secret_key(out: *mut mycelium_secret_
MYCELIUM_OK
}
/// Derive the mycelium address (text form) of the public key for the
/// given secret key. Writes a newly-allocated string to `*out`; release
/// with `mycelium_string_free`. Stateless — no node handle required.
///
/// # Safety
///
/// `key` must point to an initialised `mycelium_secret_key_t`. `out` must
/// point to a writable `*mut c_char`.
#[no_mangle]
pub unsafe extern "C" fn mycelium_address_from_secret_key(
key: *const mycelium_secret_key_t,
@@ -583,6 +690,11 @@ pub unsafe extern "C" fn mycelium_address_from_secret_key(
// Proxy
// ---------------------------------------------------------------------------
/// Begin the periodic SOCKS5 proxy probe scan.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`.
#[no_mangle]
pub unsafe extern "C" fn mycelium_start_proxy_probe(node: *mut mycelium_node_t) -> i32 {
error::clear();
@@ -594,6 +706,11 @@ pub unsafe extern "C" fn mycelium_start_proxy_probe(node: *mut mycelium_node_t)
})
}
/// Stop the periodic SOCKS5 proxy probe scan.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`.
#[no_mangle]
pub unsafe extern "C" fn mycelium_stop_proxy_probe(node: *mut mycelium_node_t) -> i32 {
error::clear();
@@ -605,6 +722,14 @@ pub unsafe extern "C" fn mycelium_stop_proxy_probe(node: *mut mycelium_node_t) -
})
}
/// List the currently known SOCKS5 proxy endpoints (formatted as
/// `addr:port` strings). Release with `mycelium_string_array_free`.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `out` must
/// point to a writable, properly aligned `mycelium_string_array_t`; any
/// previous contents are overwritten without being freed.
#[no_mangle]
pub unsafe extern "C" fn mycelium_list_proxies(
node: *mut mycelium_node_t,
@@ -634,6 +759,15 @@ pub unsafe extern "C" fn mycelium_list_proxies(
})
}
/// Connect to a remote SOCKS5 proxy. Writes the negotiated remote address
/// to `*out` as a newly-allocated string; release with
/// `mycelium_string_free`.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`. `remote`
/// must be a NUL-terminated C string. `out` must point to a writable
/// `*mut c_char`.
#[no_mangle]
pub unsafe extern "C" fn mycelium_proxy_connect(
node: *mut mycelium_node_t,
@@ -672,6 +806,11 @@ pub unsafe extern "C" fn mycelium_proxy_connect(
})
}
/// Disconnect from the currently connected SOCKS5 proxy, if any.
///
/// # Safety
///
/// `node` must be a live handle returned by `mycelium_start`.
#[no_mangle]
pub unsafe extern "C" fn mycelium_proxy_disconnect(node: *mut mycelium_node_t) -> i32 {
error::clear();
+25
View File
@@ -8,6 +8,31 @@
//! `mycelium_node_t *` that the caller passes back into every other entry
//! point. Lifecycle (singleton-or-not, lifetime, threading) is the
//! consumer's choice, not ours.
//!
//! # Safety conventions
//!
//! Common to every `extern "C"` entry point in this module; per-function
//! `# Safety` sections only document the bits that go beyond these:
//!
//! - Pointer arguments are either NULL (only where the per-function doc
//! says NULL is accepted) or valid: properly aligned, non-dangling,
//! pointing to an initialised value of the documented type.
//! - C string inputs (`*const c_char`) must be NUL-terminated. UTF-8 is
//! validated at runtime; invalid bytes yield `MYCELIUM_ERR_INVALID_ARG`
//! rather than UB.
//! - Out-pointers must point to writable, properly aligned memory of the
//! right type. Writes happen only on success (return code 0, or non-NULL
//! handle from `mycelium_start`).
//! - `mycelium_node_t *` arguments must come from `mycelium_start` and
//! must not have been passed to `mycelium_node_free`. Use-after-free,
//! double-free, or freeing on one thread while another thread is using
//! the same handle is undefined behaviour.
//! - Strings and structs that the library hands back are owned by the
//! caller and must be released with the matching `mycelium_*_free`
//! function. Reading the contents from multiple threads is safe; freeing
//! must not race with reads.
//! - The library is not async-signal safe; do not call entry points from
//! a signal handler.
mod conversions;
mod error;
+62 -2
View File
@@ -186,6 +186,12 @@ pub(super) unsafe fn drain_array<T>(ptr: *mut T, len: usize) -> Vec<T> {
/// Release a node handle returned by `mycelium_start`. If the node is still
/// running it is stopped first. Safe to call with NULL.
///
/// # Safety
///
/// `node` must be NULL or a pointer previously returned by `mycelium_start`
/// that has not already been passed to this function. Double-free or
/// use-after-free is undefined behaviour.
#[no_mangle]
pub unsafe extern "C" fn mycelium_node_free(node: *mut mycelium_node_t) {
if node.is_null() {
@@ -195,13 +201,29 @@ pub unsafe extern "C" fn mycelium_node_free(node: *mut mycelium_node_t) {
}
/// Free a single C string returned by the library. Safe to call with NULL.
///
/// # Safety
///
/// `ptr` must be NULL or a value returned by a `mycelium_*` entry point
/// that hands the caller ownership of a `char *` (e.g.
/// `mycelium_get_public_key_from_ip`, `mycelium_address_from_secret_key`,
/// `mycelium_proxy_connect`). Strings retrieved via `mycelium_last_error_message`
/// are owned by the library and must NOT be passed here.
#[no_mangle]
pub unsafe extern "C" fn mycelium_string_free(ptr: *mut c_char) {
free_cstring(ptr);
}
/// Free a string array returned by the library. The struct itself is
/// caller-allocated; this releases the contents (each item plus the array).
/// Free a string array returned by the library. The outer struct is
/// caller-allocated; this releases the items and the backing storage, then
/// resets `items` to NULL and `len` to 0.
///
/// # Safety
///
/// `arr` must be NULL or point to a `mycelium_string_array_t` populated by
/// a successful library call (currently only `mycelium_list_proxies`).
/// Calling this twice on the same struct is safe — the second call sees
/// `items == NULL` and does nothing.
#[no_mangle]
pub unsafe extern "C" fn mycelium_string_array_free(arr: *mut mycelium_string_array_t) {
if arr.is_null() {
@@ -215,6 +237,15 @@ pub unsafe extern "C" fn mycelium_string_array_free(arr: *mut mycelium_string_ar
arr.len = 0;
}
/// Free a `mycelium_node_info_t` populated by `mycelium_get_node_info`.
/// Releases the inner `subnet` and `pubkey` strings and resets them to
/// NULL.
///
/// # Safety
///
/// `info` must be NULL or point to a struct populated by a successful call
/// to `mycelium_get_node_info`. Calling this twice on the same struct is
/// safe — the second call sees the fields already NULL.
#[no_mangle]
pub unsafe extern "C" fn mycelium_node_info_free(info: *mut mycelium_node_info_t) {
if info.is_null() {
@@ -227,6 +258,13 @@ pub unsafe extern "C" fn mycelium_node_info_free(info: *mut mycelium_node_info_t
info.pubkey = std::ptr::null_mut();
}
/// Free a peer-info array populated by `mycelium_get_peers`. Releases each
/// item's strings, then the backing array, then resets the struct.
///
/// # Safety
///
/// `arr` must be NULL or point to a `mycelium_peer_info_array_t` populated
/// by a successful call to `mycelium_get_peers`. Idempotent.
#[no_mangle]
pub unsafe extern "C" fn mycelium_peer_info_array_free(arr: *mut mycelium_peer_info_array_t) {
if arr.is_null() {
@@ -243,6 +281,13 @@ pub unsafe extern "C" fn mycelium_peer_info_array_free(arr: *mut mycelium_peer_i
arr.len = 0;
}
/// Free a route array populated by `mycelium_get_selected_routes` or
/// `mycelium_get_fallback_routes`.
///
/// # Safety
///
/// `arr` must be NULL or point to a `mycelium_route_array_t` populated by
/// a successful call to one of those two functions. Idempotent.
#[no_mangle]
pub unsafe extern "C" fn mycelium_route_array_free(arr: *mut mycelium_route_array_t) {
if arr.is_null() {
@@ -257,6 +302,13 @@ pub unsafe extern "C" fn mycelium_route_array_free(arr: *mut mycelium_route_arra
arr.len = 0;
}
/// Free a queried-subnet array populated by `mycelium_get_queried_subnets`.
///
/// # Safety
///
/// `arr` must be NULL or point to a `mycelium_queried_subnet_array_t`
/// populated by a successful call to `mycelium_get_queried_subnets`.
/// Idempotent.
#[no_mangle]
pub unsafe extern "C" fn mycelium_queried_subnet_array_free(
arr: *mut mycelium_queried_subnet_array_t,
@@ -278,6 +330,14 @@ unsafe fn free_packet_stat_entries(ptr: *mut mycelium_packet_stat_entry_t, len:
}
}
/// Free a `mycelium_packet_stats_t` populated by
/// `mycelium_get_packet_stats`. Releases both the by-source and
/// by-destination arrays.
///
/// # Safety
///
/// `stats` must be NULL or point to a `mycelium_packet_stats_t` populated
/// by a successful call to `mycelium_get_packet_stats`. Idempotent.
#[no_mangle]
pub unsafe extern "C" fn mycelium_packet_stats_free(stats: *mut mycelium_packet_stats_t) {
if stats.is_null() {