Skip to main content

rns_embedded_ffi/lib_parts/
rnsembeddedv1nodeerror.rs

1#[repr(C)]
2#[derive(Debug, Clone, Copy)]
3pub struct RnsEmbeddedV1NodeError {
4    pub struct_size: usize,
5    pub struct_version: u32,
6    pub code: RnsEmbeddedV1NodeErrorCode,
7    pub reserved: [u8; 16],
8}
9
10impl Default for RnsEmbeddedV1NodeError {
11    fn default() -> Self {
12        Self {
13            struct_size: core::mem::size_of::<Self>(),
14            struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
15            code: RnsEmbeddedV1NodeErrorCode::Unknown,
16            reserved: [0; 16],
17        }
18    }
19}
20
21#[repr(C)]
22pub struct RnsEmbeddedV1NodeConfig {
23    pub struct_size: usize,
24    pub struct_version: u32,
25    pub store_identity: [u8; 32],
26    pub lxmf_address: [u8; 16],
27    pub node_mode: RnsEmbeddedNodeMode,
28    pub announce_interval_ms: u64,
29    pub max_outbound_queue: usize,
30    pub max_events: usize,
31    pub capture_default_max_bytes: u32,
32    pub ble_mtu_hint: u16,
33    pub ble_max_inbound_frames: usize,
34    pub ble_max_outbound_frames: usize,
35    pub ble_ordered_delivery: bool,
36    pub tcp_host: [u8; 256],
37    pub tcp_port: u16,
38    pub tcp_listen_port: u16,
39    pub reserved: [u8; 28],
40}
41
42impl Default for RnsEmbeddedV1NodeConfig {
43    fn default() -> Self {
44        let legacy = RnsEmbeddedNodeConfig::default();
45        Self {
46            struct_size: core::mem::size_of::<Self>(),
47            struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
48            store_identity: legacy.store_identity,
49            lxmf_address: legacy.lxmf_address,
50            node_mode: legacy.node_mode,
51            announce_interval_ms: legacy.announce_interval_ms,
52            max_outbound_queue: legacy.max_outbound_queue,
53            max_events: legacy.max_events,
54            capture_default_max_bytes: legacy.capture_default_max_bytes,
55            ble_mtu_hint: legacy.ble_mtu_hint,
56            ble_max_inbound_frames: legacy.ble_max_inbound_frames,
57            ble_max_outbound_frames: legacy.ble_max_outbound_frames,
58            ble_ordered_delivery: legacy.ble_ordered_delivery,
59            tcp_host: legacy.tcp_host,
60            tcp_port: legacy.tcp_port,
61            tcp_listen_port: legacy.tcp_listen_port,
62            reserved: [0; 28],
63        }
64    }
65}
66
67#[repr(C)]
68#[derive(Debug, Clone, Copy)]
69pub struct RnsEmbeddedV1NodeStatus {
70    pub struct_size: usize,
71    pub struct_version: u32,
72    pub run_state: RnsEmbeddedV1RunState,
73    pub epoch: u64,
74    pub lifecycle_state: RnsEmbeddedLifecycleState,
75    pub pending_outbound: usize,
76    pub announces_queued: u32,
77    pub outbound_sent: u32,
78    pub outbound_deferred: u32,
79    pub inbound_accepted: u32,
80    pub inbound_rejected: u32,
81    pub announces_received: u32,
82    pub lxmf_messages_received: u32,
83    pub log_level: RnsEmbeddedV1LogLevel,
84    pub reserved: [u8; 24],
85}
86
87impl Default for RnsEmbeddedV1NodeStatus {
88    fn default() -> Self {
89        Self {
90            struct_size: core::mem::size_of::<Self>(),
91            struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
92            run_state: RnsEmbeddedV1RunState::Stopped,
93            epoch: 0,
94            lifecycle_state: RnsEmbeddedLifecycleState::Boot,
95            pending_outbound: 0,
96            announces_queued: 0,
97            outbound_sent: 0,
98            outbound_deferred: 0,
99            inbound_accepted: 0,
100            inbound_rejected: 0,
101            announces_received: 0,
102            lxmf_messages_received: 0,
103            log_level: RnsEmbeddedV1LogLevel::Info,
104            reserved: [0; 24],
105        }
106    }
107}
108
109#[repr(C)]
110#[derive(Debug, Clone, Copy)]
111pub struct RnsEmbeddedV1SendReceipt {
112    pub struct_size: usize,
113    pub struct_version: u32,
114    pub operation_id: u64,
115    pub epoch: u64,
116    pub accepted_bytes: usize,
117    pub queued: bool,
118    pub target_count: u32,
119    pub reserved: [u8; 24],
120}
121
122impl Default for RnsEmbeddedV1SendReceipt {
123    fn default() -> Self {
124        Self {
125            struct_size: core::mem::size_of::<Self>(),
126            struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
127            operation_id: 0,
128            epoch: 0,
129            accepted_bytes: 0,
130            queued: false,
131            target_count: 0,
132            reserved: [0; 24],
133        }
134    }
135}
136
137#[repr(C)]
138#[derive(Debug, Clone, Copy)]
139pub struct RnsEmbeddedV1Capabilities {
140    pub struct_size: usize,
141    pub struct_version: u32,
142    pub abi_version: u32,
143    pub capability_schema_version: u32,
144    pub known_capability_bits: u64,
145    pub compile_time_capability_bits: u64,
146    pub capability_bits: u64,
147    pub max_event_payload_bytes: u32,
148    pub max_subscriptions: u32,
149    pub max_blocking_timeout_ms: u64,
150    pub driver_tick_target_ms: u32,
151    pub driver_tick_max_ms: u32,
152    pub reserved: [u8; 24],
153}
154
155impl Default for RnsEmbeddedV1Capabilities {
156    fn default() -> Self {
157        let mut compile_time_capability_bits =
158            RNS_EMBEDDED_V1_CAP_BROADCAST_EXPLICIT_LIST | RNS_EMBEDDED_V1_CAP_COMPAT_LEGACY_FFI;
159        if cfg!(feature = "std") {
160            compile_time_capability_bits |=
161                RNS_EMBEDDED_V1_CAP_MANAGED_RUNTIME | RNS_EMBEDDED_V1_CAP_BLOCKING_NEXT;
162        }
163        if cfg!(feature = "std") || cfg!(feature = "alloc") {
164            compile_time_capability_bits |= RNS_EMBEDDED_V1_CAP_EVENT_GAP_SIGNALING;
165        }
166        Self {
167            struct_size: core::mem::size_of::<Self>(),
168            struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
169            abi_version: RNS_EMBEDDED_V1_ABI_VERSION,
170            capability_schema_version: RNS_EMBEDDED_V1_CAPABILITY_SCHEMA_VERSION,
171            known_capability_bits: RNS_EMBEDDED_V1_KNOWN_CAPABILITY_BITS,
172            compile_time_capability_bits,
173            capability_bits: compile_time_capability_bits,
174            max_event_payload_bytes: 0,
175            max_subscriptions: 1024,
176            max_blocking_timeout_ms: if cfg!(feature = "std") {
177                RNS_EMBEDDED_V1_MAX_BLOCKING_TIMEOUT_MS
178            } else {
179                0
180            },
181            driver_tick_target_ms: if cfg!(feature = "std") {
182                RNS_EMBEDDED_V1_DRIVER_TICK_TARGET_MS
183            } else {
184                0
185            },
186            driver_tick_max_ms: if cfg!(feature = "std") {
187                RNS_EMBEDDED_V1_DRIVER_TICK_MAX_MS
188            } else {
189                0
190            },
191            reserved: [0; 24],
192        }
193    }
194}
195
196#[repr(C)]
197#[derive(Debug, Clone, Copy)]
198pub struct RnsEmbeddedV1NodeEvent {
199    pub struct_size: usize,
200    pub struct_version: u32,
201    pub kind: RnsEmbeddedV1EventKind,
202    pub event_id: u64,
203    pub epoch: u64,
204    pub occurred_at_ms: u64,
205    pub operation_id: u64,
206    pub has_operation_id: bool,
207    pub run_state: RnsEmbeddedV1RunState,
208    pub lifecycle_state: RnsEmbeddedLifecycleState,
209    pub log_level: RnsEmbeddedV1LogLevel,
210    pub error_code: RnsEmbeddedV1NodeErrorCode,
211    pub frame_kind: u8,
212    pub sequence: u32,
213    pub bytes: usize,
214    pub extension_id: u32,
215    pub value0: u64,
216    pub value1: u64,
217    pub reserved: [u8; 24],
218}
219
220impl Default for RnsEmbeddedV1NodeEvent {
221    fn default() -> Self {
222        Self {
223            struct_size: core::mem::size_of::<Self>(),
224            struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
225            kind: RnsEmbeddedV1EventKind::StatusChanged,
226            event_id: 0,
227            epoch: 0,
228            occurred_at_ms: 0,
229            operation_id: 0,
230            has_operation_id: false,
231            run_state: RnsEmbeddedV1RunState::Stopped,
232            lifecycle_state: RnsEmbeddedLifecycleState::Boot,
233            log_level: RnsEmbeddedV1LogLevel::Info,
234            error_code: RnsEmbeddedV1NodeErrorCode::Unknown,
235            frame_kind: 0,
236            sequence: 0,
237            bytes: 0,
238            extension_id: 0,
239            value0: 0,
240            value1: 0,
241            reserved: [0; 24],
242        }
243    }
244}
245
246#[repr(C)]
247#[derive(Debug, Clone, Copy)]
248pub struct RnsEmbeddedV1PollResult {
249    pub struct_size: usize,
250    pub struct_version: u32,
251    pub kind: RnsEmbeddedV1PollResultKind,
252    pub next_event_id: u64,
253    pub epoch: u64,
254    pub reserved: [u8; 24],
255}
256
257impl Default for RnsEmbeddedV1PollResult {
258    fn default() -> Self {
259        Self {
260            struct_size: core::mem::size_of::<Self>(),
261            struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
262            kind: RnsEmbeddedV1PollResultKind::Timeout,
263            next_event_id: 0,
264            epoch: 0,
265            reserved: [0; 24],
266        }
267    }
268}
269
270pub struct RnsEmbeddedNode {
271    runtime: EmbeddedNodeRuntime,
272    store: JournaledEmbeddedStore,
273    transport: BleShimTransport,
274}
275
276pub struct RnsEmbeddedV1Node {
277    node: EmbeddedNode,
278}
279
280pub struct RnsEmbeddedEventSubscription {
281    subscription: EventSubscription,
282}
283
284#[cfg(not(feature = "std"))]
285fn ensure_allocator_ready() {
286    // SAFETY: single-core bring-up for this proof path; repeated calls are idempotent
287    // because the heap is initialized exactly once before any allocation-heavy entrypoint.
288    unsafe {
289        if !RNS_ALLOCATOR_READY {
290            RNS_ALLOCATOR.init(RNS_ALLOCATOR_HEAP.as_mut_ptr() as usize, RNS_ALLOCATOR_HEAP.len());
291            RNS_ALLOCATOR_READY = true;
292        }
293    }
294}
295
296#[cfg(feature = "std")]
297fn ensure_allocator_ready() {}
298
299#[no_mangle]
300pub extern "C" fn rns_embedded_node_config_default() -> RnsEmbeddedNodeConfig {
301    RnsEmbeddedNodeConfig::default()
302}
303
304#[no_mangle]
305pub extern "C" fn rns_embedded_v1_node_config_default() -> RnsEmbeddedV1NodeConfig {
306    RnsEmbeddedV1NodeConfig::default()
307}
308
309#[no_mangle]
310pub extern "C" fn rns_embedded_v1_abi_version() -> u32 {
311    RNS_EMBEDDED_V1_ABI_VERSION
312}
313
314#[no_mangle]
315pub extern "C" fn rns_embedded_v1_get_capabilities(
316    out_capabilities: *mut RnsEmbeddedV1Capabilities,
317) -> RnsEmbeddedStatus {
318    ffi_status_boundary(|| {
319        if out_capabilities.is_null() {
320            return RnsEmbeddedStatus::InvalidArgument;
321        }
322        // SAFETY: `out_capabilities` is validated non-null above and points to
323        // writable caller-provided storage for one `RnsEmbeddedV1Capabilities`.
324        unsafe {
325            *out_capabilities = RnsEmbeddedV1Capabilities::default();
326        }
327        RnsEmbeddedStatus::Ok
328    })
329}
330
331#[no_mangle]
332pub extern "C" fn rns_embedded_v1_node_new() -> *mut RnsEmbeddedV1Node {
333    ffi_ptr_boundary(|| {
334        ensure_allocator_ready();
335        Box::into_raw(Box::new(RnsEmbeddedV1Node { node: EmbeddedNode::new() }))
336    })
337}
338
339#[no_mangle]
340pub extern "C" fn rns_embedded_v1_node_free(node: *mut RnsEmbeddedV1Node) {
341    if node.is_null() {
342        return;
343    }
344    // SAFETY: `node` is allocated by `rns_embedded_v1_node_new` with
345    // `Box::into_raw` and this function takes back ownership exactly once.
346    unsafe {
347        drop(Box::from_raw(node));
348    }
349}
350
351#[no_mangle]
352pub extern "C" fn rns_embedded_node_new(
353    config: *const RnsEmbeddedNodeConfig,
354) -> *mut RnsEmbeddedNode {
355    ensure_allocator_ready();
356    if config.is_null() {
357        return core::ptr::null_mut();
358    }
359    // SAFETY: `config` is checked non-null above and points to a caller-owned
360    // `RnsEmbeddedNodeConfig` that is only read during this call.
361    let config = unsafe { &*config };
362    let runtime = match EmbeddedNodeRuntime::new(RuntimeConfig {
363        store_identity: config.store_identity,
364        lxmf_address: config.lxmf_address,
365        node_mode: match config.node_mode {
366            RnsEmbeddedNodeMode::BleOnly => NodeTransportMode::BleOnly,
367            RnsEmbeddedNodeMode::TcpClient => NodeTransportMode::TcpClient,
368            RnsEmbeddedNodeMode::TcpServer => NodeTransportMode::TcpServer,
369        },
370        announce_interval_ms: config.announce_interval_ms,
371        max_outbound_queue: config.max_outbound_queue,
372        max_events: config.max_events,
373        capture_defaults: CaptureDefaults { max_bytes: config.capture_default_max_bytes },
374    }) {
375        Ok(runtime) => runtime,
376        Err(_) => return core::ptr::null_mut(),
377    };
378    let transport = match BleShimTransport::new(BleShimConfig {
379        mtu_hint: config.ble_mtu_hint,
380        max_inbound_frames: config.ble_max_inbound_frames,
381        max_outbound_frames: config.ble_max_outbound_frames,
382        ordered_delivery: config.ble_ordered_delivery,
383    }) {
384        Ok(transport) => transport,
385        Err(_) => return core::ptr::null_mut(),
386    };
387
388    let node = RnsEmbeddedNode { runtime, store: JournaledEmbeddedStore::new(), transport };
389    Box::into_raw(Box::new(node))
390}
391
392#[no_mangle]
393pub extern "C" fn rns_embedded_node_free(node: *mut RnsEmbeddedNode) {
394    if node.is_null() {
395        return;
396    }
397    // SAFETY: `node` originates from `Box::into_raw` in `rns_embedded_node_new`
398    // and this function takes ownership exactly once to drop it.
399    unsafe {
400        drop(Box::from_raw(node));
401    }
402}
403
404#[no_mangle]
405pub extern "C" fn rns_embedded_node_set_link_state(
406    node: *mut RnsEmbeddedNode,
407    state: RnsEmbeddedLinkState,
408) -> RnsEmbeddedStatus {
409    let Some(node) = node_mut(node) else {
410        return RnsEmbeddedStatus::InvalidArgument;
411    };
412    node.transport.set_link_state(match state {
413        RnsEmbeddedLinkState::Down => LinkState::Down,
414        RnsEmbeddedLinkState::Connecting => LinkState::Connecting,
415        RnsEmbeddedLinkState::Up => LinkState::Up,
416    });
417    RnsEmbeddedStatus::Ok
418}
419
420#[no_mangle]
421pub extern "C" fn rns_embedded_node_tick(
422    node: *mut RnsEmbeddedNode,
423    now_ms: u64,
424) -> RnsEmbeddedStatus {
425    let Some(node) = node_mut(node) else {
426        return RnsEmbeddedStatus::InvalidArgument;
427    };
428    map_status(node.runtime.tick(now_ms, &mut node.transport, &mut node.store))
429}
430
431#[no_mangle]
432pub extern "C" fn rns_embedded_node_set_network_provisioned(
433    node: *mut RnsEmbeddedNode,
434    provisioned: bool,
435) -> RnsEmbeddedStatus {
436    let Some(node) = node_mut(node) else {
437        return RnsEmbeddedStatus::InvalidArgument;
438    };
439    node.runtime.set_network_provisioned(provisioned);
440    RnsEmbeddedStatus::Ok
441}
442
443#[no_mangle]
444pub extern "C" fn rns_embedded_node_set_ble_recovery_active(
445    node: *mut RnsEmbeddedNode,
446    active: bool,
447) -> RnsEmbeddedStatus {
448    let Some(node) = node_mut(node) else {
449        return RnsEmbeddedStatus::InvalidArgument;
450    };
451    node.runtime.set_ble_recovery_active(active);
452    RnsEmbeddedStatus::Ok
453}