Skip to main content

iceoryx2/node/
mod.rs

1// Copyright (c) 2024 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13//! The [`Node`](crate::node::Node) is the central entry point of iceoryx2. It is the owner of all communication
14//! entities and provides additional memory to them to perform reference counting amongst other
15//! things.
16//!
17//! It allows also the system to monitor the state of processes and cleanup stale resources of
18//! dead processes.
19//!
20//! # Create a [`Node`](crate::node::Node)
21//!
22//! ```
23//! use iceoryx2::prelude::*;
24//!
25//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
26//! let node = NodeBuilder::new()
27//!                 .name(&"my_little_node".try_into()?)
28//!                 .create::<ipc::Service>()?;
29//!
30//! println!("created node {:?}", node);
31//! # Ok(())
32//! # }
33//! ```
34//!
35//! # List all existing [`Node`](crate::node::Node)s
36//!
37//! ```
38//! use iceoryx2::prelude::*;
39//!
40//! Node::<ipc::Service>::list(Config::global_config(), |node_state| {
41//!     println!("found node {:?}", node_state);
42//!     CallbackProgression::Continue
43//! });
44//! ```
45//!
46//! # Cleanup stale resources of all dead [`Node`](crate::node::Node)s
47//!
48//! ```
49//! use iceoryx2::prelude::*;
50//!
51//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
52//! Node::<ipc::Service>::list(Config::global_config(), |node_state| {
53//!     if let NodeState::<ipc::Service>::Dead(view) = node_state {
54//!         println!("cleanup resources of dead node {:?}", view);
55//!         if let Err(e) = view.try_remove_stale_resources() {
56//!             println!("failed to cleanup resources due to {:?}", e);
57//!         }
58//!     }
59//!     CallbackProgression::Continue
60//! })?;
61//! # Ok(())
62//! # }
63//! ```
64//!
65//! ## Simple Event Loop
66//!
67//! ```no_run
68//! use core::time::Duration;
69//! use iceoryx2::prelude::*;
70//!
71//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
72//! const CYCLE_TIME: Duration = Duration::from_secs(1);
73//! let node = NodeBuilder::new()
74//!                 .name(&"my_little_node".try_into()?)
75//!                 .create::<ipc::Service>()?;
76//!
77//! while node.wait(CYCLE_TIME).is_ok() {
78//!     // your algorithm in here
79//! }
80//! # Ok(())
81//! # }
82//! ```
83//!
84//! ## Simple Event Loop With Disabled [`Signal`](iceoryx2_bb_posix::signal::Signal) Handling
85//!
86//! This example demonstrates how the [`Node`](crate::node::Node) can be used when system signals
87//! are being handled elsewhere. The builder parameter
88//! [`NodeBuilder::signal_handling_mode()`](crate::node::NodeBuilder::signal_handling_mode())
89//! can be used to disable signal handling in all [`Node`](crate::node::Node) calls like
90//! [`Node::wait()`](crate::node::Node::wait()).
91//!
92//! ```no_run
93//! use core::time::Duration;
94//! use iceoryx2::prelude::*;
95//!
96//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
97//! const CYCLE_TIME: Duration = Duration::from_secs(1);
98//! let node = NodeBuilder::new()
99//!                 .name(&"my_little_node".try_into()?)
100//!                 // disable signal handling
101//!                 .signal_handling_mode(SignalHandlingMode::Disabled)
102//!                 .create::<ipc::Service>()?;
103//!
104//! while node.wait(CYCLE_TIME).is_ok() {
105//!     // your algorithm in here
106//! }
107//! # Ok(())
108//! # }
109//! ```
110//!
111//! ## Advanced Event Loop
112//!
113//! ```no_run
114//! use core::time::Duration;
115//! use iceoryx2::node::NodeWaitFailure;
116//! use iceoryx2::prelude::*;
117//!
118//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
119//! const CYCLE_TIME: Duration = Duration::from_secs(1);
120//! let node = NodeBuilder::new()
121//!                 .name(&"my_little_node".try_into()?)
122//!                 .create::<ipc::Service>()?;
123//!
124//! loop {
125//!     match node.wait(CYCLE_TIME) {
126//!         Ok(()) => {
127//!             println!("entered next cycle");
128//!         }
129//!         Err(NodeWaitFailure::TerminationRequest) => {
130//!             println!("User pressed CTRL+c, terminating");
131//!             break;
132//!         }
133//!         Err(NodeWaitFailure::Interrupt) => {
134//!             println!("Someone send an interrupt signal ...");
135//!         }
136//!     }
137//! }
138//! # Ok(())
139//! # }
140//! ```
141
142pub(crate) mod global_management_segment;
143/// The name for a node.
144pub mod node_name;
145
146use core::fmt::Debug;
147use core::marker::PhantomData;
148use core::ptr::NonNull;
149use core::time::Duration;
150use iceoryx2_bb_concurrency::atomic::Ordering;
151
152use alloc::collections::BTreeMap;
153use alloc::format;
154use alloc::string::String;
155use alloc::string::ToString;
156use alloc::sync::Arc;
157use alloc::vec;
158use alloc::vec::Vec;
159
160use iceoryx2_bb_concurrency::atomic::AtomicBool;
161use iceoryx2_bb_concurrency::cell::UnsafeCell;
162use iceoryx2_bb_container::semantic_string::SemanticString;
163use iceoryx2_bb_derive_macros::ZeroCopySend;
164use iceoryx2_bb_elementary::CallbackProgression;
165use iceoryx2_bb_elementary::scope_guard::ScopeGuardBuilder;
166use iceoryx2_bb_elementary_traits::testing::abandonable::Abandonable;
167use iceoryx2_bb_elementary_traits::zero_copy_send::ZeroCopySend;
168use iceoryx2_bb_posix::adaptive_wait::{AdaptiveWaitBuilder, AdaptiveWaitStrategy};
169use iceoryx2_bb_posix::clock::Time;
170use iceoryx2_bb_posix::clock::{NanosleepError, nanosleep};
171use iceoryx2_bb_posix::mutex::Handle;
172use iceoryx2_bb_posix::mutex::Mutex;
173use iceoryx2_bb_posix::mutex::MutexBuilder;
174use iceoryx2_bb_posix::mutex::MutexHandle;
175use iceoryx2_bb_posix::mutex::MutexType;
176use iceoryx2_bb_posix::process::Process;
177use iceoryx2_bb_posix::process::ProcessId;
178use iceoryx2_bb_posix::signal::SignalHandler;
179use iceoryx2_bb_system_types::file_name::FileName;
180use iceoryx2_cal::bag::BagFamily;
181use iceoryx2_cal::bag::BagHandleFamily;
182use iceoryx2_cal::named_concept::{NamedConceptPathHintRemoveError, NamedConceptRemoveError};
183use iceoryx2_cal::{
184    monitoring::*, named_concept::NamedConceptListError, serialize::*, static_storage::*,
185};
186use iceoryx2_log::{debug, fail, fatal_panic, trace, warn};
187
188use crate::identifiers::UniqueNodeId;
189use crate::node::node_name::NodeName;
190use crate::prelude::MessagingPattern;
191use crate::service::ServiceRemoveError;
192use crate::service::builder::{Builder, OpenDynamicStorageFailure};
193use crate::service::config_scheme::port_tag_config;
194use crate::service::config_scheme::{
195    node_details_path, node_monitoring_config, service_tag_config,
196};
197use crate::service::service_hash::ServiceHash;
198use crate::service::service_name::ServiceName;
199use crate::service::stale_resource_cleanup::RemoveStalePortResourcesError;
200use crate::service::stale_resource_cleanup::remove_stale_port_resources;
201use crate::service::{self, ServiceRemoveNodeError};
202use crate::signal_handling_mode::SignalHandlingMode;
203use crate::unique_id_generator::*;
204use crate::{config::Config, service::config_scheme::node_details_config};
205
206impl UniqueNodeId {
207    pub(crate) fn as_file_name(&self) -> FileName {
208        fatal_panic!(from self, when FileName::new(self.0.value().to_string().as_bytes()),
209                        "This should never happen! The NodeId shall be always a valid FileName.")
210    }
211}
212
213/// The failures that can occur when a [`Node`] is created with the [`NodeBuilder`].
214#[derive(Debug, Copy, Clone, PartialEq, Eq)]
215pub enum NodeCreationFailure {
216    /// The [`Node`] could not be created since the process does not have sufficient permissions.
217    InsufficientPermissions,
218    /// Errors that indicate either an implementation issue or a wrongly configured system.
219    InternalError,
220    /// Indicates that another "instance" on the system removed the resource required by the [`Node`].
221    SystemCorrupted,
222    /// The [`UniqueNodeId`] could not be generated.
223    UnableToGenerateUniqueNodeId,
224}
225
226impl core::fmt::Display for NodeCreationFailure {
227    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
228        write!(f, "NodeCreationFailure::{self:?}")
229    }
230}
231
232impl core::error::Error for NodeCreationFailure {}
233
234/// The failures that can occur when a list of [`NodeState`]s is created with [`Node::list()`].
235#[derive(Debug, Copy, Clone, PartialEq, Eq)]
236pub enum NodeWaitFailure {
237    /// The process received an interrupt signal while acquiring the list of all [`Node`]s.
238    Interrupt,
239    /// A termination signal `SIGTERM` was received.
240    TerminationRequest,
241}
242
243impl core::fmt::Display for NodeWaitFailure {
244    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
245        write!(f, "NodeWaitFailure::{self:?}")
246    }
247}
248
249impl core::error::Error for NodeWaitFailure {}
250
251/// The failures that can occur when a list of [`NodeState`]s is created with [`Node::list()`].
252#[derive(Debug, Copy, Clone, PartialEq, Eq)]
253pub enum NodeListFailure {
254    /// A list of all [`Node`]s could not be created since the process does not have sufficient permissions.
255    InsufficientPermissions,
256    /// The process received an interrupt signal while acquiring the list of all [`Node`]s.
257    Interrupt,
258    /// Errors that indicate either an implementation issue or a wrongly configured system.
259    InternalError,
260}
261
262impl core::fmt::Display for NodeListFailure {
263    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
264        write!(f, "NodeListFailure::{self:?}")
265    }
266}
267
268impl core::error::Error for NodeListFailure {}
269
270/// Failures of [`DeadNodeView::try_remove_stale_resources()`] that occur when the stale resources of
271/// a dead [`Node`] are removed.
272#[derive(Debug, Copy, Clone, PartialEq, Eq)]
273pub enum NodeCleanupFailure {
274    /// The process received an interrupt signal while cleaning up all stale resources of a dead [`Node`].
275    Interrupt,
276    /// Errors that indicate either an implementation issue or a wrongly configured system.
277    InternalError,
278    /// The stale resources of a dead [`Node`] could not be removed since the process does not have sufficient permissions.
279    InsufficientPermissions,
280    /// Trying to cleanup resources from a dead [`Node`] which was using a different iceoryx2 version.
281    VersionMismatch,
282    /// Another instance has successfully cleaned up all resources.
283    ResourcesAlreadyCleanedUp,
284    /// Another instance has acquired the ownership of all resources and is currently cleaning up.
285    AnotherInstanceIsCleaningUpTheNode,
286}
287
288impl core::fmt::Display for NodeCleanupFailure {
289    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
290        write!(f, "NodeCleanupFailure::{self:?}")
291    }
292}
293
294impl core::error::Error for NodeCleanupFailure {}
295
296#[derive(Debug, Copy, Clone, PartialEq, Eq)]
297enum NodeReadStorageFailure {
298    ReadError,
299    InsufficientPermissions,
300    Corrupted,
301    Interrupt,
302    InternalError,
303}
304
305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
306enum NodeReadServiceTagsFailure {
307    InsufficientPermissions,
308    InternalError,
309}
310
311#[derive(Debug, Copy, Clone, PartialEq, Eq)]
312enum NodeReadPortTagsFailure {
313    InsufficientPermissions,
314    InternalError,
315}
316
317/// Optional detailed information that a [`Node`] can have. They can only be obtained when the
318/// process has sufficient access permissions.
319#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
320pub struct NodeDetails {
321    executable: FileName,
322    process: ProcessId,
323    name: NodeName,
324    config: Config,
325}
326
327impl NodeDetails {
328    #[doc(hidden)]
329    pub fn __internal_new(node_name: &Option<NodeName>, config: &Config) -> Self {
330        Self::new(node_name, config)
331    }
332
333    fn new(node_name: &Option<NodeName>, config: &Config) -> Self {
334        let process = Process::from_self();
335
336        let executable = match process.executable() {
337            Ok(n) => n.file_name(),
338            Err(e) => {
339                debug!(from "NodeDetails::new()", "Unable to acquire executable name of the Node's process ({:?}).", e);
340                const FALLBACK_EXEC: &[u8] = b"undefined";
341                unsafe { FileName::new_unchecked(FALLBACK_EXEC) }
342            }
343        };
344
345        Self {
346            executable,
347            process: process.id(),
348            name: if let Some(name) = node_name {
349                name.clone()
350            } else {
351                NodeName::new("").expect("An empty NodeName is always valid.")
352            },
353            config: config.clone(),
354        }
355    }
356
357    /// Returns the executable [`FileName`] of the [`Node`]s owner process.
358    pub fn executable(&self) -> &FileName {
359        &self.executable
360    }
361
362    /// Returns the [`ProcessId`] of the [`Node`]s owner process.
363    pub fn process_id(&self) -> ProcessId {
364        self.process
365    }
366
367    /// Returns the [`NodeName`]. Multiple [`Node`]s are allowed to have the same [`NodeName`], it
368    /// is not unique!
369    pub fn name(&self) -> &NodeName {
370        &self.name
371    }
372
373    /// Returns the [`Config`] the [`Node`] uses to create all entities.
374    pub fn config(&self) -> &Config {
375        &self.config
376    }
377}
378
379/// The current state of the [`Node`]. If the [`Node`] is dead all of its resources can be removed
380/// with [`DeadNodeView::try_remove_stale_resources()`].
381#[derive(Debug)]
382pub enum NodeState<Service: service::Service> {
383    /// The [`Node`]s process is still alive.
384    Alive(AliveNodeView<Service>),
385    /// The [`Node`]s process died without cleaning up the [`Node`]s resources. Another process has
386    /// now the responsibility to cleanup all the stale resources.
387    Dead(DeadNodeView<Service>),
388    /// The process does not have sufficient permissions to identify the [`Node`] as dead or alive.
389    Inaccessible(UniqueNodeId),
390    /// The [`Node`] is in an undefined state, meaning that certain elements are missing,
391    /// misconfigured or inconsistent. This can only happen due to an implementation failure or
392    /// when the corresponding [`Node`] resources were altered.
393    Undefined(UniqueNodeId),
394}
395
396impl<Service: service::Service> Clone for NodeState<Service> {
397    fn clone(&self) -> Self {
398        match self {
399            NodeState::Alive(n) => NodeState::Alive(n.clone()),
400            NodeState::Dead(n) => NodeState::Dead(n.clone()),
401            NodeState::Inaccessible(n) => NodeState::Inaccessible(*n),
402            NodeState::Undefined(n) => NodeState::Undefined(*n),
403        }
404    }
405}
406
407impl<Service: service::Service> NodeState<Service> {
408    pub(crate) fn new(
409        node_id: &UniqueNodeId,
410        config: &Config,
411    ) -> Result<Option<Self>, NodeListFailure> {
412        let details = Node::<Service>::get_node_details(config, node_id).unwrap_or_default();
413
414        let node_view = AliveNodeView::<Service> {
415            id: *node_id,
416            details,
417            _service: PhantomData,
418        };
419
420        match Node::<Service>::get_node_state(config, node_id) {
421            Ok(State::DoesNotExist) => Ok(None),
422            Ok(State::Alive) => Ok(Some(NodeState::Alive(node_view))),
423            Ok(State::Dead) => Ok(Some(NodeState::Dead(DeadNodeView(node_view)))),
424            Err(NodeListFailure::InsufficientPermissions) => {
425                Ok(Some(NodeState::Inaccessible(*node_id)))
426            }
427            Err(NodeListFailure::InternalError) => Ok(Some(NodeState::Undefined(*node_id))),
428            Err(e) => Err(e),
429        }
430    }
431
432    /// Returns the [`UniqueNodeId`] of the corresponding [`Node`].
433    pub fn node_id(&self) -> &UniqueNodeId {
434        match self {
435            NodeState::Dead(node) => node.id(),
436            NodeState::Alive(node) => node.id(),
437            NodeState::Inaccessible(node_id) => node_id,
438            NodeState::Undefined(node_id) => node_id,
439        }
440    }
441}
442
443/// Returned by [`Node::try_cleanup_dead_nodes()`]. Contains the cleanup report of the call
444/// and contains the number of dead nodes that were successfully cleaned up and how many
445/// could not be cleaned up.
446/// This does not have to be an error, for instance when the current process does not
447/// have the permission to access the corresponding resources.
448#[derive(Debug, Clone, Copy, PartialEq, Eq, ZeroCopySend)]
449#[repr(C)]
450pub struct CleanupState {
451    /// The number of successful dead node cleanups
452    pub cleanups: u64,
453    /// The number of failed dead node cleanups
454    pub failed_cleanups: u64,
455}
456
457/// Contains all available details of a [`Node`].
458pub trait NodeView {
459    /// Returns the [`UniqueNodeId`] of the [`Node`].
460    fn id(&self) -> &UniqueNodeId;
461    /// Returns the [`NodeDetails`].
462    fn details(&self) -> &Option<NodeDetails>;
463}
464
465/// All the information of a [`Node`] that is alive.
466#[derive(Debug)]
467pub struct AliveNodeView<Service: service::Service> {
468    id: UniqueNodeId,
469    details: Option<NodeDetails>,
470    _service: PhantomData<Service>,
471}
472
473impl<Service: service::Service> Clone for AliveNodeView<Service> {
474    fn clone(&self) -> Self {
475        Self {
476            id: self.id,
477            details: self.details.clone(),
478            _service: PhantomData,
479        }
480    }
481}
482
483impl<Service: service::Service> NodeView for AliveNodeView<Service> {
484    fn id(&self) -> &UniqueNodeId {
485        &self.id
486    }
487
488    fn details(&self) -> &Option<NodeDetails> {
489        &self.details
490    }
491}
492
493/// All the information and management operations belonging to a dead [`Node`].
494#[derive(Debug)]
495pub struct DeadNodeView<Service: service::Service>(AliveNodeView<Service>);
496
497impl<Service: service::Service> Clone for DeadNodeView<Service> {
498    fn clone(&self) -> Self {
499        Self(self.0.clone())
500    }
501}
502
503impl<Service: service::Service> NodeView for DeadNodeView<Service> {
504    fn id(&self) -> &UniqueNodeId {
505        self.0.id()
506    }
507
508    fn details(&self) -> &Option<NodeDetails> {
509        self.0.details()
510    }
511}
512
513impl<Service: service::Service> DeadNodeView<Service> {
514    #[doc(hidden)]
515    pub fn __internal_try_remove_stale_resources(
516        id: UniqueNodeId,
517        details: NodeDetails,
518    ) -> Result<(), NodeCleanupFailure> {
519        DeadNodeView(AliveNodeView {
520            id,
521            details: Some(details),
522            _service: PhantomData::<Service>,
523        })
524        .try_remove_stale_resources()
525    }
526
527    #[doc(hidden)]
528    pub fn __internal_blocking_remove_stale_resources(
529        id: UniqueNodeId,
530        details: NodeDetails,
531        timeout: Duration,
532    ) -> Result<(), NodeCleanupFailure> {
533        DeadNodeView(AliveNodeView {
534            id,
535            details: Some(details),
536            _service: PhantomData::<Service>,
537        })
538        .blocking_remove_stale_resources(timeout)
539    }
540
541    /// Removes all stale resources of a dead [`Node`]. If another instance
542    /// is already removing the dead [`Node`] it waits until the other instance
543    /// has cleaned up the dead [`Node`] completely. If the other cleanup instance
544    /// crashes, it will take over the ownership and continue the cleanup.
545    /// If the process does not have the permission to cleanup all resources it
546    /// aborts with an error.
547    ///
548    /// If the provided timeout is expired it will return with
549    /// [`NodeCleanupFailure::AnotherInstanceIsCleaningUpTheNode`].
550    pub fn blocking_remove_stale_resources(
551        self,
552        timeout: Duration,
553    ) -> Result<(), NodeCleanupFailure> {
554        let msg = "Unable to block until the stale resources of the dead node are removed";
555        let mut adaptive_wait = fail!(from self,
556                                        when AdaptiveWaitBuilder::new()
557                                                .strategy(AdaptiveWaitStrategy::FixedTicks(Duration::from_millis(1)))
558                                                .create(),
559                                        with NodeCleanupFailure::InternalError,
560                                       "{msg} since the adaptive wait builder could not be initiated.");
561        let start = fail!(from self,
562                          when Time::now(),
563                          with NodeCleanupFailure::InternalError,
564                          "{msg} since the current system time could not be acquired.");
565
566        loop {
567            match self.remove_stale_resources_impl() {
568                Ok(()) | Err(NodeCleanupFailure::ResourcesAlreadyCleanedUp) => return Ok(()),
569                Err(NodeCleanupFailure::AnotherInstanceIsCleaningUpTheNode) => (),
570                Err(e) => return Err(e),
571            }
572
573            fail!(from self,
574                  when adaptive_wait.wait(),
575                  with NodeCleanupFailure::InternalError,
576                  "{msg} since the adaptive wait failed.");
577
578            let elapsed = fail!(from self,
579                                when start.elapsed(),
580                                with NodeCleanupFailure::InternalError,
581                                "{msg} due to a failure while acquiring the elapsed time.");
582
583            if elapsed > timeout {
584                fail!(from self, with NodeCleanupFailure::AnotherInstanceIsCleaningUpTheNode,
585                    "{msg} since another instance requires longer than {timeout:?} to cleanup the resources.");
586            }
587        }
588    }
589
590    /// Tries to remove all stale resources of a dead [`Node`]. If another instance
591    /// is already removing the dead [`Node`] or the [`Node`] is already removed it will
592    /// return immediately.
593    pub fn try_remove_stale_resources(self) -> Result<(), NodeCleanupFailure> {
594        self.remove_stale_resources_impl()
595    }
596
597    fn remove_stale_resources_impl(&self) -> Result<(), NodeCleanupFailure> {
598        let msg = "Unable to remove stale resources";
599        let monitor_name = fatal_panic!(from self,
600                            when FileName::new(self.id().0.value().to_string().as_bytes()),
601                            "This should never happen! {msg} since the NodeId is not a valid file name.");
602
603        // The cleaner guarantees that the lock can be acquired only once in the inter-process context.
604        // But the same process could acquire the same cleaner multiple times. To avoid intra-process
605        // races an additional lock is introduced so that only one thread can call
606        // remove_stale_resources.
607        static IN_CLEANUP_SECTION: AtomicBool = AtomicBool::new(false);
608
609        let _cleanup_section_guard = ScopeGuardBuilder::new(&IN_CLEANUP_SECTION)
610            .on_init(|v| {
611                // if swap returns true, someone else is holding the lock
612                if v.swap(true, Ordering::Relaxed) {
613                    fail!(from self, with NodeCleanupFailure::AnotherInstanceIsCleaningUpTheNode,
614                        "{msg} since another instance is already cleaning up the dead nodes resources.");
615                }
616
617                Ok(())
618            })
619            .on_drop(|v| v.store(false, Ordering::Relaxed))
620            .create()?;
621
622        let config = if let Some(d) = self.details() {
623            d.config()
624        } else {
625            Config::global_config()
626        };
627
628        let cleaner = fail!(from self, when self.acquire_cleaner_lock(&monitor_name, config),
629                        "{} since the monitor cleaner lock could not be acquired.", msg);
630
631        let mut cleanup_failure = Ok(());
632        let remove_node_from_service = |service_hash: &ServiceHash| {
633            match Service::__internal_remove_node_from_service(self.id(), service_hash, config) {
634                Ok(()) => (),
635                Err(ServiceRemoveNodeError::VersionMismatch) => {
636                    cleanup_failure = Err(NodeCleanupFailure::VersionMismatch);
637                    debug!(from self,
638                        "{msg} since the dead node was using a different iceoryx2 version.");
639                }
640                Err(ServiceRemoveNodeError::Interrupt) => {
641                    cleanup_failure = Err(NodeCleanupFailure::Interrupt);
642                    debug!(from self,
643                        "{msg} since an interrupt signal was raised while removing the node from the service.");
644                }
645                Err(ServiceRemoveNodeError::InsufficientPermissions) => {
646                    cleanup_failure = Err(NodeCleanupFailure::InsufficientPermissions);
647                    debug!(from self,
648                        "{msg} since an interrupt signal was raised while removing the node from the service.");
649                }
650                Err(ServiceRemoveNodeError::InternalError) => {
651                    cleanup_failure = Err(NodeCleanupFailure::InternalError);
652                    debug!(from self,
653                        "{msg} since an internal failure occurred while removing the node from the service.");
654                }
655            }
656            CallbackProgression::Continue
657        };
658
659        // the tags need to be removed at the end of the cleanup process; at first the service tags
660        match Node::<Service>::service_tags(config, self.id(), remove_node_from_service) {
661            Ok(()) => (),
662            Err(NodeReadServiceTagsFailure::InsufficientPermissions) => {
663                cleaner.abandon();
664                fail!(from self, with NodeCleanupFailure::InsufficientPermissions,
665                    "{} since the service tags could not be read due to insufficient permissions.", msg);
666            }
667            Err(NodeReadServiceTagsFailure::InternalError) => {
668                cleaner.abandon();
669                fail!(from self, with NodeCleanupFailure::InternalError,
670                    "{} since the service tags could not be read due to an internal error.", msg);
671            }
672        };
673
674        cleanup_failure?;
675
676        // remove the port tags last, after the ports have been removed from the service;
677        // now, everything not belonging to a service can be removed
678        match Node::<Service>::port_tags(config, self.id(), |port_id| {
679            match unsafe { remove_stale_port_resources::<Service>(self.id(), port_id, config) } {
680                Ok(()) => CallbackProgression::Continue,
681                Err(RemoveStalePortResourcesError::InsufficientPermissions) => {
682                    cleanup_failure = Err(NodeCleanupFailure::InsufficientPermissions);
683                    debug!(from self,
684                        "{} since the stale resources of the port {port_id} could not be removed due to insufficient permissions.", msg);
685                    CallbackProgression::Stop
686                }
687                Err(RemoveStalePortResourcesError::VersionMismatch) => {
688                    cleanup_failure = Err(NodeCleanupFailure::VersionMismatch);
689                    debug!(from self,
690                        "{} since the stale resources of the port {port_id} could not be removed since the iceoryx2 version does not match.", msg);
691                    CallbackProgression::Stop
692                }
693                Err(RemoveStalePortResourcesError::InternalError) => {
694                    cleanup_failure = Err(NodeCleanupFailure::InternalError);
695                    debug!(from self,
696                        "{} since the stale resources of the port {port_id} could not be removed due to an internal failure.", msg);
697                    CallbackProgression::Stop
698                }
699                Err(RemoveStalePortResourcesError::Interrupt) => {
700                    cleanup_failure = Err(NodeCleanupFailure::Interrupt);
701                    debug!(from self,
702                        "{} since the stale resources of the port {port_id} could not be removed due to an interrupt signal.", msg);
703                    CallbackProgression::Stop
704                }
705            }
706        }) {
707            Ok(()) => (),
708            Err(NodeReadPortTagsFailure::InsufficientPermissions) => {
709                cleaner.abandon();
710                fail!(from self, with NodeCleanupFailure::InsufficientPermissions,
711                    "{} since the port tags could not be read due to insufficient permissions.", msg);
712            }
713            Err(NodeReadPortTagsFailure::InternalError) => {
714                cleaner.abandon();
715                fail!(from self, with NodeCleanupFailure::InternalError,
716                    "{} since the port tags could not be read due to an internal error.", msg);
717            }
718        }
719
720        cleanup_failure?;
721
722        match remove_node::<Service>(*self.id(), config) {
723            Ok(_) => {
724                drop(cleaner);
725                Ok(())
726            }
727            Err(e) => {
728                cleaner.abandon();
729                fail!(from self, with e, "{} since the node itself could not be removed.", msg);
730            }
731        }
732    }
733
734    fn acquire_cleaner_lock(
735        &self,
736        monitor_name: &FileName,
737        config: &Config,
738    ) -> Result<<Service::Monitoring as Monitoring>::Cleaner, NodeCleanupFailure> {
739        let msg = "Unable to acquire monitor cleaner";
740
741        match <Service::Monitoring as Monitoring>::Builder::new(monitor_name)
742            .config(&node_monitoring_config::<Service>(config))
743            .cleaner()
744        {
745            Ok(cleaner) => Ok(cleaner),
746            Err(MonitoringCreateCleanerError::AlreadyOwnedByAnotherInstance)
747            | Err(
748                MonitoringCreateCleanerError::IsBeingCleanedUpOrAnotherCleanerCrashedDuringCleanup,
749            ) => {
750                fail!(from self, with NodeCleanupFailure::AnotherInstanceIsCleaningUpTheNode,
751                    "{} since another instance is already cleaning up all resources.", msg);
752            }
753            Err(MonitoringCreateCleanerError::DoesNotExist) => {
754                fail!(from self, with NodeCleanupFailure::ResourcesAlreadyCleanedUp,
755                    "{} since another instance has already cleaned up all resources.", msg);
756            }
757            Err(MonitoringCreateCleanerError::Interrupt) => {
758                fail!(from self, with NodeCleanupFailure::Interrupt,
759                    "{} since an interrupt signal was received.", msg);
760            }
761            Err(MonitoringCreateCleanerError::InternalError) => {
762                fail!(from self, with NodeCleanupFailure::InternalError,
763                    "{} due to an internal error while acquiring monitoring cleaner.", msg);
764            }
765            Err(MonitoringCreateCleanerError::InstanceStillAlive) => {
766                fatal_panic!(from self,
767                        "This should never happen! {} since the Node is still alive.", msg);
768            }
769        }
770    }
771}
772
773fn acquire_all_node_detail_storages<Service: service::Service>(
774    origin: &str,
775    config: &<Service::StaticStorage as NamedConceptMgmt>::Configuration,
776) -> Result<Vec<FileName>, NodeCleanupFailure> {
777    let msg = "Unable to list all node detail storages";
778    match <Service::StaticStorage as NamedConceptMgmt>::list_cfg(config) {
779        Ok(v) => Ok(v),
780        Err(NamedConceptListError::InsufficientPermissions) => {
781            fail!(from origin, with NodeCleanupFailure::InsufficientPermissions,
782                "{} due to insufficient permissions.", msg);
783        }
784        Err(NamedConceptListError::InternalError) => {
785            fail!(from origin, with NodeCleanupFailure::InternalError,
786                "{} due to an internal error.", msg);
787        }
788    }
789}
790
791fn remove_detail_storages<Service: service::Service>(
792    origin: &str,
793    storages: Vec<FileName>,
794    config: &<Service::StaticStorage as NamedConceptMgmt>::Configuration,
795) -> Result<(), NodeCleanupFailure> {
796    let msg = "Unable to remove node detail storage";
797    for entry in storages {
798        match unsafe { <Service::StaticStorage as NamedConceptMgmt>::remove_cfg(&entry, config) } {
799            Ok(_) => (),
800            Err(NamedConceptRemoveError::InsufficientPermissions) => {
801                fail!(from origin, with NodeCleanupFailure::InsufficientPermissions,
802                    "{} {} due to insufficient permissions.", msg, entry);
803            }
804            Err(NamedConceptRemoveError::InternalError) => {
805                fail!(from origin, with NodeCleanupFailure::InternalError,
806                    "{} {} due to an internal failure.", msg, entry);
807            }
808            Err(NamedConceptRemoveError::Interrupt) => {
809                fail!(from origin, with NodeCleanupFailure::Interrupt,
810                    "{} {} since an interrupt signal was raised.", msg, entry);
811            }
812        }
813    }
814
815    Ok(())
816}
817
818fn remove_node_details_directory<Service: service::Service>(
819    config: &Config,
820    node_id: &UniqueNodeId,
821) -> Result<(), NodeCleanupFailure> {
822    let origin = format!("remove_node_details_directory({config:?}, {node_id:?})");
823    let msg = "Unable to remove node details directory";
824    let path = node_details_path(config, node_id);
825    match <Service::StaticStorage as NamedConceptMgmt>::remove_path_hint(&path) {
826        Ok(()) => Ok(()),
827        Err(NamedConceptPathHintRemoveError::InsufficientPermissions) => {
828            fail!(from origin, with NodeCleanupFailure::InsufficientPermissions,
829                "{} due to insufficient permissions.", msg);
830        }
831        Err(NamedConceptPathHintRemoveError::InternalError) => {
832            fail!(from origin, with NodeCleanupFailure::InternalError,
833                "{} due to an internal error.", msg);
834        }
835    }
836}
837
838fn remove_node<Service: service::Service>(
839    id: UniqueNodeId,
840    config: &Config,
841) -> Result<bool, NodeCleanupFailure> {
842    let origin = format!(
843        "remove_node<{}>({:?})",
844        core::any::type_name::<Service>(),
845        id
846    );
847
848    let details_config = node_details_config::<Service>(config, &id);
849    let detail_storages = acquire_all_node_detail_storages::<Service>(&origin, &details_config)?;
850    remove_detail_storages::<Service>(&origin, detail_storages, &details_config)?;
851    remove_node_details_directory::<Service>(config, &id)?;
852
853    Ok(true)
854}
855
856#[derive(Debug)]
857pub(crate) struct RegisteredServices<BagHandle: BagHandleFamily> {
858    handle: MutexHandle<BTreeMap<ServiceHash, (BagHandle, u64)>>,
859}
860
861impl<BagHandle: BagHandleFamily> RegisteredServices<BagHandle> {
862    pub(crate) fn new() -> Self {
863        let origin = "RegisteredServices::new()";
864        let handle = MutexHandle::new();
865
866        fatal_panic!(
867            from origin,
868            when MutexBuilder::new()
869                .is_interprocess_capable(false)
870                .mutex_type(MutexType::Normal)
871                .create(BTreeMap::new(), &handle),
872            "Failed to create mutex"
873        );
874
875        Self { handle }
876    }
877
878    fn insert(
879        services: &mut BTreeMap<ServiceHash, (BagHandle, u64)>,
880        service_hash: ServiceHash,
881        handle: BagHandle,
882    ) {
883        if services.insert(service_hash, (handle, 1)).is_some() {
884            fatal_panic!(from "RegisteredServices::insert()",
885                "This should never happen! The service with the {:?} was already registered.",
886                service_hash);
887        }
888    }
889
890    pub(crate) fn add(&self, service_hash: &ServiceHash, handle: BagHandle) {
891        let mut guard = fatal_panic!(
892            from self,
893            when self.mutex().lock(),
894            "Failed to lock mutex"
895        );
896
897        Self::insert(&mut guard, *service_hash, handle);
898    }
899
900    pub(crate) fn add_or<F: FnMut() -> Result<BagHandle, OpenDynamicStorageFailure>>(
901        &self,
902        service_hash: &ServiceHash,
903        mut or_callback: F,
904    ) -> Result<(), OpenDynamicStorageFailure> {
905        let mut guard = fatal_panic!(
906            from self,
907            when self.mutex().lock(),
908            "Failed to lock mutex"
909        );
910
911        match guard.get_mut(service_hash) {
912            Some(entry) => {
913                entry.1 += 1;
914            }
915            None => {
916                let new_handle = or_callback()?;
917                Self::insert(&mut guard, *service_hash, new_handle);
918            }
919        };
920        Ok(())
921    }
922
923    pub(crate) fn remove<F: FnMut(BagHandle)>(
924        &self,
925        service_hash: &ServiceHash,
926        mut cleanup_call: F,
927    ) {
928        let mut guard = self.mutex().lock().expect("Failed to lock mutex");
929
930        if let Some(entry) = guard.get_mut(service_hash) {
931            entry.1 -= 1;
932            if entry.1 == 0 {
933                let handle = entry.0;
934                guard.remove(service_hash);
935                cleanup_call(handle);
936            }
937        } else {
938            fatal_panic!(from "RegisteredServices::remove()",
939                "This should never happen! The service with the {:?} was not registered.", service_hash);
940        }
941
942        drop(guard);
943    }
944
945    fn mutex(&self) -> Mutex<'_, '_, BTreeMap<ServiceHash, (BagHandle, u64)>> {
946        // Safe - the mutex is initialized when constructing the struct and
947        // not interacted with by anything else.
948        unsafe { Mutex::from_handle(&self.handle) }
949    }
950}
951
952#[derive(Debug)]
953struct SharedNodeState<Service: service::Service> {
954    id: UniqueNodeId,
955    details: NodeDetails,
956    monitoring_token: UnsafeCell<Option<<Service::Monitoring as Monitoring>::Token>>,
957    registered_services: RegisteredServices<<Service::Bag as BagFamily>::BagHandle>,
958    signal_handling_mode: SignalHandlingMode,
959    details_storage: Service::StaticStorage,
960}
961
962unsafe impl<Service: service::Service> Send for SharedNodeState<Service> {}
963unsafe impl<Service: service::Service> Sync for SharedNodeState<Service> {}
964
965impl<Service: service::Service> Abandonable for SharedNodeState<Service> {
966    unsafe fn abandon_in_place(mut this: NonNull<Self>) {
967        let this = unsafe { this.as_mut() };
968        unsafe {
969            <Service::StaticStorage as Abandonable>::abandon_in_place(NonNull::from_mut(
970                &mut this.details_storage,
971            ))
972        };
973        if let Some(token) = this.monitoring_token.get_mut() {
974            unsafe {
975                <<Service::Monitoring as Monitoring>::Token as Abandonable>::abandon_in_place(
976                    NonNull::from_mut(token),
977                )
978            };
979        }
980    }
981}
982
983impl<Service: service::Service> SharedNodeState<Service> {
984    pub(crate) fn blocking_cleanup_dead_nodes(&self, timeout: Duration) -> CleanupState {
985        let mut cleanup_state = CleanupState {
986            cleanups: 0,
987            failed_cleanups: 0,
988        };
989        let origin = format!(
990            "Node::<{}>::cleanup_dead_nodes()",
991            core::any::type_name::<Service>()
992        );
993
994        let cleanup_call = |node_state| {
995            if let NodeState::Dead(dead_node) = node_state {
996                let node_id = *dead_node.id();
997                debug!(from origin, "Dead node ({:?}) detected", node_id);
998                match dead_node.blocking_remove_stale_resources(timeout) {
999                    Ok(_) => {
1000                        cleanup_state.cleanups += 1;
1001                        trace!(from origin, "The dead node ({:?}) was successfully removed.", node_id)
1002                    }
1003                    Err(e) => {
1004                        cleanup_state.failed_cleanups += 1;
1005                        trace!(from origin, "Unable to remove dead node {:?} ({:?}).", node_id, e)
1006                    }
1007                }
1008            }
1009
1010            CallbackProgression::Continue
1011        };
1012
1013        match Node::<Service>::list(&self.details.config, cleanup_call) {
1014            Ok(()) => cleanup_state,
1015            Err(e) => {
1016                debug!(from origin, "Unable to perform a full scan for dead nodes since the all existing nodes could not be listed ({:?}).", e);
1017                cleanup_state
1018            }
1019        }
1020    }
1021}
1022
1023impl<Service: service::Service> Drop for SharedNodeState<Service> {
1024    fn drop(&mut self) {
1025        let config = self.details.config();
1026        if self.monitoring_token.get_mut().is_some() {
1027            if config.global.node.cleanup_dead_nodes_on_destruction {
1028                self.blocking_cleanup_dead_nodes(Duration::ZERO);
1029            }
1030
1031            warn!(from self, when remove_node::<Service>(self.id, config),
1032                "Unable to remove node resources.");
1033        }
1034
1035        trace!(from self, "removed");
1036    }
1037}
1038
1039#[derive(Debug, Clone)]
1040pub(crate) struct SharedNode<Service: service::Service> {
1041    state: Arc<SharedNodeState<Service>>,
1042}
1043
1044impl<Service: service::Service> Abandonable for SharedNode<Service> {
1045    unsafe fn abandon_in_place(mut this: NonNull<Self>) {
1046        let this = unsafe { this.as_mut() };
1047        if let Some(state) = Arc::get_mut(&mut this.state) {
1048            unsafe { SharedNodeState::abandon_in_place(NonNull::from_mut(state)) };
1049        } else {
1050            unsafe { core::ptr::drop_in_place(&mut this.state) };
1051        }
1052    }
1053}
1054
1055impl<Service: service::Service> SharedNode<Service> {
1056    pub(crate) fn config(&self) -> &Config {
1057        &self.state.details.config
1058    }
1059
1060    pub(crate) fn id(&self) -> &UniqueNodeId {
1061        &self.state.id
1062    }
1063
1064    pub(crate) fn registered_services(
1065        &self,
1066    ) -> &RegisteredServices<<Service::Bag as BagFamily>::BagHandle> {
1067        &self.state.registered_services
1068    }
1069
1070    pub(crate) fn name(&self) -> &NodeName {
1071        &self.state.details.name
1072    }
1073
1074    pub(crate) fn create_port_tag(
1075        &self,
1076        origin: &str,
1077        msg: &str,
1078        port_id: u128,
1079    ) -> Result<Service::StaticStorage, StaticStorageCreateError> {
1080        let name = FileName::new(port_id.to_string().as_bytes())
1081            .expect("A number is always a valid file name.");
1082
1083        match <<Service::StaticStorage as StaticStorage>::Builder as NamedConceptBuilder<
1084            Service::StaticStorage,
1085        >>::new(&name)
1086        .config(&port_tag_config::<Service>(self.config(), self.id()))
1087        .has_ownership(true)
1088        .create(&[])
1089        {
1090            Ok(static_storage) => Ok(static_storage),
1091            Err(e) => {
1092                fail!(from origin, with e,
1093                    "{msg} since the port tag could not be created. [{e:?}]");
1094            }
1095        }
1096    }
1097
1098    pub(crate) fn create_service_tag<T: Debug + ?Sized>(
1099        &self,
1100        origin: &T,
1101        msg: &str,
1102        service_hash: &ServiceHash,
1103    ) -> Result<Option<Service::StaticStorage>, StaticStorageCreateError> {
1104        match <<Service::StaticStorage as StaticStorage>::Builder as NamedConceptBuilder<
1105            Service::StaticStorage,
1106        >>::new(&service_hash.0.into())
1107        .config(&service_tag_config::<Service>(self.config(), self.id()))
1108        .has_ownership(true)
1109        .create(&[])
1110        {
1111            Ok(static_storage) => Ok(Some(static_storage)),
1112            Err(StaticStorageCreateError::AlreadyExists) => Ok(None),
1113            Err(e) => {
1114                fail!(from origin, with e,
1115                    "{msg} since the service tag could not be created. [{e:?}]");
1116            }
1117        }
1118    }
1119}
1120
1121/// The [`Node`] is the entry point to the whole iceoryx2 infrastructure and owns all entities.
1122///
1123/// As soon as a process crashes other processes can detect dead [`Node`]s via [`Node::list()`]
1124/// and clean up the stale resources - the entities that
1125/// were created via the [`Node`].
1126///
1127/// Can be created via the [`NodeBuilder`].
1128#[derive(Debug)]
1129pub struct Node<Service: service::Service> {
1130    pub(crate) shared: SharedNode<Service>,
1131}
1132
1133unsafe impl<Service: service::Service> Send for Node<Service> {}
1134
1135impl<Service: service::Service> Abandonable for Node<Service> {
1136    unsafe fn abandon_in_place(mut this: NonNull<Self>) {
1137        let this = unsafe { this.as_mut() };
1138        unsafe { SharedNode::abandon_in_place(NonNull::from_mut(&mut this.shared)) };
1139    }
1140}
1141
1142impl<Service: service::Service> Node<Service> {
1143    /// Returns the [`NodeName`].
1144    pub fn name(&self) -> &NodeName {
1145        self.shared.name()
1146    }
1147
1148    /// Returns the [`Config`] that the [`Node`] will use to create any iceoryx2 entity.
1149    pub fn config(&self) -> &Config {
1150        self.shared.config()
1151    }
1152
1153    /// Returns the [`UniqueNodeId`] of the [`Node`].
1154    pub fn id(&self) -> &UniqueNodeId {
1155        self.shared.id()
1156    }
1157
1158    /// Instantiates a [`ServiceBuilder`](Builder) for a service with the provided name.
1159    pub fn service_builder(&self, name: &ServiceName) -> Builder<Service> {
1160        Builder::new(name, self.shared.clone())
1161    }
1162
1163    /// Returns the [`NodeState`] of a specific [`Node`] that has the provided [`UniqueNodeId`].
1164    /// If this [`Node`] does not exist, the function returns [`None`].
1165    pub fn state_of(
1166        config: &Config,
1167        node_id: UniqueNodeId,
1168    ) -> Result<Option<NodeState<Service>>, NodeListFailure> {
1169        let mut node_state = None;
1170        match Node::list(config, |v| {
1171            if *v.node_id() == node_id {
1172                node_state = Some(v);
1173                CallbackProgression::Stop
1174            } else {
1175                CallbackProgression::Continue
1176            }
1177        }) {
1178            Ok(()) => Ok(node_state),
1179            Err(e) => {
1180                fail!(from "Node::state_of()", with e,
1181                    "Unable to acquire the node state of \"{node_id}\" due to a failure while listing all nodes. [{e:?}]");
1182            }
1183        }
1184    }
1185
1186    /// Calls the provided callback for all [`Node`]s in the system under a given [`Config`] and
1187    /// provides [`NodeState<Service>`] as input argument. With every iteration the callback has to
1188    /// return [`CallbackProgression::Continue`] to perform the next iteration or
1189    /// [`CallbackProgression::Stop`] to stop the iteration immediately.
1190    /// ```
1191    /// # use iceoryx2::prelude::*;
1192    /// Node::<ipc::Service>::list(Config::global_config(), |node_state| {
1193    ///     println!("found node {:?}", node_state);
1194    ///     CallbackProgression::Continue
1195    /// });
1196    /// ```
1197    pub fn list<F: FnMut(NodeState<Service>) -> CallbackProgression>(
1198        config: &Config,
1199        mut callback: F,
1200    ) -> Result<(), NodeListFailure> {
1201        let msg = "Unable to iterate over Node list";
1202        let origin = "Node::list()";
1203        let monitoring_config = node_monitoring_config::<Service>(config);
1204
1205        match Self::list_all_nodes(&monitoring_config) {
1206            Ok(node_list) => {
1207                for node_name in node_list {
1208                    // not bad, just found a file that is not a node
1209                    let Ok(node_id) = core::str::from_utf8(node_name.as_bytes()) else {
1210                        continue;
1211                    };
1212                    let node_id = match node_id.parse::<u128>() {
1213                        Ok(v) => UniqueNodeId(unsafe { UniqueId::from_raw_id(v) }),
1214                        Err(_) => continue,
1215                    };
1216
1217                    match NodeState::new(&node_id, config) {
1218                        Ok(Some(node_state)) => {
1219                            if callback(node_state) == CallbackProgression::Stop {
1220                                break;
1221                            }
1222                        }
1223                        Ok(None) => (),
1224                        Err(e) => {
1225                            fail!(from origin, with e,
1226                                "{msg} since the following error occurred ({:?}).", e);
1227                        }
1228                    }
1229                }
1230            }
1231            Err(e) => {
1232                fail!(from origin, with e,
1233                    "{msg} since the node list could not be acquired ({:?}).", e);
1234            }
1235        }
1236
1237        Ok(())
1238    }
1239
1240    fn handle_termination_request(&self, error_msg: &str) -> Result<(), NodeWaitFailure> {
1241        if self.signal_handling_mode() == SignalHandlingMode::HandleTerminationRequests
1242            && SignalHandler::termination_requested()
1243        {
1244            fail!(from self, with NodeWaitFailure::TerminationRequest,
1245                "{error_msg} since a termination request was received.");
1246        }
1247
1248        Ok(())
1249    }
1250
1251    /// Waits until the cycle time has passed. It returns [`NodeWaitFailure::TerminationRequest`]
1252    /// when a `SIGTERM` signal was received or [`NodeWaitFailure::Interrupt`] when a `SIGINT`
1253    /// signal was received.
1254    pub fn wait(&self, cycle_time: Duration) -> Result<(), NodeWaitFailure> {
1255        let msg = "Unable to wait on node";
1256        self.handle_termination_request(msg)?;
1257
1258        match nanosleep(cycle_time) {
1259            Ok(()) => {
1260                self.handle_termination_request(msg)?;
1261                Ok(())
1262            }
1263            Err(NanosleepError::InterruptedBySignal(_)) => {
1264                fail!(from self, with NodeWaitFailure::Interrupt,
1265                        "{msg} since a interrupt signal was received.");
1266            }
1267            Err(v) => {
1268                fatal_panic!(from self,
1269                    "Failed to wait with cycle time {:?} in main event look, caused by ({:?}).",
1270                    cycle_time, v);
1271            }
1272        }
1273    }
1274
1275    /// Returns the [`SignalHandlingMode`] with which the [`Node`] was created.
1276    pub fn signal_handling_mode(&self) -> SignalHandlingMode {
1277        self.shared.state.signal_handling_mode
1278    }
1279
1280    /// Removes the stale system resources of all dead [`Node`]s. The dead [`Node`]s are also
1281    /// removed from all registered [`Service`](crate::service::Service)s.
1282    ///
1283    /// If a [`Node`] cannot be cleaned up since the process has insufficient permissions or it
1284    /// is currently being cleaned up by another process then the [`Node`] is skipped.
1285    pub fn try_cleanup_dead_nodes(&self) -> CleanupState {
1286        self.shared
1287            .state
1288            .blocking_cleanup_dead_nodes(Duration::ZERO)
1289    }
1290
1291    /// Removes the stale system resources of all dead [`Node`]s. The dead [`Node`]s are also
1292    /// removed from all registered [`Service`](crate::service::Service)s.
1293    ///
1294    /// If a [`Node`] cannot be cleaned up since the process has insufficient permissions then the
1295    /// [`Node`] is skipped. If it is currently being cleaned up by another process then the
1296    /// cleaner will wait until the timeout as either passed or the cleaned was finished.
1297    ///
1298    /// The timeout is applied to every individual dead [`Node`] the function needs to wait on.
1299    pub fn blocking_cleanup_dead_nodes(&self, timeout: Duration) -> CleanupState {
1300        self.shared.state.blocking_cleanup_dead_nodes(timeout)
1301    }
1302
1303    /// Removes a [`Service`](crate::service::Service) by force. This shall be used if the
1304    /// resources could not be removed in a previous run and now it is no longer possible to
1305    /// open the service.
1306    ///
1307    /// # Safety
1308    ///
1309    ///  * No other process shall use the service.
1310    ///
1311    pub unsafe fn force_remove_service(
1312        &self,
1313        name: &ServiceName,
1314        messaging_pattern: MessagingPattern,
1315    ) -> Result<bool, ServiceRemoveError> {
1316        unsafe { Service::__internal_force_remove_service(name, self.config(), messaging_pattern) }
1317    }
1318
1319    fn list_all_nodes(
1320        config: &<Service::Monitoring as NamedConceptMgmt>::Configuration,
1321    ) -> Result<Vec<FileName>, NodeListFailure> {
1322        let result = <Service::Monitoring as NamedConceptMgmt>::list_cfg(config);
1323
1324        if let Ok(result) = result {
1325            return Ok(result);
1326        }
1327
1328        let msg = "Unable to list all nodes";
1329        let origin = format!("Node::list_all_nodes({config:?})");
1330        match result.err().unwrap() {
1331            NamedConceptListError::InsufficientPermissions => {
1332                fail!(from origin, with NodeListFailure::InsufficientPermissions,
1333                        "{} due to insufficient permissions while listing all nodes.", msg);
1334            }
1335            NamedConceptListError::InternalError => {
1336                fail!(from origin, with NodeListFailure::InternalError,
1337                        "{} due to an internal failure while listing all nodes.", msg);
1338            }
1339        }
1340    }
1341
1342    fn state_from_monitor(
1343        monitor: &<Service::Monitoring as Monitoring>::Monitor,
1344    ) -> Result<State, NodeListFailure> {
1345        let result = monitor.state();
1346
1347        if let Ok(result) = result {
1348            return Ok(result);
1349        }
1350
1351        let msg = "Unable to acquire node state from monitor";
1352        let origin = format!("Node::state_from_monitor({monitor:?})");
1353
1354        match result.err().unwrap() {
1355            MonitoringStateError::InsufficientPermissions => {
1356                fail!(from origin, with NodeListFailure::InsufficientPermissions,
1357                    "{} due to insufficient permissions to acquire the nodes state.", msg);
1358            }
1359            MonitoringStateError::Interrupt => {
1360                fail!(from origin, with NodeListFailure::Interrupt,
1361                    "{} due to an interrupt signal while acquiring the nodes state.", msg);
1362            }
1363            MonitoringStateError::InternalError => {
1364                fail!(from origin, with NodeListFailure::InternalError,
1365                    "{} due to an internal error while acquiring the nodes state.", msg);
1366            }
1367        }
1368    }
1369
1370    fn get_node_state(config: &Config, node_id: &UniqueNodeId) -> Result<State, NodeListFailure> {
1371        let config = node_monitoring_config::<Service>(config);
1372        let result = <Service::Monitoring as Monitoring>::Builder::new(&node_id.as_file_name())
1373            .config(&config)
1374            .monitor();
1375
1376        if let Ok(result) = result {
1377            return Self::state_from_monitor(&result);
1378        }
1379
1380        let msg = "Unable to acquire node monitor";
1381        let origin = format!("Node::get_node_state({config:?}, {node_id:?})");
1382        match result.err().unwrap() {
1383            MonitoringCreateMonitorError::InsufficientPermissions => {
1384                fail!(from origin, with NodeListFailure::InsufficientPermissions,
1385                        "{} due to insufficient permissions while acquiring the node state.", msg);
1386            }
1387            MonitoringCreateMonitorError::Interrupt => {
1388                fail!(from origin, with NodeListFailure::Interrupt,
1389                        "{} since an interrupt was received while acquiring the node state.", msg);
1390            }
1391            MonitoringCreateMonitorError::InternalError
1392            | MonitoringCreateMonitorError::ConceptNameNotSupportedOnPlatform => {
1393                fail!(from origin, with NodeListFailure::InternalError,
1394                        "{} since an internal failure occurred while acquiring the node state.", msg);
1395            }
1396        }
1397    }
1398
1399    fn open_node_storage(
1400        config: &Config,
1401        node_id: &UniqueNodeId,
1402    ) -> Result<Option<Service::StaticStorage>, NodeReadStorageFailure> {
1403        let details_config = node_details_config::<Service>(config, node_id);
1404        let msg = "Unable to open node config storage";
1405        let origin = format!("open_node_storage({config:?}, {node_id:?})");
1406
1407        match <Service::StaticStorage as StaticStorage>::Builder::new(
1408            &FileName::new(b"node").unwrap(),
1409        )
1410        .config(&details_config)
1411        .has_ownership(false)
1412        .open(Duration::ZERO)
1413        {
1414            Ok(result) => Ok(Some(result)),
1415            Err(StaticStorageOpenError::DoesNotExist) => Ok(None),
1416            Err(StaticStorageOpenError::Read) => {
1417                fail!(from origin, with NodeReadStorageFailure::ReadError,
1418                        "{} since the node config storage could not be read.", msg);
1419            }
1420            Err(StaticStorageOpenError::InitializationNotYetFinalized) => {
1421                fail!(from origin, with NodeReadStorageFailure::Corrupted,
1422                        "{} since the node config storage seems to be uninitialized but the state should always be present.", msg);
1423            }
1424            Err(StaticStorageOpenError::InternalError) => {
1425                fail!(from origin, with NodeReadStorageFailure::InternalError,
1426                        "{} due to an internal failure while opening the node config storage.", msg);
1427            }
1428            Err(StaticStorageOpenError::Interrupt) => {
1429                fail!(from origin, with NodeReadStorageFailure::Interrupt,
1430                    "{} since an interrupt signal was raised.", msg);
1431            }
1432            Err(StaticStorageOpenError::InsufficientPermissions) => {
1433                fail!(from origin, with NodeReadStorageFailure::InsufficientPermissions,
1434                    "{} due to insufficient permissions.", msg);
1435            }
1436        }
1437    }
1438
1439    fn get_node_details(
1440        config: &Config,
1441        node_id: &UniqueNodeId,
1442    ) -> Result<Option<NodeDetails>, NodeReadStorageFailure> {
1443        let node_storage = if let Some(n) = Self::open_node_storage(config, node_id)? {
1444            n
1445        } else {
1446            return Ok(None);
1447        };
1448
1449        let mut read_content =
1450            String::from_utf8(vec![b' '; node_storage.len() as usize]).expect("");
1451
1452        let origin = format!("get_node_details({config:?}, {node_id:?})");
1453        let msg = "Unable to read node details";
1454
1455        if node_storage
1456            .read(unsafe { read_content.as_mut_vec() }.as_mut_slice())
1457            .is_err()
1458        {
1459            fail!(from origin, with NodeReadStorageFailure::ReadError,
1460                "{} since the content of the node config storage could not be read.", msg);
1461        }
1462
1463        let node_details = fail!(from origin,
1464                    when Service::ConfigSerializer::deserialize::<NodeDetails>(unsafe { read_content.as_mut_vec()}),
1465                    with NodeReadStorageFailure::Corrupted,
1466                "{} since the contents of the node config storage is corrupted.", msg);
1467
1468        Ok(Some(node_details))
1469    }
1470
1471    fn port_tags<F: FnMut(u128) -> CallbackProgression>(
1472        config: &Config,
1473        node_id: &UniqueNodeId,
1474        mut callback: F,
1475    ) -> Result<(), NodeReadPortTagsFailure> {
1476        let origin = "Node::service_tags()";
1477        let msg = format!("Unable to acquire all port tags of the node {node_id:?}");
1478        match <Service::StaticStorage as NamedConceptMgmt>::list_cfg(&port_tag_config::<Service>(
1479            config, node_id,
1480        )) {
1481            Ok(tags) => {
1482                for tag in &tags {
1483                    if let Ok(v) = tag.to_string().parse::<u128>() {
1484                        if callback(v) == CallbackProgression::Stop {
1485                            break;
1486                        }
1487                    } else {
1488                        continue;
1489                    }
1490                }
1491                Ok(())
1492            }
1493            Err(NamedConceptListError::InsufficientPermissions) => {
1494                fail!(from origin, with NodeReadPortTagsFailure::InsufficientPermissions,
1495                    "{} due to insufficient permissions.", msg);
1496            }
1497            Err(NamedConceptListError::InternalError) => {
1498                fail!(from origin, with NodeReadPortTagsFailure::InternalError,
1499                    "{} due to an internal error.", msg);
1500            }
1501        }
1502    }
1503
1504    fn service_tags<F: FnMut(&ServiceHash) -> CallbackProgression>(
1505        config: &Config,
1506        node_id: &UniqueNodeId,
1507        mut callback: F,
1508    ) -> Result<(), NodeReadServiceTagsFailure> {
1509        let origin = "Node::service_tags()";
1510        let msg = format!("Unable to acquire all service tags of the node {node_id:?}");
1511        match <Service::StaticStorage as NamedConceptMgmt>::list_cfg(
1512            &service_tag_config::<Service>(config, node_id),
1513        ) {
1514            Ok(tags) => {
1515                for tag in &tags {
1516                    if let Ok(v) = tag.try_into() {
1517                        if callback(&ServiceHash(v)) == CallbackProgression::Stop {
1518                            break;
1519                        }
1520                    } else {
1521                        continue;
1522                    }
1523                }
1524                Ok(())
1525            }
1526            Err(NamedConceptListError::InsufficientPermissions) => {
1527                fail!(from origin, with NodeReadServiceTagsFailure::InsufficientPermissions,
1528                    "{} due to insufficient permissions.", msg);
1529            }
1530            Err(NamedConceptListError::InternalError) => {
1531                fail!(from origin, with NodeReadServiceTagsFailure::InternalError,
1532                    "{} due to an internal error.", msg);
1533            }
1534        }
1535    }
1536}
1537
1538/// Creates a [`Node`].
1539///
1540/// ```
1541/// use iceoryx2::prelude::*;
1542///
1543/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
1544/// let node = NodeBuilder::new()
1545///                 .name(&"my_little_node".try_into()?)
1546///                 .create::<ipc::Service>()?;
1547///
1548/// // do things with your cool new node
1549/// # Ok(())
1550/// # }
1551/// ```
1552#[derive(Debug, Default, Clone)]
1553pub struct NodeBuilder {
1554    name: Option<NodeName>,
1555    signal_handling_mode: SignalHandlingMode,
1556    config: Option<Config>,
1557}
1558
1559impl NodeBuilder {
1560    /// Creates a new [`NodeBuilder`]
1561    pub fn new() -> Self {
1562        Self::default()
1563    }
1564
1565    /// Sets the [`NodeName`] of the to be created [`Node`].
1566    pub fn name(mut self, value: &NodeName) -> Self {
1567        self.name = Some(value.clone());
1568        self
1569    }
1570
1571    /// Defines the [`SignalHandlingMode`] for the [`Node`]. It affects the [`Node::wait()`] call
1572    /// that returns any received [`Signal`](iceoryx2_bb_posix::signal::Signal) via its
1573    /// [`NodeWaitFailure`]
1574    pub fn signal_handling_mode(mut self, value: SignalHandlingMode) -> Self {
1575        self.signal_handling_mode = value;
1576        self
1577    }
1578
1579    /// Sets the config of the [`Node`] that will be used to create all entities owned by the
1580    /// [`Node`].
1581    pub fn config(mut self, value: &Config) -> Self {
1582        self.config = Some(value.clone());
1583        self
1584    }
1585
1586    /// Creates a new [`Node`] for a specific [`service::Service`]. All entities owned by the
1587    /// [`Node`] will have the same [`service::Service`].
1588    pub fn create<Service: service::Service>(self) -> Result<Node<Service>, NodeCreationFailure> {
1589        let msg = "Unable to create node";
1590
1591        let config = self
1592            .config
1593            .as_ref()
1594            .unwrap_or_else(|| Config::global_config());
1595
1596        let name = match &self.name {
1597            Some(n) => n.clone(),
1598            None => NodeName::default(),
1599        };
1600        let node_id = fail!(from self, when UniqueNodeId::new::<Service>(name, config),
1601            with NodeCreationFailure::UnableToGenerateUniqueNodeId,
1602            "{msg} since the UniqueNodeId could not be generated.");
1603
1604        let monitor_name = fatal_panic!(from self, when FileName::new(node_id.value().to_string().as_bytes()),
1605                                "This should never happen! {msg} since the UniqueNodeId is not a valid file name.");
1606        let (details_storage, details) =
1607            self.create_node_details_storage::<Service>(config, &node_id)?;
1608        let monitoring_token = self.create_token::<Service>(config, &monitor_name)?;
1609
1610        let state = Arc::new(SharedNodeState {
1611            id: node_id,
1612            monitoring_token: UnsafeCell::new(Some(monitoring_token)),
1613            registered_services: RegisteredServices::new(),
1614            details_storage,
1615            signal_handling_mode: self.signal_handling_mode,
1616            details,
1617        });
1618
1619        if config.global.node.cleanup_dead_nodes_on_creation {
1620            state.blocking_cleanup_dead_nodes(Duration::ZERO);
1621        }
1622
1623        let new_node = Node {
1624            shared: SharedNode { state },
1625        };
1626
1627        trace!(from new_node, "created");
1628        Ok(new_node)
1629    }
1630
1631    fn create_token<Service: service::Service>(
1632        &self,
1633        config: &Config,
1634        monitor_name: &FileName,
1635    ) -> Result<<Service::Monitoring as Monitoring>::Token, NodeCreationFailure> {
1636        let msg = "Unable to create token for new node";
1637        let token_result = <Service::Monitoring as Monitoring>::Builder::new(monitor_name)
1638            .config(&node_monitoring_config::<Service>(config))
1639            .token();
1640
1641        match token_result {
1642            Ok(token) => Ok(token),
1643            Err(MonitoringCreateTokenError::InsufficientPermissions) => {
1644                fail!(from self, with NodeCreationFailure::InsufficientPermissions,
1645                    "{msg} due to insufficient permissions to create a monitor token.");
1646            }
1647            Err(MonitoringCreateTokenError::AlreadyExists) => {
1648                fatal_panic!(from self,
1649                    "This should never happen! {msg} since a node with the same UniqueNodeId already exists.");
1650            }
1651            Err(MonitoringCreateTokenError::InternalError) => {
1652                fail!(from self, with NodeCreationFailure::InternalError,
1653                    "{msg} since the monitor token could not be created.");
1654            }
1655            Err(MonitoringCreateTokenError::SystemCorrupted) => {
1656                fail!(from self, with NodeCreationFailure::SystemCorrupted,
1657                    "{msg} since some external instance removed the underlying resources of the monitoring token.");
1658            }
1659        }
1660    }
1661
1662    fn create_node_details_storage<Service: service::Service>(
1663        &self,
1664        config: &Config,
1665        node_id: &UniqueNodeId,
1666    ) -> Result<(Service::StaticStorage, NodeDetails), NodeCreationFailure> {
1667        let msg = "Unable to create node details storage";
1668        let details = NodeDetails::new(&self.name, config);
1669
1670        let details_config = node_details_config::<Service>(&details.config, node_id);
1671        let serialized_details = match <Service::ConfigSerializer>::serialize(&details) {
1672            Ok(serialized_details) => serialized_details,
1673            Err(SerializeError::InternalError) => {
1674                fail!(from self, with NodeCreationFailure::InternalError,
1675                    "{msg} since the node details could not be serialized.");
1676            }
1677        };
1678
1679        match <Service::StaticStorage as StaticStorage>::Builder::new(
1680            &FileName::new(b"node").unwrap(),
1681        )
1682        .config(&details_config)
1683        .has_ownership(false)
1684        .create(&serialized_details)
1685        {
1686            Ok(node_details) => Ok((node_details, details)),
1687            Err(StaticStorageCreateError::InsufficientPermissions) => {
1688                fail!(from self, with NodeCreationFailure::InsufficientPermissions,
1689                    "{msg} due to insufficient permissions to create the node details file.");
1690            }
1691            Err(StaticStorageCreateError::AlreadyExists) => {
1692                fatal_panic!(from self,
1693                    "This should never happen! {msg} since the node details file already exists.");
1694            }
1695            Err(e) => {
1696                fail!(from self, with NodeCreationFailure::InternalError,
1697                    "{msg} due to an unknown failure while creating the node details file {:?}.", e);
1698            }
1699        }
1700    }
1701}