diff --git a/iceoryx2-ffi/cxx/CMakeLists.txt b/iceoryx2-ffi/cxx/CMakeLists.txt index 9bfee8b92..5d150350a 100644 --- a/iceoryx2-ffi/cxx/CMakeLists.txt +++ b/iceoryx2-ffi/cxx/CMakeLists.txt @@ -50,6 +50,7 @@ add_library(iceoryx2-cxx-object-lib OBJECT src/messaging_pattern.cpp src/node.cpp src/node_details.cpp + src/node_id.cpp src/node_name.cpp src/node_state.cpp src/notifier.cpp diff --git a/iceoryx2-ffi/cxx/include/iox2/config.hpp b/iceoryx2-ffi/cxx/include/iox2/config.hpp index 05483b54e..70956fb93 100644 --- a/iceoryx2-ffi/cxx/include/iox2/config.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/config.hpp @@ -306,6 +306,9 @@ class Config { friend class ConfigView; friend class config::Global; friend class NodeBuilder; + template + friend class DeadNodeView; + explicit Config(iox2_config_h handle); void drop(); diff --git a/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp b/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp index 3c33ee94b..82dd000db 100644 --- a/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp @@ -53,9 +53,8 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto -from(const iox2::SemanticStringError value) noexcept - -> iox2_semantic_string_error_e { +constexpr auto from( + const iox2::SemanticStringError value) noexcept -> iox2_semantic_string_error_e { switch (value) { case iox2::SemanticStringError::InvalidContent: return iox2_semantic_string_error_e_INVALID_CONTENT; @@ -86,8 +85,8 @@ constexpr auto from(const int value) noexcept -> iox2::S } template <> -constexpr auto from(const iox2::ServiceType value) noexcept - -> iox2_service_type_e { +constexpr auto +from(const iox2::ServiceType value) noexcept -> iox2_service_type_e { switch (value) { case iox2::ServiceType::Ipc: return iox2_service_type_e_IPC; @@ -112,9 +111,8 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto -from(const iox2::NodeCreationFailure value) noexcept - -> iox2_node_creation_failure_e { +constexpr auto from( + const iox2::NodeCreationFailure value) noexcept -> iox2_node_creation_failure_e { switch (value) { case iox2::NodeCreationFailure::InsufficientPermissions: return iox2_node_creation_failure_e_INSUFFICIENT_PERMISSIONS; @@ -145,9 +143,8 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto -from(const iox2::CallbackProgression value) noexcept - -> iox2_callback_progression_e { +constexpr auto from( + const iox2::CallbackProgression value) noexcept -> iox2_callback_progression_e { switch (value) { case iox2::CallbackProgression::Continue: return iox2_callback_progression_e_CONTINUE; @@ -261,9 +258,8 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto -from(const iox2::ServiceDetailsError value) noexcept - -> iox2_service_details_error_e { +constexpr auto from( + const iox2::ServiceDetailsError value) noexcept -> iox2_service_details_error_e { switch (value) { case iox2::ServiceDetailsError::FailedToOpenStaticServiceInfo: return iox2_service_details_error_e_FAILED_TO_OPEN_STATIC_SERVICE_INFO; @@ -341,9 +337,8 @@ constexpr auto from(const int value) noexcept } template <> -constexpr auto -from(const iox2::EventOpenOrCreateError value) noexcept - -> iox2_event_open_or_create_error_e { +constexpr auto from( + const iox2::EventOpenOrCreateError value) noexcept -> iox2_event_open_or_create_error_e { switch (value) { case iox2::EventOpenOrCreateError::OpenDoesNotExist: return iox2_event_open_or_create_error_e_O_DOES_NOT_EXIST; @@ -494,9 +489,8 @@ constexpr auto from(const int value) noexcept -> io } template <> -constexpr auto -from(const iox2::EventCreateError value) noexcept - -> iox2_event_open_or_create_error_e { +constexpr auto from( + const iox2::EventCreateError value) noexcept -> iox2_event_open_or_create_error_e { switch (value) { case iox2::EventCreateError::InsufficientPermissions: return iox2_event_open_or_create_error_e_C_INSUFFICIENT_PERMISSIONS; @@ -670,14 +664,15 @@ constexpr auto from -inline auto from(const iox2::PublishSubscribeOpenError value) noexcept - -> const char* { +inline auto +from(const iox2::PublishSubscribeOpenError value) noexcept -> const + char* { return iox2_pub_sub_open_or_create_error_string(iox::into(value)); } template <> -constexpr auto from(const int value) noexcept - -> iox2::PublishSubscribeCreateError { +constexpr auto +from(const int value) noexcept -> iox2::PublishSubscribeCreateError { const auto error = static_cast(value); switch (error) { case iox2_pub_sub_open_or_create_error_e_C_SERVICE_IN_CORRUPTED_STATE: @@ -723,8 +718,9 @@ constexpr auto from -inline auto from(const iox2::PublishSubscribeCreateError value) noexcept - -> const char* { +inline auto +from(const iox2::PublishSubscribeCreateError value) noexcept -> const + char* { return iox2_pub_sub_open_or_create_error_string(iox::into(value)); } @@ -788,9 +784,8 @@ constexpr auto from -inline auto -from(const iox2::PublishSubscribeOpenOrCreateError value) noexcept - -> const char* { +inline auto from( + const iox2::PublishSubscribeOpenOrCreateError value) noexcept -> const char* { return iox2_pub_sub_open_or_create_error_string(iox::into(value)); } @@ -806,9 +801,8 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto -from(const iox2::NotifierCreateError value) noexcept - -> iox2_notifier_create_error_e { +constexpr auto from( + const iox2::NotifierCreateError value) noexcept -> iox2_notifier_create_error_e { switch (value) { case iox2::NotifierCreateError::ExceedsMaxSupportedNotifiers: return iox2_notifier_create_error_e_EXCEEDS_MAX_SUPPORTED_NOTIFIERS; @@ -837,9 +831,8 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto -from(const iox2::ListenerCreateError value) noexcept - -> iox2_listener_create_error_e { +constexpr auto from( + const iox2::ListenerCreateError value) noexcept -> iox2_listener_create_error_e { switch (value) { case iox2::ListenerCreateError::ExceedsMaxSupportedListeners: return iox2_listener_create_error_e_EXCEEDS_MAX_SUPPORTED_LISTENERS; @@ -868,9 +861,8 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto -from(const iox2::NotifierNotifyError value) noexcept - -> iox2_notifier_notify_error_e { +constexpr auto from( + const iox2::NotifierNotifyError value) noexcept -> iox2_notifier_notify_error_e { switch (value) { case iox2::NotifierNotifyError::EventIdOutOfBounds: return iox2_notifier_notify_error_e_EVENT_ID_OUT_OF_BOUNDS; @@ -934,9 +926,8 @@ constexpr auto from(const int value) noexcept - } template <> -constexpr auto -from(const iox2::PublisherCreateError value) noexcept - -> iox2_publisher_create_error_e { +constexpr auto from( + const iox2::PublisherCreateError value) noexcept -> iox2_publisher_create_error_e { switch (value) { case iox2::PublisherCreateError::ExceedsMaxSupportedPublishers: return iox2_publisher_create_error_e_EXCEEDS_MAX_SUPPORTED_PUBLISHERS; @@ -967,9 +958,8 @@ constexpr auto from(const int value) noexcept } template <> -constexpr auto -from(const iox2::SubscriberCreateError value) noexcept - -> iox2_subscriber_create_error_e { +constexpr auto from( + const iox2::SubscriberCreateError value) noexcept -> iox2_subscriber_create_error_e { switch (value) { case iox2::SubscriberCreateError::BufferSizeExceedsMaxSupportedBufferSizeOfService: return iox2_subscriber_create_error_e_BUFFER_SIZE_EXCEEDS_MAX_SUPPORTED_BUFFER_SIZE_OF_SERVICE; @@ -1010,9 +1000,8 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto -from(const iox2::PublisherSendError value) noexcept - -> iox2_publisher_send_error_e { +constexpr auto from( + const iox2::PublisherSendError value) noexcept -> iox2_publisher_send_error_e { switch (value) { case iox2::PublisherSendError::ConnectionBrokenSincePublisherNoLongerExists: return iox2_publisher_send_error_e_CONNECTION_BROKEN_SINCE_PUBLISHER_NO_LONGER_EXISTS; @@ -1054,9 +1043,8 @@ constexpr auto from(const int value) noexcept } template <> -constexpr auto -from(const iox2::SubscriberReceiveError value) noexcept - -> iox2_subscriber_receive_error_e { +constexpr auto from( + const iox2::SubscriberReceiveError value) noexcept -> iox2_subscriber_receive_error_e { switch (value) { case iox2::SubscriberReceiveError::FailedToEstablishConnection: return iox2_subscriber_receive_error_e_FAILED_TO_ESTABLISH_CONNECTION; @@ -1093,9 +1081,8 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto -from(const iox2::PublisherLoanError value) noexcept - -> iox2_publisher_loan_error_e { +constexpr auto from( + const iox2::PublisherLoanError value) noexcept -> iox2_publisher_loan_error_e { switch (value) { case iox2::PublisherLoanError::ExceedsMaxLoanedSamples: return iox2_publisher_loan_error_e_EXCEEDS_MAX_LOANED_SAMPLES; @@ -1247,9 +1234,8 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto -from(const iox2::ConfigCreationError value) noexcept - -> iox2_config_creation_error_e { +constexpr auto from( + const iox2::ConfigCreationError value) noexcept -> iox2_config_creation_error_e { switch (value) { case iox2::ConfigCreationError::FailedToOpenConfigFile: return iox2_config_creation_error_e_FAILED_TO_OPEN_CONFIG_FILE; @@ -1320,9 +1306,8 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto -from(const iox2::WaitSetCreateError value) noexcept - -> iox2_waitset_create_error_e { +constexpr auto from( + const iox2::WaitSetCreateError value) noexcept -> iox2_waitset_create_error_e { switch (value) { case iox2::WaitSetCreateError::InternalError: return iox2_waitset_create_error_e_INTERNAL_ERROR; @@ -1386,9 +1371,8 @@ constexpr auto from(const int value) noexcept } template <> -constexpr auto -from(const iox2::WaitSetAttachmentError value) noexcept - -> iox2_waitset_attachment_error_e { +constexpr auto from( + const iox2::WaitSetAttachmentError value) noexcept -> iox2_waitset_attachment_error_e { switch (value) { case iox2::WaitSetAttachmentError::AlreadyAttached: return iox2_waitset_attachment_error_e_ALREADY_ATTACHED; @@ -1451,9 +1435,8 @@ inline auto from(const iox2::WaitSetRunError } template <> -constexpr auto -from(const iox2::SignalHandlingMode value) noexcept - -> iox2_signal_handling_mode_e { +constexpr auto from( + const iox2::SignalHandlingMode value) noexcept -> iox2_signal_handling_mode_e { switch (value) { case iox2::SignalHandlingMode::Disabled: return iox2_signal_handling_mode_e_DISABLED; @@ -1492,6 +1475,22 @@ constexpr auto from(const IOX_UNREACHABLE(); } + +template <> +constexpr auto from(const int value) noexcept -> iox2::NodeCleanupFailure { + const auto variant = static_cast(value); + + switch (variant) { + case iox2_node_cleanup_failure_e_INTERRUPT: + return iox2::NodeCleanupFailure::Interrupt; + case iox2_node_cleanup_failure_e_INTERNAL_ERROR: + return iox2::NodeCleanupFailure::InternalError; + case iox2_node_cleanup_failure_e_INSUFFICIENT_PERMISSIONS: + return iox2::NodeCleanupFailure::InsufficientPermissions; + } + + IOX_UNREACHABLE(); +} } // namespace iox #endif diff --git a/iceoryx2-ffi/cxx/include/iox2/event_id.hpp b/iceoryx2-ffi/cxx/include/iox2/event_id.hpp index d85d4e887..b8fbe8465 100644 --- a/iceoryx2-ffi/cxx/include/iox2/event_id.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/event_id.hpp @@ -15,7 +15,6 @@ #include "iox2/internal/iceoryx2.hpp" -#include #include namespace iox2 { diff --git a/iceoryx2-ffi/cxx/include/iox2/node_failure_enums.hpp b/iceoryx2-ffi/cxx/include/iox2/node_failure_enums.hpp index 0b6ab338c..a27a994f4 100644 --- a/iceoryx2-ffi/cxx/include/iox2/node_failure_enums.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/node_failure_enums.hpp @@ -37,6 +37,13 @@ enum class NodeCreationFailure : uint8_t { }; enum class NodeCleanupFailure : uint8_t { + /// The process received an interrupt signal while cleaning up all stale resources of a dead [`Node`]. + Interrupt, + /// Errors that indicate either an implementation issue or a wrongly configured system. + InternalError, + /// The stale resources of a dead [`Node`] could not be removed since the process does not have sufficient + /// permissions. + InsufficientPermissions, }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/node_id.hpp b/iceoryx2-ffi/cxx/include/iox2/node_id.hpp index ef5f22ae8..2d78344c6 100644 --- a/iceoryx2-ffi/cxx/include/iox2/node_id.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/node_id.hpp @@ -13,8 +13,57 @@ #ifndef IOX2_NODE_ID_HPP #define IOX2_NODE_ID_HPP +#include "iox2/iceoryx2.h" +#include "iox2/service_type.hpp" + +#include +#include +#include + namespace iox2 { -class NodeId { }; +class NodeId { + public: + NodeId(const NodeId& rhs); + NodeId(NodeId&& rhs) noexcept; + auto operator=(const NodeId& rhs) -> NodeId&; + auto operator=(NodeId&& rhs) noexcept -> NodeId&; + ~NodeId(); + + /// Returns high bits of the underlying value of the [`NodeId`]. + auto value_high() const -> uint64_t; + + /// Returns low bits of the underlying value of the [`NodeId`]. + auto value_low() const -> uint64_t; + + /// Returns the [`ProcessId`] of the process that owns the [`Node`]. + auto pid() const -> int32_t; + + /// Returns the time the [`Node`] was created. + auto creation_time() const -> timespec; + + private: + template + friend class Node; + template + friend class DeadNodeView; + template + friend auto list_callback(iox2_node_state_e, + iox2_node_id_ptr, + const char*, + iox2_node_name_ptr, + iox2_config_ptr, + iox2_callback_context) -> iox2_callback_progression_e; + + + explicit NodeId(iox2_node_id_h handle); + void drop(); + + iox2_node_id_h m_handle = nullptr; +}; + +auto operator<<(std::ostream& stream, const NodeId& node) -> std::ostream&; +auto operator==(const NodeId& lhs, const NodeId& rhs) -> bool; +auto operator!=(const NodeId& lhs, const NodeId& rhs) -> bool; } // namespace iox2 #endif diff --git a/iceoryx2-ffi/cxx/include/iox2/node_state.hpp b/iceoryx2-ffi/cxx/include/iox2/node_state.hpp index b6212b504..90124a08b 100644 --- a/iceoryx2-ffi/cxx/include/iox2/node_state.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/node_state.hpp @@ -33,7 +33,7 @@ class AliveNodeView { auto operator=(AliveNodeView&&) -> AliveNodeView& = default; ~AliveNodeView() = default; - AliveNodeView(const NodeId& node_id, const iox::optional& details); + AliveNodeView(NodeId node_id, const iox::optional& details); /// Returns the [`NodeId`]. auto id() const -> const NodeId&; @@ -84,10 +84,6 @@ class NodeState { auto operator=(NodeState&&) -> NodeState& = default; ~NodeState() = default; - explicit NodeState(const AliveNodeView& view); - explicit NodeState(const DeadNodeView& view); - NodeState(iox2_node_state_e node_state, const NodeId& node_id); - /// If the [`Node`] is alive the provided callback is called with an [`AliveNodeView`] /// as argument. auto alive(const iox::function&)>& callback) -> NodeState&; @@ -105,6 +101,19 @@ class NodeState { auto undefined(const iox::function& callback) -> NodeState&; private: + template + // NOLINTBEGIN(readability-function-size) + friend auto list_callback(iox2_node_state_e, + iox2_node_id_ptr, + const char*, + iox2_node_name_ptr, + iox2_config_ptr, + iox2_callback_context) -> iox2_callback_progression_e; + + explicit NodeState(const AliveNodeView& view); + explicit NodeState(const DeadNodeView& view); + NodeState(iox2_node_state_e node_state, const NodeId& node_id); + iox::variant, DeadNodeView, NodeId, NodeId> m_state; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/src/node.cpp b/iceoryx2-ffi/cxx/src/node.cpp index 367e0f261..af60eb44e 100644 --- a/iceoryx2-ffi/cxx/src/node.cpp +++ b/iceoryx2-ffi/cxx/src/node.cpp @@ -61,7 +61,10 @@ auto Node::config() const -> ConfigView { template auto Node::id() const -> NodeId { - IOX_TODO(); + const auto* node_id_ptr = iox2_node_id(&m_handle, iox::into(T)); + iox2_node_id_h node_id_handle = nullptr; + iox2_node_id_clone_from_ptr(nullptr, node_id_ptr, &node_id_handle); + return NodeId(node_id_handle); } template @@ -83,13 +86,13 @@ auto Node::service_builder(const ServiceName& name) const -> ServiceBuilder // NOLINTBEGIN(readability-function-size) auto list_callback(iox2_node_state_e node_state, - iox2_node_id_ptr node_id, + iox2_node_id_ptr node_id_ptr, const char* executable, iox2_node_name_ptr node_name, iox2_config_ptr config, iox2_callback_context context) -> iox2_callback_progression_e { auto node_details = [&] { - if (node_id == nullptr || config == nullptr) { + if (node_id_ptr == nullptr || config == nullptr) { return iox::optional(); } @@ -100,16 +103,20 @@ auto list_callback(iox2_node_state_e node_state, Config {} }); }(); + iox2_node_id_h node_id_handle = nullptr; + iox2_node_id_clone_from_ptr(nullptr, node_id_ptr, &node_id_handle); + NodeId node_id { node_id_handle }; + auto node_state_object = [&] { switch (node_state) { case iox2_node_state_e_ALIVE: - return NodeState { AliveNodeView { NodeId {}, node_details } }; + return NodeState { AliveNodeView { node_id, node_details } }; case iox2_node_state_e_DEAD: - return NodeState { DeadNodeView { AliveNodeView { NodeId {}, node_details } } }; + return NodeState { DeadNodeView { AliveNodeView { node_id, node_details } } }; case iox2_node_state_e_UNDEFINED: - return NodeState { iox2_node_state_e_UNDEFINED, NodeId {} }; + return NodeState { iox2_node_state_e_UNDEFINED, node_id }; case iox2_node_state_e_INACCESSIBLE: - return NodeState { iox2_node_state_e_INACCESSIBLE, NodeId {} }; + return NodeState { iox2_node_state_e_INACCESSIBLE, node_id }; } IOX_UNREACHABLE(); diff --git a/iceoryx2-ffi/cxx/src/node_id.cpp b/iceoryx2-ffi/cxx/src/node_id.cpp new file mode 100644 index 000000000..2f2da6a01 --- /dev/null +++ b/iceoryx2-ffi/cxx/src/node_id.cpp @@ -0,0 +1,100 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#include "iox2/node_id.hpp" + +#include + +namespace iox2 { +NodeId::NodeId(iox2_node_id_h handle) + : m_handle { handle } { +} + +NodeId::NodeId(const NodeId& rhs) { + if (rhs.m_handle != nullptr) { + iox2_node_id_clone_from_handle(nullptr, &rhs.m_handle, &m_handle); + } +} + +NodeId::NodeId(NodeId&& rhs) noexcept + : m_handle { std::move(rhs.m_handle) } { + rhs.m_handle = nullptr; +} + +auto NodeId::operator=(NodeId&& rhs) noexcept -> NodeId& { + if (this != &rhs) { + drop(); + m_handle = std::move(rhs.m_handle); + rhs.m_handle = nullptr; + } + + return *this; +} + +auto NodeId::operator=(const NodeId& rhs) -> NodeId& { + if (this != &rhs) { + drop(); + + if (rhs.m_handle != nullptr) { + iox2_node_id_clone_from_handle(nullptr, &rhs.m_handle, &m_handle); + } + } + + return *this; +} + +NodeId::~NodeId() { + drop(); +} + +void NodeId::drop() { + if (m_handle != nullptr) { + iox2_node_id_drop(m_handle); + m_handle = nullptr; + } +} + +auto NodeId::value_high() const -> uint64_t { + return iox2_node_id_value_high(&m_handle); +} + +auto NodeId::value_low() const -> uint64_t { + return iox2_node_id_value_low(&m_handle); +} + +auto NodeId::pid() const -> int32_t { + return iox2_node_id_pid(&m_handle); +} + +auto NodeId::creation_time() const -> timespec { + uint64_t seconds = 0; + uint32_t nanoseconds = 0; + iox2_node_id_creation_time(&m_handle, &seconds, &nanoseconds); + + return { static_cast(seconds), nanoseconds }; +} + +auto operator<<(std::ostream& stream, const NodeId& node) -> std::ostream& { + stream << "NodeId { value_high: " << node.value_high() << ", value_low: " << node.value_low() + << ", pid: " << node.pid() << ", creation time: " << node.creation_time().tv_sec << "." + << node.creation_time().tv_nsec << "s }"; + return stream; +} + +auto operator==(const NodeId& lhs, const NodeId& rhs) -> bool { + return lhs.value_high() == rhs.value_high() && lhs.value_low() == rhs.value_low(); +} + +auto operator!=(const NodeId& lhs, const NodeId& rhs) -> bool { + return !(lhs == rhs); +} +} // namespace iox2 diff --git a/iceoryx2-ffi/cxx/src/node_state.cpp b/iceoryx2-ffi/cxx/src/node_state.cpp index 96321f596..bb36c2d91 100644 --- a/iceoryx2-ffi/cxx/src/node_state.cpp +++ b/iceoryx2-ffi/cxx/src/node_state.cpp @@ -11,7 +11,6 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT #include "iox2/node_state.hpp" -#include "iox/assertions_addendum.hpp" namespace iox2 { constexpr uint64_t ALIVE_STATE = 0; @@ -20,8 +19,8 @@ constexpr uint64_t INACCESSIBLE_STATE = 2; constexpr uint64_t UNDEFINED_STATE = 3; template -AliveNodeView::AliveNodeView(const NodeId& node_id, const iox::optional& details) - : m_id { node_id } +AliveNodeView::AliveNodeView(NodeId node_id, const iox::optional& details) + : m_id { std::move(node_id) } , m_details { details } { } @@ -52,7 +51,17 @@ auto DeadNodeView::details() const -> iox::optional { template auto DeadNodeView::remove_stale_resources() -> iox::expected { - IOX_TODO(); + bool has_success = false; + auto result = iox2_dead_node_remove_stale_resources(iox::into(T), + &m_view.id().m_handle, + &m_view.details().value().config().m_handle, + &has_success); + + if (result == IOX2_OK) { + return iox::ok(has_success); + } + + return iox::err(iox::into(result)); } template diff --git a/iceoryx2-ffi/cxx/tests/src/node_state_tests.cpp b/iceoryx2-ffi/cxx/tests/src/node_state_tests.cpp index 936204280..a19cca031 100644 --- a/iceoryx2-ffi/cxx/tests/src/node_state_tests.cpp +++ b/iceoryx2-ffi/cxx/tests/src/node_state_tests.cpp @@ -11,7 +11,6 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT #include "iox2/node.hpp" -#include "iox2/node_state.hpp" #include "test.hpp" @@ -32,13 +31,19 @@ TYPED_TEST(NodeStateTest, alive_node_works) { const auto* valid_name = "Which companies middleware could be best described as a dead horse!"; auto node_name = NodeName::create(valid_name).expect(""); auto node = NodeBuilder().name(node_name).create().expect(""); + auto node_id = node.id(); bool alive_node_found = false; + bool has_invalid_state = false; Node::list(node.config(), [&](auto state) { state.alive( [&](auto& view) { alive_node_found = view.details()->name().to_string() == node_name.to_string(); }); + state.dead( + [&](auto& view) { has_invalid_state = view.details()->name().to_string() == node_name.to_string(); }); + state.inaccessible([&](auto& view) { has_invalid_state = view == node_id; }); + state.undefined([&](auto& view) { has_invalid_state = view == node_id; }); - if (alive_node_found) { + if (alive_node_found || has_invalid_state) { return CallbackProgression::Stop; } @@ -47,36 +52,4 @@ TYPED_TEST(NodeStateTest, alive_node_works) { ASSERT_TRUE(alive_node_found); } - -TYPED_TEST(NodeStateTest, inaccessible_node_works) { - constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; - - auto sut = NodeState(iox2_node_state_e_INACCESSIBLE, NodeId {}); - - bool entered_right_callback = false; - bool entered_wrong_callback = false; - sut.alive([&](auto& view) { entered_wrong_callback = true; }); - sut.dead([&](auto& view) { entered_wrong_callback = true; }); - sut.undefined([&](auto& view) { entered_wrong_callback = true; }); - sut.inaccessible([&](auto& view) { entered_right_callback = true; }); - - ASSERT_FALSE(entered_wrong_callback); - ASSERT_TRUE(entered_right_callback); -} - -TYPED_TEST(NodeStateTest, undefined_node_works) { - constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; - - auto sut = NodeState(iox2_node_state_e_UNDEFINED, NodeId {}); - - bool entered_right_callback = false; - bool entered_wrong_callback = false; - sut.alive([&](auto& view) { entered_wrong_callback = true; }); - sut.dead([&](auto& view) { entered_wrong_callback = true; }); - sut.undefined([&](auto& view) { entered_right_callback = true; }); - sut.inaccessible([&](auto& view) { entered_wrong_callback = true; }); - - ASSERT_FALSE(entered_wrong_callback); - ASSERT_TRUE(entered_right_callback); -} } // namespace diff --git a/iceoryx2-ffi/cxx/tests/src/node_tests.cpp b/iceoryx2-ffi/cxx/tests/src/node_tests.cpp index 124e2a391..838758aab 100644 --- a/iceoryx2-ffi/cxx/tests/src/node_tests.cpp +++ b/iceoryx2-ffi/cxx/tests/src/node_tests.cpp @@ -90,4 +90,19 @@ TYPED_TEST(NodeTest, signal_handling_mode_can_be_set) { ASSERT_THAT(sut_1.signal_handling_mode(), Eq(SignalHandlingMode::Disabled)); ASSERT_THAT(sut_2.signal_handling_mode(), Eq(SignalHandlingMode::HandleTerminationRequests)); } + +TYPED_TEST(NodeTest, node_id_is_unique) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + + auto sut_1 = NodeBuilder().create().expect(""); + auto sut_2 = NodeBuilder().create().expect(""); + + auto id_1 = sut_1.id(); + auto id_1_1 = sut_1.id(); + auto id_2 = sut_2.id(); + + ASSERT_THAT(id_1, Eq(id_1_1)); + ASSERT_THAT(id_2, Ne(id_1)); + ASSERT_THAT(id_1.pid(), Eq(id_2.pid())); +} } // namespace diff --git a/iceoryx2-ffi/ffi/src/api/mod.rs b/iceoryx2-ffi/ffi/src/api/mod.rs index f7ed17fe7..84c11dfcd 100644 --- a/iceoryx2-ffi/ffi/src/api/mod.rs +++ b/iceoryx2-ffi/ffi/src/api/mod.rs @@ -32,6 +32,7 @@ mod log; mod message_type_details; mod node; mod node_builder; +mod node_id; mod node_name; mod notifier; mod port_factory_event; @@ -76,6 +77,7 @@ pub use listener::*; pub use message_type_details::*; pub use node::*; pub use node_builder::*; +pub use node_id::*; pub use node_name::*; pub use notifier::*; pub use port_factory_event::*; diff --git a/iceoryx2-ffi/ffi/src/api/node.rs b/iceoryx2-ffi/ffi/src/api/node.rs index 8d07885f6..0740261f0 100644 --- a/iceoryx2-ffi/ffi/src/api/node.rs +++ b/iceoryx2-ffi/ffi/src/api/node.rs @@ -18,7 +18,9 @@ use crate::api::{ AssertNonNullHandle, HandleToType, IntoCInt, ServiceBuilderUnion, IOX2_OK, }; -use iceoryx2::node::{NodeId, NodeListFailure, NodeView, NodeWaitFailure}; +use iceoryx2::node::{ + DeadNodeView, NodeCleanupFailure, NodeDetails, NodeListFailure, NodeView, NodeWaitFailure, +}; use iceoryx2::prelude::*; use iceoryx2_bb_container::semantic_string::SemanticString; use iceoryx2_bb_derive_macros::StringLiteral; @@ -31,7 +33,7 @@ use core::mem::ManuallyDrop; use std::ffi::CString; use std::time::Duration; -use super::iox2_signal_handling_mode_e; +use super::{iox2_config_h_ref, iox2_node_id_h_ref, iox2_node_id_ptr, iox2_signal_handling_mode_e}; // BEGIN type definition @@ -71,6 +73,26 @@ impl IntoCInt for NodeWaitFailure { } } +#[repr(C)] +#[derive(Copy, Clone, StringLiteral)] +pub enum iox2_node_cleanup_failure_e { + INTERRUPT = IOX2_OK as isize + 1, + INTERNAL_ERROR, + INSUFFICIENT_PERMISSIONS, +} + +impl IntoCInt for NodeCleanupFailure { + fn into_c_int(self) -> c_int { + (match self { + NodeCleanupFailure::Interrupt => iox2_node_cleanup_failure_e::INTERRUPT, + NodeCleanupFailure::InternalError => iox2_node_cleanup_failure_e::INTERNAL_ERROR, + NodeCleanupFailure::InsufficientPermissions => { + iox2_node_cleanup_failure_e::INSUFFICIENT_PERMISSIONS + } + }) as c_int + } +} + pub(super) union NodeUnion { ipc: ManuallyDrop>, local: ManuallyDrop>, @@ -162,12 +184,6 @@ pub enum iox2_node_state_e { UNDEFINED, } -// NOTE check the README.md for using opaque types with renaming -/// The immutable pointer to the underlying `NodeId` -pub type iox2_node_id_ptr = *const NodeId; -/// The mutable pointer to the underlying `NodeId` -pub type iox2_node_id_ptr_mut = *mut NodeId; - /// The callback for [`iox2_node_list`] /// /// # Arguments @@ -319,9 +335,51 @@ pub unsafe extern "C" fn iox2_node_signal_handling_mode( /// /// * The `node_handle` must be valid and obtained by [`iox2_node_builder_create`](crate::iox2_node_builder_create)! #[no_mangle] -pub unsafe extern "C" fn iox2_node_id(node_handle: iox2_node_h_ref) -> iox2_node_id_ptr { +pub unsafe extern "C" fn iox2_node_id( + node_handle: iox2_node_h_ref, + service_type: iox2_service_type_e, +) -> iox2_node_id_ptr { node_handle.assert_non_null(); - todo!() // TODO: [#210] implement + + let node = &mut *node_handle.as_type(); + match service_type { + iox2_service_type_e::IPC => node.value.as_ref().ipc.id(), + iox2_service_type_e::LOCAL => node.value.as_ref().local.id(), + } +} + +#[no_mangle] +pub unsafe extern "C" fn iox2_dead_node_remove_stale_resources( + service_type: iox2_service_type_e, + node_id: iox2_node_id_h_ref, + config: iox2_config_h_ref, + has_success: *mut bool, +) -> c_int { + let node_id = (&*node_id.as_type()).value.as_ref(); + let config = (&*config.as_type()).value.as_ref(); + + let result = match service_type { + iox2_service_type_e::IPC => { + DeadNodeView::::__internal_remove_stale_resources( + *node_id, + NodeDetails::__internal_new(&None, &config.value), + ) + } + iox2_service_type_e::LOCAL => { + DeadNodeView::::__internal_remove_stale_resources( + *node_id, + NodeDetails::__internal_new(&None, &config.value), + ) + } + }; + + match result { + Ok(v) => { + *has_success = v; + IOX2_OK + } + Err(e) => e.into_c_int(), + } } fn iox2_node_list_impl( diff --git a/iceoryx2-ffi/ffi/src/api/node_id.rs b/iceoryx2-ffi/ffi/src/api/node_id.rs new file mode 100644 index 000000000..db614e738 --- /dev/null +++ b/iceoryx2-ffi/ffi/src/api/node_id.rs @@ -0,0 +1,175 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#![allow(non_camel_case_types)] + +use crate::api::{AssertNonNullHandle, HandleToType}; + +use iceoryx2::node::NodeId; +use iceoryx2_bb_elementary::static_assert::*; +use iceoryx2_ffi_macros::iceoryx2_ffi; + +// BEGIN type definition + +#[repr(C)] +#[repr(align(8))] // alignment of Option +pub struct iox2_node_id_storage_t { + internal: [u8; 20], // magic number obtained with size_of::>() +} + +#[repr(C)] +#[iceoryx2_ffi(NodeId)] +pub struct iox2_node_id_t { + pub value: iox2_node_id_storage_t, + deleter: fn(*mut iox2_node_id_t), +} + +pub struct iox2_node_id_h_t; +/// The owning handle for `iox2_node_id_t`. Passing the handle to an function transfers the ownership. +pub type iox2_node_id_h = *mut iox2_node_id_h_t; + +/// The non-owning handle for `iox2_node_id_t`. Passing the handle to an function does not transfers the ownership. +pub type iox2_node_id_h_ref = *const iox2_node_id_h; + +// NOTE check the README.md for using opaque types with renaming +/// The immutable pointer to the underlying `NodeId` +pub type iox2_node_id_ptr = *const NodeId; +/// The mutable pointer to the underlying `NodeId` +pub type iox2_node_id_ptr_mut = *mut NodeId; + +impl AssertNonNullHandle for iox2_node_id_h { + fn assert_non_null(self) { + debug_assert!(!self.is_null()); + } +} + +impl AssertNonNullHandle for iox2_node_id_h_ref { + fn assert_non_null(self) { + debug_assert!(!self.is_null()); + unsafe { + debug_assert!(!(*self).is_null()); + } + } +} + +impl HandleToType for iox2_node_id_h { + type Target = *mut iox2_node_id_t; + + fn as_type(self) -> Self::Target { + self as *mut _ as _ + } +} + +impl HandleToType for iox2_node_id_h_ref { + type Target = *mut iox2_node_id_t; + + fn as_type(self) -> Self::Target { + unsafe { *self as *mut _ as _ } + } +} + +// END type definition + +// BEGIN C API +#[no_mangle] +pub unsafe extern "C" fn iox2_node_id_clone_from_ptr( + node_id_struct_ptr: *mut iox2_node_id_t, + node_id_ptr: iox2_node_id_ptr, + node_id_handle_ptr: *mut iox2_node_id_h, +) { + debug_assert!(!node_id_handle_ptr.is_null()); + debug_assert!(!node_id_ptr.is_null()); + + *node_id_handle_ptr = std::ptr::null_mut(); + + let mut node_id_struct_ptr = node_id_struct_ptr; + fn no_op(_: *mut iox2_node_id_t) {} + let mut deleter: fn(*mut iox2_node_id_t) = no_op; + if node_id_struct_ptr.is_null() { + node_id_struct_ptr = iox2_node_id_t::alloc(); + deleter = iox2_node_id_t::dealloc; + } + debug_assert!(!node_id_struct_ptr.is_null()); + + unsafe { + (*node_id_struct_ptr).deleter = deleter; + } + + (*node_id_struct_ptr).value.init((*node_id_ptr).clone()); + *node_id_handle_ptr = (*node_id_struct_ptr).as_handle(); +} + +#[no_mangle] +pub unsafe extern "C" fn iox2_node_id_clone_from_handle( + node_id_struct_ptr: *mut iox2_node_id_t, + node_id_handle: iox2_node_id_h_ref, + node_id_handle_ptr: *mut iox2_node_id_h, +) { + node_id_handle.assert_non_null(); + debug_assert!(!node_id_handle_ptr.is_null()); + + let node_id = &mut *node_id_handle.as_type(); + let node_id_ptr = node_id.value.as_ref(); + + iox2_node_id_clone_from_ptr(node_id_struct_ptr, node_id_ptr, node_id_handle_ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn iox2_node_id_value_high(node_id_handle: iox2_node_id_h_ref) -> u64 { + node_id_handle.assert_non_null(); + + let node_id = &mut *node_id_handle.as_type(); + (node_id.value.as_ref().value() >> 64) as u64 +} + +#[no_mangle] +pub unsafe extern "C" fn iox2_node_id_value_low(node_id_handle: iox2_node_id_h_ref) -> u64 { + node_id_handle.assert_non_null(); + + let node_id = &mut *node_id_handle.as_type(); + ((node_id.value.as_ref().value() << 64) >> 64) as u64 +} + +#[no_mangle] +pub unsafe extern "C" fn iox2_node_id_pid(node_id_handle: iox2_node_id_h_ref) -> i32 { + node_id_handle.assert_non_null(); + + let node_id = &mut *node_id_handle.as_type(); + node_id.value.as_ref().pid().value() +} + +#[no_mangle] +pub unsafe extern "C" fn iox2_node_id_creation_time( + node_id_handle: iox2_node_id_h_ref, + seconds: *mut u64, + nanoseconds: *mut u32, +) { + node_id_handle.assert_non_null(); + debug_assert!(!seconds.is_null()); + debug_assert!(!nanoseconds.is_null()); + + let node_id = &mut *node_id_handle.as_type(); + *seconds = node_id.value.as_ref().creation_time().seconds(); + *nanoseconds = node_id.value.as_ref().creation_time().nanoseconds(); +} + +#[no_mangle] +pub unsafe extern "C" fn iox2_node_id_drop(node_id_handle: iox2_node_id_h) { + debug_assert!(!node_id_handle.is_null()); + + let node_id = &mut *node_id_handle.as_type(); + + std::ptr::drop_in_place(node_id.value.as_option_mut()); + (node_id.deleter)(node_id); +} + +// END C API diff --git a/iceoryx2-ffi/ffi/src/api/quirks_correction.rs b/iceoryx2-ffi/ffi/src/api/quirks_correction.rs index 7ef8be016..26119a0b1 100644 --- a/iceoryx2-ffi/ffi/src/api/quirks_correction.rs +++ b/iceoryx2-ffi/ffi/src/api/quirks_correction.rs @@ -26,7 +26,7 @@ use crate::{ iox2_waitset_create_error_e, iox2_waitset_run_error_e, iox2_waitset_run_result_e, }; -use super::iox2_connection_failure_e; +use super::{iox2_connection_failure_e, iox2_node_cleanup_failure_e}; #[doc(hidden)] #[no_mangle] @@ -211,3 +211,11 @@ pub unsafe extern "C" fn __iox2_internal_waitset_attachment_error_stub( ) -> iox2_waitset_attachment_error_e { iox2_waitset_attachment_error_e::INTERNAL_ERROR } + +#[doc(hidden)] +#[no_mangle] +// TODO: enums are only exported when they are actually used by some function +pub unsafe extern "C" fn __iox2_internal_node_cleanup_failure_stub() -> iox2_node_cleanup_failure_e +{ + iox2_node_cleanup_failure_e::INTERNAL_ERROR +} diff --git a/iceoryx2-ffi/ffi/src/tests/node_tests.rs b/iceoryx2-ffi/ffi/src/tests/node_tests.rs index 71472f4a9..95ac6b299 100644 --- a/iceoryx2-ffi/ffi/src/tests/node_tests.rs +++ b/iceoryx2-ffi/ffi/src/tests/node_tests.rs @@ -15,6 +15,7 @@ mod node { use crate::tests::*; use core::{slice, str}; + use std::ffi::c_char; #[test] fn basic_node_api_test() { @@ -75,6 +76,7 @@ mod node { extern "C" fn node_list_callback( node_state: iox2_node_state_e, _node_id_ptr: iox2_node_id_ptr, + _executable: *const c_char, _node_name_ptr: iox2_node_name_ptr, _config_ptr: iox2_config_ptr, ctx: iox2_callback_context, diff --git a/iceoryx2/src/node/mod.rs b/iceoryx2/src/node/mod.rs index a5d39f930..00bf65c52 100644 --- a/iceoryx2/src/node/mod.rs +++ b/iceoryx2/src/node/mod.rs @@ -300,6 +300,11 @@ pub struct NodeDetails { } impl NodeDetails { + #[doc(hidden)] + pub fn __internal_new(node_name: &Option, config: &Config) -> Self { + Self::new(node_name, config) + } + fn new(node_name: &Option, config: &Config) -> Self { let executable = match Process::from_self().executable() { Ok(n) => n.file_name(), @@ -469,6 +474,19 @@ impl NodeView for DeadNodeView { } impl DeadNodeView { + #[doc(hidden)] + pub fn __internal_remove_stale_resources( + id: NodeId, + details: NodeDetails, + ) -> Result { + DeadNodeView(AliveNodeView { + id, + details: Some(details), + _service: PhantomData::, + }) + .remove_stale_resources() + } + /// Removes all stale resources of a dead [`Node`]. pub fn remove_stale_resources(self) -> Result { let msg = "Unable to remove stale resources";