pub(crate) mod stale_resource_cleanup;
pub mod builder;
pub mod dynamic_config;
pub mod header;
pub mod messaging_pattern;
pub mod port_factory;
pub mod service_name;
pub mod service_hash;
pub mod static_config;
pub mod attribute;
pub mod local;
pub mod local_threadsafe;
pub mod ipc;
pub mod ipc_threadsafe;
pub(crate) mod config_scheme;
pub(crate) mod naming_scheme;
use core::fmt::Debug;
use core::ptr::NonNull;
use core::time::Duration;
use alloc::format;
use alloc::string::String as CoreString;
use alloc::string::ToString;
use alloc::sync::Arc;
use alloc::vec;
use alloc::vec::Vec;
use iceoryx2_bb_elementary_traits::non_null::NonNullCompat;
use iceoryx2_bb_elementary_traits::testing::abandonable::Abandonable;
use iceoryx2_bb_posix::file::AccessMode;
use crate::config;
use crate::constants::MAX_TYPE_NAME_LENGTH;
use crate::identifiers::{UniqueNodeId, UniquePortId};
use crate::node::{NodeListFailure, NodeState, SharedNode};
use crate::service::config_scheme::{dynamic_config_storage_config, port_tag_config};
use crate::service::dynamic_config::DynamicConfig;
use crate::service::static_config::*;
use config_scheme::service_tag_config;
use iceoryx2_bb_container::semantic_string::SemanticString;
use iceoryx2_bb_elementary::CallbackProgression;
use iceoryx2_cal::arc_sync_policy::ArcSyncPolicy;
use iceoryx2_cal::dynamic_storage::{
DynamicStorage, DynamicStorageBuilder, DynamicStorageOpenError,
};
use iceoryx2_cal::event::Event;
use iceoryx2_cal::hash::*;
use iceoryx2_cal::monitoring::Monitoring;
use iceoryx2_cal::named_concept::NamedConceptListError;
use iceoryx2_cal::named_concept::*;
use iceoryx2_cal::reactor::Reactor;
use iceoryx2_cal::resizable_shared_memory::ResizableSharedMemoryForPoolAllocator;
use iceoryx2_cal::serialize::Serialize;
use iceoryx2_cal::shared_memory::{SharedMemory, SharedMemoryForPoolAllocator};
use iceoryx2_cal::shm_allocator::bump_allocator::BumpAllocator;
use iceoryx2_cal::static_storage::*;
use iceoryx2_cal::zero_copy_connection::ZeroCopyConnection;
use iceoryx2_log::{debug, error, fail, trace, warn};
use service_hash::ServiceHash;
use self::dynamic_config::DeregisterNodeState;
use self::messaging_pattern::MessagingPattern;
use self::service_name::ServiceName;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ServiceRemoveNodeError {
VersionMismatch,
InternalError,
ServiceInCorruptedState,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ServiceRemoveTagError {
AlreadyRemoved,
InternalError,
InsufficientPermissions,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum PortRemoveTagError {
AlreadyRemoved,
InternalError,
InsufficientPermissions,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ServiceDetailsError {
FailedToOpenStaticServiceInfo,
FailedToReadStaticServiceInfo,
FailedToDeserializeStaticServiceInfo,
ServiceInInconsistentState,
VersionMismatch,
InternalError,
FailedToAcquireNodeState,
}
impl core::fmt::Display for ServiceDetailsError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "ServiceDetailsError::{self:?}")
}
}
impl core::error::Error for ServiceDetailsError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ServiceListError {
InsufficientPermissions,
InternalError,
}
impl core::fmt::Display for ServiceListError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "ServiceListError::{self:?}")
}
}
impl core::error::Error for ServiceListError {}
#[derive(Debug, Clone)]
pub struct ServiceDynamicDetails<S: Service> {
pub nodes: Vec<NodeState<S>>,
}
#[derive(Debug)]
pub struct ServiceDetails<S: Service> {
pub static_details: StaticConfig,
pub dynamic_details: Option<ServiceDynamicDetails<S>>,
}
#[derive(Debug)]
pub struct ServiceState<S: Service, R: ServiceResource> {
pub(crate) dynamic_storage: S::DynamicStorage<DynamicConfig>,
pub(crate) additional_resource: R,
pub(crate) static_config: StaticConfig,
pub(crate) shared_node: SharedNode<S>,
pub(crate) static_storage: S::StaticStorage,
}
impl<S: Service, R: ServiceResource> Abandonable for ServiceState<S, R> {
unsafe fn abandon_in_place(mut this: NonNull<Self>) {
let this = unsafe { this.as_mut() };
unsafe {
S::DynamicStorage::abandon_in_place(NonNull::iox2_from_mut(&mut this.dynamic_storage))
};
unsafe { R::abandon_in_place(NonNull::iox2_from_mut(&mut this.additional_resource)) };
unsafe { SharedNode::<S>::abandon_in_place(NonNull::iox2_from_mut(&mut this.shared_node)) };
unsafe {
S::StaticStorage::abandon_in_place(NonNull::iox2_from_mut(&mut this.static_storage))
};
}
}
#[derive(Debug)]
pub(crate) struct SharedServiceState<S: Service, R: ServiceResource> {
state: Arc<ServiceState<S, R>>,
}
impl<S: Service, R: ServiceResource> Clone for SharedServiceState<S, R> {
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
}
}
}
impl<S: Service, R: ServiceResource> Abandonable for SharedServiceState<S, R> {
unsafe fn abandon_in_place(mut this: NonNull<Self>) {
let this = unsafe { this.as_mut() };
if let Some(state) = Arc::get_mut(&mut this.state) {
unsafe { ServiceState::abandon_in_place(NonNull::iox2_from_mut(state)) };
} else {
unsafe { core::ptr::drop_in_place(&mut this.state) };
}
}
}
impl<S: Service, R: ServiceResource> SharedServiceState<S, R> {
pub(crate) fn static_config(&self) -> &StaticConfig {
&self.state.static_config
}
pub(crate) fn dynamic_storage(&self) -> &S::DynamicStorage<DynamicConfig> {
&self.state.dynamic_storage
}
pub(crate) fn shared_node(&self) -> &SharedNode<S> {
&self.state.shared_node
}
pub(crate) fn additional_resource(&self) -> &R {
&self.state.additional_resource
}
}
impl<S: Service, R: ServiceResource> ServiceState<S, R> {
pub(crate) fn new(
static_config: StaticConfig,
shared_node: SharedNode<S>,
dynamic_storage: S::DynamicStorage<DynamicConfig>,
static_storage: S::StaticStorage,
additional_resource: R,
) -> Self {
let new_self = Self {
static_config,
shared_node,
dynamic_storage,
static_storage,
additional_resource,
};
trace!(from "Service::open()", "open service: {} ({:?})",
new_self.static_config.name(), new_self.static_config.service_hash());
new_self
}
}
impl<S: Service, R: ServiceResource> Drop for ServiceState<S, R> {
fn drop(&mut self) {
let origin = "ServiceState::drop()";
let hash = self.static_config.service_hash();
self.shared_node.registered_services().remove(hash, |handle| {
if let Err(e) = remove_service_tag::<S>(self.shared_node.id(), hash, self.shared_node.config())
{
debug!(from origin, "The service tag could not be removed from the node {:?} ({:?}).",
self.shared_node.id(), e);
}
match self.dynamic_storage.get().deregister_node_id(handle) {
Ok(DeregisterNodeState::HasOwners) => {
trace!(from origin, "close service: {} ({:?})",
self.static_config.name(), hash);
}
Ok(DeregisterNodeState::NoMoreOwners) => {
self.static_storage.acquire_ownership();
self.dynamic_storage.acquire_ownership();
self.additional_resource.acquire_ownership();
trace!(from origin, "close and remove service: {} ({:?})",
self.static_config.name(), hash);
}
Err(e) => {
error!(from origin,
"Unable to deregister node {} from service. This could indicate a corrupted system! [{e:?}]", self.shared_node.id())
}
}
});
}
}
#[doc(hidden)]
pub mod internal {
use builder::event::EventOpenError;
use dynamic_config::PortCleanupAction;
use iceoryx2_bb_container::string::*;
use iceoryx2_log::error;
use port_factory::PortFactory;
use crate::{
identifiers::{UniqueNodeId, UniquePortId},
node::NodeBuilder,
port::{listener::remove_connection_of_listener, notifier::Notifier},
prelude::EventId,
service::stale_resource_cleanup::{
remove_data_segment_of_port, remove_receiver_port_from_all_connections,
remove_sender_port_from_all_connections,
},
};
use super::*;
#[derive(Debug)]
struct CleanupFailure;
fn send_dead_node_signal<S: Service>(service_hash: &ServiceHash, config: &config::Config) {
let origin = "send_dead_node_signal()";
let service_details = match __internal_details::<S>(config, &service_hash.0.into()) {
Ok(Some(service_details)) => service_details,
Ok(None) => return,
Err(e) => {
warn!(from origin,
"Unable to acquire service details to emit dead node signal to waiting listeners for the service id {:?} due to ({:?})",
service_hash, e);
return;
}
};
let service_name = service_details.static_details.name();
let mut config = config.clone();
config.global.node.cleanup_dead_nodes_on_creation = false;
config.global.node.cleanup_dead_nodes_on_destruction = false;
let node = match NodeBuilder::new().config(&config).create::<S>() {
Ok(node) => node,
Err(e) => {
warn!(from origin,
"Unable to create node to emit dead node signal to waiting listeners on the service {} due to ({:?}).",
service_name, e);
return;
}
};
let service = match node.service_builder(service_name).event().open() {
Ok(service) => service,
Err(EventOpenError::DoesNotExist) => return,
Err(e) => {
warn!(from origin,
"Unable to open event service to emit dead node signal to waiting listeners on the service {} due to ({:?}).",
service_name, e);
return;
}
};
if service.dynamic_config().number_of_listeners() == 0 {
return;
}
let event_id = match service.static_config().notifier_dead_event.as_option_ref() {
Some(event_id) => *event_id,
None => return,
};
let notifier = match Notifier::new_without_auto_event_emission(
service.service,
EventId::new(0),
) {
Ok(notifier) => notifier,
Err(e) => {
warn!(from origin,
"Unable to create notifier to send dead node signal to waiting listeners on the service {} due to ({:?})",
service_name, e);
return;
}
};
if let Err(e) = notifier.notify_with_custom_event_id(EventId::new(event_id)) {
warn!(from origin,
"Unable to send dead node signal to waiting listeners on service {} due to ({:?})",
service_name, e);
}
trace!(from origin, "Send dead node signal on service {}.", service_name);
}
fn remove_sender_connection_and_data_segment<S: Service>(
id: u128,
config: &config::Config,
origin: &str,
port_name: &str,
) -> Result<(), CleanupFailure> {
unsafe { remove_sender_port_from_all_connections::<S>(id, config) }.map_err(|e| {
debug!(from origin,
"Failed to remove the {} ({:?}) from all of its connections ({:?}).",
port_name, id, e);
CleanupFailure
})?;
unsafe { remove_data_segment_of_port::<S>(id, config) }.map_err(|e| {
debug!(from origin,
"Failed to remove the {} ({:?}) data segment ({:?}).",
port_name, id, e);
CleanupFailure
})?;
Ok(())
}
fn remove_sender_and_receiver_connections_and_data_segment<S: Service>(
id: u128,
config: &config::Config,
origin: &str,
port_name: &str,
) -> Result<(), CleanupFailure> {
remove_sender_connection_and_data_segment::<S>(id, config, origin, port_name)?;
unsafe { remove_receiver_port_from_all_connections::<S>(id, config) }.map_err(|e| {
debug!(from origin,
"Failed to remove the {} ({:?}) from all of its incoming connections ({:?}).",
port_name, id, e);
CleanupFailure
})?;
Ok(())
}
fn remove_additional_blackboard_resources<S: Service>(
config: &config::Config,
blackboard_name: &FileName,
blackboard_payload_config: &<S::BlackboardPayload as NamedConceptMgmt>::Configuration,
blackboard_mgmt_name: &StaticString<MAX_TYPE_NAME_LENGTH>,
origin: &str,
msg: &str,
) {
match unsafe {
<S::BlackboardPayload as NamedConceptMgmt>::remove_cfg(
blackboard_name,
blackboard_payload_config,
)
} {
Ok(true) => {
trace!(from origin, "Remove blackboard payload segment.");
}
_ => {
error!(from origin,
"{} since the blackboard payload segment cannot be removed - service seems to be in a corrupted state.", msg);
}
}
let mut blackboard_mgmt_config =
crate::service::config_scheme::blackboard_mgmt_config::<S, u64>(config);
unsafe {
<S::BlackboardMgmt<u64> as DynamicStorage<u64>>::__internal_set_type_name_in_config(
&mut blackboard_mgmt_config,
blackboard_mgmt_name.as_str(),
)
};
match unsafe {
<S::BlackboardMgmt<u64> as NamedConceptMgmt>::remove_cfg(
blackboard_name,
&blackboard_mgmt_config,
)
} {
Ok(true) => {
trace!(from origin, "Remove blackboard mgmt segment.");
}
_ => {
error!(from origin, "{} since the blackboard mgmt segment cannot be removed - service seems to be in a corrupted state.", msg);
}
}
}
pub trait ServiceInternal<S: Service> {
fn __internal_remove_node_from_service(
node_id: &UniqueNodeId,
service_hash: &ServiceHash,
config: &config::Config,
) -> Result<(), ServiceRemoveNodeError> {
let origin =
format!("Service::remove_node_from_service({node_id:?}, {service_hash:?})");
let msg = "Unable to remove node from service";
let dynamic_config = match open_dynamic_config::<S>(config, service_hash) {
Ok(Some(c)) => c,
Ok(None) => {
fail!(from origin,
with ServiceRemoveNodeError::ServiceInCorruptedState,
"{} since the dynamic service segment is missing - service seems to be in a corrupted state.", msg);
}
Err(ServiceDetailsError::VersionMismatch) => {
fail!(from origin, with ServiceRemoveNodeError::VersionMismatch,
"{} since the service version does not match.", msg);
}
Err(e) => {
fail!(from origin, with ServiceRemoveNodeError::InternalError,
"{} due to an internal failure ({:?}).", msg, e);
}
};
let mut number_of_dead_node_notifications = 0;
let cleanup_port_resources = |port_id| {
match port_id {
UniquePortId::Publisher(ref id) => {
if remove_sender_connection_and_data_segment::<S>(
id.value(),
config,
&origin,
"publisher",
)
.is_err()
{
return PortCleanupAction::SkipPort;
}
}
UniquePortId::Subscriber(ref id) => {
if let Err(e) = unsafe {
remove_receiver_port_from_all_connections::<S>(id.value(), config)
} {
debug!(from origin, "Failed to remove the subscriber ({:?}) from all of its connections ({:?}).", id, e);
return PortCleanupAction::SkipPort;
}
}
UniquePortId::Notifier(_) => {
number_of_dead_node_notifications += 1;
}
UniquePortId::Listener(ref id) => {
if let Err(e) = unsafe { remove_connection_of_listener::<S>(id, config) } {
debug!(from origin, "Failed to remove the listeners ({:?}) connection ({:?}).", id, e);
return PortCleanupAction::SkipPort;
}
}
UniquePortId::Client(ref id) => {
if remove_sender_and_receiver_connections_and_data_segment::<S>(
id.value(),
config,
&origin,
"client",
)
.is_err()
{
return PortCleanupAction::SkipPort;
}
}
UniquePortId::Server(ref id) => {
if remove_sender_and_receiver_connections_and_data_segment::<S>(
id.value(),
config,
&origin,
"server",
)
.is_err()
{
return PortCleanupAction::SkipPort;
}
}
UniquePortId::Reader(ref _id) => {}
UniquePortId::Writer(ref _id) => {}
};
if let Err(e) = remove_port_tag::<S>(node_id, &port_id, config) {
debug!(from origin, "Failed to remove the port tag for port {:?}. [{e:?}]", port_id);
return PortCleanupAction::SkipPort;
}
trace!(from origin, "Remove port {:?} from service.", port_id);
PortCleanupAction::RemovePort
};
let remove_service = match unsafe {
dynamic_config
.get()
.remove_dead_node_id(node_id, cleanup_port_resources)
} {
DeregisterNodeState::HasOwners => false,
DeregisterNodeState::NoMoreOwners => true,
};
if remove_service {
let blackboard_name =
crate::service::naming_scheme::blackboard_name(service_hash.as_str());
let blackboard_payload_config =
crate::service::config_scheme::blackboard_data_config::<S>(config);
let blackboard_payload = <S::BlackboardPayload as NamedConceptMgmt>::does_exist_cfg(
&blackboard_name,
&blackboard_payload_config,
);
let mut is_blackboard = false;
let mut blackboard_mgmt_name = StaticString::<MAX_TYPE_NAME_LENGTH>::new();
if let Ok(true) = blackboard_payload {
is_blackboard = true;
let details = match __internal_details::<S>(config, &service_hash.0.into()) {
Ok(Some(d)) => d,
_ => {
fail!(from origin,
with ServiceRemoveNodeError::ServiceInCorruptedState,
"{} due to a failure while acquiring the service details.", msg);
}
};
blackboard_mgmt_name =
details.static_details.blackboard().type_details.type_name;
}
match unsafe {
remove_static_service_config::<S>(config, &service_hash.0.into())
} {
Ok(_) => {
trace!(from origin, "Remove unused service.");
if is_blackboard {
remove_additional_blackboard_resources::<S>(
config,
&blackboard_name,
&blackboard_payload_config,
&blackboard_mgmt_name,
&origin,
msg,
);
}
dynamic_config.acquire_ownership()
}
Err(e) => {
error!(from origin, "Unable to remove static config of unused service ({:?}).",
e);
}
}
} else if number_of_dead_node_notifications != 0 {
send_dead_node_signal::<S>(service_hash, config);
}
Ok(())
}
}
}
pub trait ServiceResource: Abandonable {
fn acquire_ownership(&self);
}
#[derive(Debug)]
pub(crate) struct NoResource;
impl ServiceResource for NoResource {
fn acquire_ownership(&self) {}
}
impl Abandonable for NoResource {
unsafe fn abandon_in_place(_this: NonNull<Self>) {}
}
#[allow(private_bounds)]
pub trait Service: Debug + Sized + internal::ServiceInternal<Self> + Clone {
type ServiceNameHasher: Hash;
type StaticStorage: StaticStorage;
type ConfigSerializer: Serialize;
type PersistentDynamicStorage<T: Debug + Send + Sync + 'static>: DynamicStorage<T>;
type DynamicStorage<T: Debug + Send + Sync + 'static>: DynamicStorage<T>;
type SharedMemory: SharedMemoryForPoolAllocator;
type ResizableSharedMemory: ResizableSharedMemoryForPoolAllocator<Self::SharedMemory>;
type Connection: ZeroCopyConnection;
type Event: Event;
type Monitoring: Monitoring;
type Reactor: Reactor;
type ArcThreadSafetyPolicy<T: Send + Debug + Abandonable>: ArcSyncPolicy<T>;
type BlackboardMgmt<T: Send + Sync + Debug + 'static>: DynamicStorage<T>;
type BlackboardPayload: SharedMemory<BumpAllocator>;
fn does_exist(
service_name: &ServiceName,
config: &config::Config,
messaging_pattern: MessagingPattern,
) -> Result<bool, ServiceDetailsError> {
Ok(Self::details(service_name, config, messaging_pattern)?.is_some())
}
fn details(
service_name: &ServiceName,
config: &config::Config,
messaging_pattern: MessagingPattern,
) -> Result<Option<ServiceDetails<Self>>, ServiceDetailsError> {
let service_hash =
ServiceHash::new::<Self::ServiceNameHasher>(service_name, messaging_pattern);
__internal_details::<Self>(config, &service_hash.0.into())
}
fn list<F: FnMut(ServiceDetails<Self>) -> CallbackProgression>(
config: &config::Config,
mut callback: F,
) -> Result<(), ServiceListError> {
let msg = "Unable to list all services";
let origin = "Service::list_from_config()";
let static_storage_config = config_scheme::static_config_storage_config::<Self>(config);
let service_uuids = fail!(from origin,
when <Self::StaticStorage as NamedConceptMgmt>::list_cfg(&static_storage_config),
map NamedConceptListError::InsufficientPermissions => ServiceListError::InsufficientPermissions,
unmatched ServiceListError::InternalError,
"{} due to a failure while collecting all active services for config: {:?}", msg, config);
for uuid in &service_uuids {
if let Ok(Some(service_details)) = __internal_details::<Self>(config, uuid) {
if callback(service_details) == CallbackProgression::Stop {
break;
}
}
}
Ok(())
}
}
pub(crate) unsafe fn remove_static_service_config<S: Service>(
config: &config::Config,
uuid: &FileName,
) -> Result<bool, NamedConceptRemoveError> {
let msg = "Unable to remove static service config";
let origin = "Service::remove_static_service_config()";
let static_storage_config = config_scheme::static_config_storage_config::<S>(config);
match unsafe {
<S::StaticStorage as NamedConceptMgmt>::remove_cfg(uuid, &static_storage_config)
} {
Ok(v) => Ok(v),
Err(e) => {
fail!(from origin, with e, "{msg} due to ({:?}).", e);
}
}
}
#[doc(hidden)]
pub fn __internal_details<S: Service>(
config: &config::Config,
uuid: &FileName,
) -> Result<Option<ServiceDetails<S>>, ServiceDetailsError> {
let msg = "Unable to acquire service details";
let origin = "Service::details()";
let static_storage_config = config_scheme::static_config_storage_config::<S>(config);
let reader = match <<S::StaticStorage as StaticStorage>::Builder as NamedConceptBuilder<
S::StaticStorage,
>>::new(uuid)
.config(&static_storage_config.clone())
.has_ownership(false)
.open(Duration::ZERO)
{
Ok(reader) => reader,
Err(StaticStorageOpenError::DoesNotExist)
| Err(StaticStorageOpenError::InitializationNotYetFinalized) => return Ok(None),
Err(e) => {
fail!(from origin, with ServiceDetailsError::FailedToOpenStaticServiceInfo,
"{} due to a failure while opening the static service info \"{}\" for reading ({:?})",
msg, uuid, e);
}
};
let mut content = CoreString::from_utf8(vec![b' '; reader.len() as usize]).unwrap();
if let Err(e) = reader.read(unsafe { content.as_mut_vec().as_mut_slice() }) {
fail!(from origin, with ServiceDetailsError::FailedToReadStaticServiceInfo,
"{} since the static service info \"{}\" could not be read ({:?}).",
msg, uuid, e );
}
let service_config =
match S::ConfigSerializer::deserialize::<StaticConfig>(unsafe { content.as_mut_vec() }) {
Ok(service_config) => service_config,
Err(e) => {
fail!(from origin, with ServiceDetailsError::FailedToDeserializeStaticServiceInfo,
"{} since the static service info \"{}\" could not be deserialized ({:?}).",
msg, uuid, e );
}
};
if uuid.as_bytes() != service_config.service_hash().0.as_bytes() {
fail!(from origin, with ServiceDetailsError::ServiceInInconsistentState,
"{} since the service {:?} has an inconsistent hash of {} according to config {:?}",
msg, service_config, uuid, config);
}
let dynamic_config = open_dynamic_config::<S>(config, service_config.service_hash())?;
let dynamic_details = if let Some(d) = dynamic_config {
let mut nodes = vec![];
d.get().list_node_ids(|node_id| {
match NodeState::new(node_id, config) {
Ok(Some(state)) => nodes.push(state),
Ok(None)
| Err(NodeListFailure::InsufficientPermissions)
| Err(NodeListFailure::Interrupt) => (),
Err(NodeListFailure::InternalError) => {
debug!(from origin, "Unable to acquire NodeState for service \"{:?}\"", uuid);
}
};
CallbackProgression::Continue
});
Some(ServiceDynamicDetails { nodes })
} else {
None
};
Ok(Some(ServiceDetails {
static_details: service_config,
dynamic_details,
}))
}
fn open_dynamic_config<S: Service>(
config: &config::Config,
service_hash: &ServiceHash,
) -> Result<Option<S::DynamicStorage<DynamicConfig>>, ServiceDetailsError> {
let origin = format!(
"Service::open_dynamic_details<{}>({:?})",
core::any::type_name::<S>(),
service_hash
);
let msg = "Unable to open the services dynamic config";
match
<<S::DynamicStorage<DynamicConfig> as DynamicStorage<
DynamicConfig,
>>::Builder<'_> as NamedConceptBuilder<
S::DynamicStorage<DynamicConfig>,
>>::new(&service_hash.0.into())
.config(&dynamic_config_storage_config::<S>(config))
.has_ownership(false)
.open(AccessMode::ReadWrite) {
Ok(storage) => Ok(Some(storage)),
Err(DynamicStorageOpenError::DoesNotExist) | Err(DynamicStorageOpenError::InitializationNotYetFinalized) => Ok(None),
Err(DynamicStorageOpenError::VersionMismatch) => {
fail!(from origin, with ServiceDetailsError::VersionMismatch,
"{} since there is a version mismatch. Please use the same iceoryx2 version for the whole system.", msg);
}
Err(DynamicStorageOpenError::InternalError) => {
fail!(from origin, with ServiceDetailsError::InternalError,
"{} due to an internal failure while opening the services dynamic config.", msg);
}
}
}
pub(crate) fn remove_service_tag<S: Service>(
node_id: &UniqueNodeId,
service_hash: &ServiceHash,
config: &config::Config,
) -> Result<(), ServiceRemoveTagError> {
let origin = format!(
"remove_service_tag<{}>({:?}, service_hash: {:?})",
core::any::type_name::<S>(),
node_id,
service_hash
);
match unsafe {
<S::StaticStorage as NamedConceptMgmt>::remove_cfg(
&service_hash.0.into(),
&service_tag_config::<S>(config, node_id),
)
} {
Ok(true) => Ok(()),
Ok(false) => {
fail!(from origin, with ServiceRemoveTagError::AlreadyRemoved,
"The service's tag for the node was already removed. This may indicate a corrupted system!");
}
Err(NamedConceptRemoveError::InternalError) => {
fail!(from origin, with ServiceRemoveTagError::InternalError,
"Unable to remove the service's tag for the node due to an internal error.");
}
Err(NamedConceptRemoveError::InsufficientPermissions) => {
fail!(from origin, with ServiceRemoveTagError::InsufficientPermissions,
"Unable to remove the service's tag for the node due to insufficient permissions.");
}
}
}
pub(crate) fn remove_port_tag<S: Service>(
node_id: &UniqueNodeId,
port_id: &UniquePortId,
config: &config::Config,
) -> Result<(), PortRemoveTagError> {
let origin = format!(
"remove_port_tag<{}>({:?}, port_id: {:?})",
core::any::type_name::<S>(),
node_id,
port_id
);
let name = FileName::new(port_id.value().to_string().as_bytes())
.expect("A number is always a valid file name.");
match unsafe {
<S::StaticStorage as NamedConceptMgmt>::remove_cfg(
&name,
&port_tag_config::<S>(config, node_id),
)
} {
Ok(true) => Ok(()),
Ok(false) => {
fail!(from origin, with PortRemoveTagError::AlreadyRemoved,
"The port's tag for the node was already removed. This may indicate a corrupted system!");
}
Err(NamedConceptRemoveError::InternalError) => {
fail!(from origin, with PortRemoveTagError::InternalError,
"Unable to remove the port's tag for the node due to an internal error.");
}
Err(NamedConceptRemoveError::InsufficientPermissions) => {
fail!(from origin, with PortRemoveTagError::InsufficientPermissions,
"Unable to remove the port's tag for the node due to insufficient permissions.");
}
}
}