use alloc::format;
use alloc::vec::Vec;
use iceoryx2_bb_system_types::file_name::FileName;
use iceoryx2_cal::event::NamedConceptMgmt;
use iceoryx2_cal::named_concept::NamedConceptListError;
use iceoryx2_cal::named_concept::NamedConceptRemoveError;
use iceoryx2_cal::zero_copy_connection::{ZeroCopyConnection, ZeroCopyPortRemoveError};
use iceoryx2_log::fail;
use crate::config;
use crate::service;
use crate::service::config_scheme::{data_segment_config, resizable_data_segment_config};
use crate::service::naming_scheme::data_segment_name;
use super::config_scheme::connection_config;
use super::naming_scheme::extract_receiver_port_id_from_connection;
use super::naming_scheme::extract_sender_port_id_from_connection;
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub(crate) enum RemovePortFromAllConnectionsError {
InsufficientPermissions,
VersionMismatch,
InternalError,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub(crate) enum RemoveStalePortResourcesError {
InsufficientPermissions,
VersionMismatch,
InternalError,
}
pub(crate) unsafe fn remove_data_segment_of_port<Service: service::Service>(
port_id: u128,
config: &config::Config,
) -> Result<(), NamedConceptRemoveError> {
let origin = format!(
"remove_data_segment_of_port::<{}>::({:?})",
core::any::type_name::<Service>(),
port_id
);
unsafe {
fail!(from origin, when <Service::SharedMemory as NamedConceptMgmt>::remove_cfg(
&data_segment_name(port_id),
&data_segment_config::<Service>(config),
), "Unable to remove the ports ({port_id}) data segment."
);
fail!(from origin, when <Service::ResizableSharedMemory as NamedConceptMgmt>::remove_cfg(
&data_segment_name(port_id),
&resizable_data_segment_config::<Service>(config),
), "Unable to remove the ports ({port_id}) resizable data segment."
);
}
Ok(())
}
fn connections<Service: service::Service>(
origin: &str,
msg: &str,
config: &<Service::Connection as NamedConceptMgmt>::Configuration,
) -> Result<Vec<FileName>, RemovePortFromAllConnectionsError> {
match <Service::Connection as NamedConceptMgmt>::list_cfg(config) {
Ok(list) => Ok(list),
Err(NamedConceptListError::InsufficientPermissions) => {
fail!(from origin, with RemovePortFromAllConnectionsError::InsufficientPermissions,
"{} due to insufficient permissions to list all connections.", msg);
}
Err(NamedConceptListError::InternalError) => {
fail!(from origin, with RemovePortFromAllConnectionsError::InternalError,
"{} due to an internal error while listing all connections.", msg);
}
}
}
fn handle_port_remove_error(
result: Result<(), ZeroCopyPortRemoveError>,
origin: &str,
msg: &str,
connection: &FileName,
) -> Result<(), RemovePortFromAllConnectionsError> {
match result {
Ok(()) | Err(ZeroCopyPortRemoveError::DoesNotExist) => Ok(()),
Err(ZeroCopyPortRemoveError::InsufficientPermissions) => {
fail!(from origin,
with RemovePortFromAllConnectionsError::InsufficientPermissions,
"{} due to insufficient permissions to remove the connection ({:?}).",
msg, connection);
}
Err(ZeroCopyPortRemoveError::VersionMismatch) => {
fail!(from origin,
with RemovePortFromAllConnectionsError::VersionMismatch,
"{} since connection ({:?}) has a different iceoryx2 version.",
msg, connection);
}
Err(ZeroCopyPortRemoveError::InternalError) => {
fail!(from origin,
with RemovePortFromAllConnectionsError::InternalError,
"{} due to insufficient permissions to remove the connection ({:?}).",
msg, connection);
}
}
}
pub(crate) unsafe fn remove_sender_port_from_all_connections<Service: service::Service>(
port_id: u128,
config: &config::Config,
) -> Result<(), RemovePortFromAllConnectionsError> {
let origin = format!(
"remove_sender_port_from_all_connections::<{}>::({:?})",
core::any::type_name::<Service>(),
port_id
);
let msg = "Unable to remove the sender port from all connections";
let connection_config = connection_config::<Service>(config);
let connection_list = connections::<Service>(&origin, msg, &connection_config)?;
let mut ret_val = Ok(());
for connection in connection_list {
if let Some(sender_port_id) = extract_sender_port_id_from_connection(&connection) {
if sender_port_id == port_id {
let result = handle_port_remove_error(
unsafe { Service::Connection::remove_sender(&connection, &connection_config) },
&origin,
msg,
&connection,
);
if ret_val.is_ok() {
ret_val = result;
}
}
}
}
ret_val
}
pub(crate) unsafe fn remove_receiver_port_from_all_connections<Service: service::Service>(
port_id: u128,
config: &config::Config,
) -> Result<(), RemovePortFromAllConnectionsError> {
let origin = format!(
"remove_receiver_port_from_all_connections::<{}>::({:?})",
core::any::type_name::<Service>(),
port_id
);
let msg = "Unable to remove the receiver port from all connections";
let connection_config = connection_config::<Service>(config);
let connection_list = connections::<Service>(&origin, msg, &connection_config)?;
let mut ret_val = Ok(());
for connection in connection_list {
if let Some(receiver_port_id) = extract_receiver_port_id_from_connection(&connection) {
if receiver_port_id == port_id {
let result = handle_port_remove_error(
unsafe {
Service::Connection::remove_receiver(&connection, &connection_config)
},
&origin,
msg,
&connection,
);
if ret_val.is_ok() {
ret_val = result;
}
}
}
}
ret_val
}
pub(crate) unsafe fn remove_stale_port_resources<Service: service::Service>(
port_id: u128,
config: &config::Config,
) -> Result<(), RemoveStalePortResourcesError> {
let origin = format!(
"remove_stale_port_resources<{}>({}, {:?})",
core::any::type_name::<Service>(),
port_id,
config
);
let msg = "Failed to remove stale port resources";
match unsafe { remove_data_segment_of_port::<Service>(port_id, config) } {
Ok(()) => (),
Err(NamedConceptRemoveError::InsufficientPermissions) => {
fail!(from origin, with RemoveStalePortResourcesError::InsufficientPermissions,
"{msg} due to insufficient permissions to remove the ports data segment.");
}
Err(NamedConceptRemoveError::InternalError) => {
fail!(from origin, with RemoveStalePortResourcesError::InternalError,
"{msg} due to an internal error while removing the ports data segment.");
}
}
for result in [
unsafe { remove_sender_port_from_all_connections::<Service>(port_id, config) },
unsafe { remove_receiver_port_from_all_connections::<Service>(port_id, config) },
] {
match result {
Ok(()) => (),
Err(RemovePortFromAllConnectionsError::InsufficientPermissions) => {
fail!(from origin, with RemoveStalePortResourcesError::InsufficientPermissions,
"{msg} due to insufficient permissions to remove the port from its connections.");
}
Err(RemovePortFromAllConnectionsError::VersionMismatch) => {
fail!(from origin, with RemoveStalePortResourcesError::VersionMismatch,
"{msg} since the port could not be removed from its connection since iceoryx2 version does not match.");
}
Err(RemovePortFromAllConnectionsError::InternalError) => {
fail!(from origin, with RemoveStalePortResourcesError::InternalError,
"{msg} due to an internal error while removing the port from its connection.");
}
}
}
Ok(())
}