Skip to content
Exportieren

librns C ABI

Purpose

librns embeds Reticulum in-process for native hosts (C, C++, and similar FFI). It is a thin facade over pkg/node, destination, and link. Same wire stack as the daemon. Not a Python API and not a full Control API mirror.

For Go apps, prefer pkg/node directly. For a separate daemon and JSON/WebSocket, use the Control API.

Artifacts

Artifact Role
include/rns.h Public C header
bin/librns.so Shared library (Linux first)
pkg/librns Pure Go facade (tests and fuzz without CGO)
pkg/librns/capi CGO //export shims
cmd/librns -buildmode=c-shared entry
examples/librns-smoke Minimal C smoke program
bindings/odin Idiomatic Odin bindings and tests over librns.so
bindings/dart Dart FFI (ffi.dart) plus Control API client

Daemon builds stay CGO_ENABLED=0. Only build-librns turns CGO on.

Build and smoke

task build-librns
make -C examples/librns-smoke
./examples/librns-smoke/librns-smoke

Needs a C toolchain and CGO. Output: bin/librns.so and a copy of the header under bin/rns.h.

librns vs Control API

librns Control API
In-process Separate reticulum-go process
rns_event_poll or callback WebSocket events
C ABI / FFI JSON over HTTP and WS
Caller-owned buffers Base64 / hex JSON payloads
Node, link, request, path table, lifecycle Sessions and full HTTP surface

Supported surface

Authoritative names live in include/rns.h. Summary below.

Version and errors

Function Notes
rns_version Returns RNS_API_VERSION string
rns_last_error Copies last failing call message into caller buffer
Code Meaning
RNS_OK Success
RNS_ERR_INVALID_ARG Bad argument (empty path, wrong hash length, NUL in path)
RNS_ERR_INVALID_HANDLE Unknown or destroyed handle
RNS_ERR_NOT_FOUND Unknown destination identity or request id
RNS_ERR_STATE Wrong lifecycle state (not started, no identity)
RNS_ERR_IO Config or identity file I/O
RNS_ERR_INTERNAL Unexpected internal failure
RNS_ERR_TIMEOUT Event poll timed out
RNS_ERR_TRUNCATED Output buffer too small

Node

Function Notes
rns_node_create Empty path uses in-memory defaults with share_instance off
rns_node_start / rns_node_stop Idempotent
rns_node_destroy Stops if needed, clears callback, invalidates handle
rns_node_set_identity Attach identity before destinations that need one
rns_node_pause Network lost (OnNetworkLost)
rns_node_resume Network available (OnNetworkAvailable)
rns_node_refresh_paths Refresh watched paths, or pass packed 16-byte hashes

Identity

Function Notes
rns_identity_generate New software identity
rns_identity_load Path from operator config. Rejects empty and NUL
rns_identity_destroy Release handle
rns_identity_hash Truncated hash as 32 hex chars

Destination

Function Notes
rns_destination_create App name required. Optional aspects. accepts_links wires inbound links
rns_destination_announce Optional app data
rns_destination_hash 16-byte truncated hash (RNS_HASH_LEN)
rns_destination_destroy Release handle
rns_destination_register_request_handler Bridge path to RNS_EV_REQUEST_INCOMING

Path and link

Function Notes
rns_path_request Requires started node and 16-byte dest hash
rns_path_table Snapshot into caller array. max_hops < 0 means no filter
rns_link_open Outbound link to dest hash (identity must be known from announce)
rns_link_send On established link
rns_link_close Teardown
rns_link_id 16-byte link id
rns_link_request Outbound request. Completion via response or failed events
rns_request_respond Answer a pending RNS_EV_REQUEST_INCOMING

Events

Function Notes
rns_event_poll Blocks up to timeout_ms. Returns RNS_ERR_TIMEOUT if empty
rns_set_event_callback Optional. Drains the same queue. Pass NULL to clear
Kind Meaning
RNS_EV_ANNOUNCE Announce received
RNS_EV_LINK_ESTABLISHED Link up (inbound or outbound)
RNS_EV_LINK_FAILED Open failed or timed out
RNS_EV_LINK_DATA Payload on link
RNS_EV_LINK_CLOSED Link torn down
RNS_EV_REQUEST_INCOMING Inbound request. Call rns_request_respond
RNS_EV_REQUEST_RESPONSE Outbound request succeeded
RNS_EV_REQUEST_FAILED Outbound request failed or timed out

rns_event fields are filled by copy. Set app_data and app_data_cap before poll for variable payloads. Truncation sets app_data_truncated (and path_truncated / error_message_truncated when those strings do not fit).

The per-node queue is bounded. On overflow it drops the oldest event. Poll and callback share that queue. Prefer one consumer style at a time.

ABI rules

  • Handles are opaque uint64_t. Destroy them before process exit.
  • Never hold Go pointers across the ABI. The facade always copies.
  • Paths are operator-chosen. Empty and embedded NUL are rejected.
  • Empty config path is valid and means in-memory defaults (no shared-instance bind).
  • Incoming request handlers block the link goroutine until respond or a 30s timeout.

Not in this ABI (yet)

  • macOS / Windows shared libs
  • Android NDK packaging

Grow the header only when a real host needs it. Keep RNS_API_VERSION in mind.

Typical flow

rns_node_create("")
rns_identity_generate / rns_identity_load
rns_node_set_identity
rns_node_start
rns_destination_create(..., accepts_links=1)
rns_destination_register_request_handler(dest, "/ping")
rns_destination_announce
  peer: rns_event_poll -> RNS_EV_ANNOUNCE
  peer: rns_link_open(dest_hash)
rns_event_poll -> RNS_EV_LINK_ESTABLISHED
rns_link_send / RNS_EV_LINK_DATA
rns_link_request / RNS_EV_REQUEST_RESPONSE
rns_link_close / RNS_EV_LINK_CLOSED
rns_node_stop
rns_node_destroy

Testing

Kind Where
Unit and edge pkg/librns/*_test.go
Facade link integration TestFacadeLinkOpenSendClose
Lifecycle, path table, callback extended_test.go
Property testing/quick drop-oldest and handle table
Fuzz FuzzHandleTable, FuzzEventQueue, FuzzConfigPathCreate, FuzzValidatePath
C smoke examples/librns-smoke
Odin bindings bindings/odin (task test-odin)
go test ./pkg/librns
task build-librns
make -C examples/librns-smoke && ./examples/librns-smoke/librns-smoke
task test-odin

Odin bindings

Path: bindings/odin/.

Idiomatic wrappers over the same C ABI (foreign import system:rns). Package import uses a collection rooted at bindings/odin:

import rns "rns:rns"

Coverage

Area Odin surface
Version and errors version, last_error, error_string, Error
Node lifecycle node_create, node_start, node_stop, node_destroy, node_pause, node_resume, node_set_identity, node_refresh_paths
Identity identity_generate, identity_load, identity_destroy, identity_hash
Destination destination_create, destination_announce, destination_hash, destroy, request handler register
Path path_request, path_table
Link and requests link_open, link_send, link_close, link_id, link_request, request_respond
Events event_poll, set_event_callback, helpers for app data and hashes
Raw ABI foreign rns_* procs in bindings/odin/rns/foreign.odin

Linux only (matches librns.so). Requires Odin on PATH and a built shared library.

Build and test

task build-librns
task test-odin
# or
make -C bindings/odin test
make -C bindings/odin smoke

CI runs the same suite (test-odin job, pinned Odin dev-2026-06).

Tests cover version and node lifecycle, identity and destination helpers, and a live UDP announce, link, and send round trip through librns.so.

Dart FFI bindings

Path: bindings/dart/ (import package:rns_control/ffi.dart).

In-process dart:ffi wrappers over the same C ABI. First platforms: Linux desktop, Android (arm64-v8a, armeabi-v7a, x86_64), and Windows amd64.

import 'package:rns_control/ffi.dart';

final rns = Rns();
final node = rns.nodeCreate();
rns.nodeStart(node);

Artifacts

Platform Output
Linux bin/librns.so
Android bin/android/<abi>/librns.so
Windows bin/windows/amd64/librns.dll
task build-librns
task build-librns-targets -- linux android windows
task test-dart

Android builds need an NDK (ANDROID_NDK_HOME). Windows cross-builds need mingw-w64 or Zig (scripts/cc-windows-zig.sh). Flutter apps copy Android ABIs into jniLibs and ship librns.dll beside the Windows runner.

For out-of-process Dart or Flutter without shipping native code, use the Control API client in the same package.

Related documents

R
Reticulum-Go

A Go implementation of the Reticulum Network Stack. Building the future of resilient, sovereign communications.

Implementation License: Apache-2.0

Follow Development

Links

Quad4 Software

Backed by Quad4 Software. Building privacy-first, secure, efficient software.

quad4.io
© 2026 Quad4 Software. All rights reserved.
Deployed using Coolify