diff --git a/rcl/include/rcl/node.h b/rcl/include/rcl/node.h index fafaa04df..b9b864358 100644 --- a/rcl/include/rcl/node.h +++ b/rcl/include/rcl/node.h @@ -33,6 +33,8 @@ extern "C" #include "rcl/types.h" #include "rcl/visibility_control.h" +extern const char * const RCL_DISABLE_LOANED_MESSAGES_ENV_VAR; + typedef struct rcl_node_impl_s rcl_node_impl_t; /// Structure which encapsulates a ROS Node. @@ -533,6 +535,20 @@ rcl_node_resolve_name( bool only_expand, char ** output_name); +/// Check if loaned message is disabled, according to the environment variable. +/** + * If the `ROS_DISABLE_LOANED_MESSAGES` environment variable is set to "1", + * `disable_loaned_message` will be set to true. + * + * \param[out] disable_loaned_message Must not be NULL. + * \return #RCL_RET_INVALID_ARGUMENT if an argument is not valid, or + * \return #RCL_RET_ERROR if an unexpected error happened, or + * \return #RCL_RET_OK. + */ +RCL_PUBLIC +rcl_ret_t +rcl_get_disable_loaned_message(bool * disable_loaned_message); + #ifdef __cplusplus } #endif diff --git a/rcl/src/rcl/node.c b/rcl/src/rcl/node.c index a0aa51d4f..4afc40f53 100644 --- a/rcl/src/rcl/node.c +++ b/rcl/src/rcl/node.c @@ -34,6 +34,7 @@ extern "C" #include "rcl/remap.h" #include "rcl/security.h" +#include "rcutils/env.h" #include "rcutils/filesystem.h" #include "rcutils/find.h" #include "rcutils/format_string.h" @@ -52,6 +53,8 @@ extern "C" #include "./context_impl.h" +const char * const RCL_DISABLE_LOANED_MESSAGES_ENV_VAR = "ROS_DISABLE_LOANED_MESSAGES"; + struct rcl_node_impl_s { rcl_node_options_t options; @@ -514,6 +517,25 @@ rcl_node_get_logger_name(const rcl_node_t * node) return node->impl->logger_name; } +rcl_ret_t +rcl_get_disable_loaned_message(bool * disable_loaned_message) +{ + const char * env_val = NULL; + const char * env_error_str = NULL; + + RCL_CHECK_ARGUMENT_FOR_NULL(disable_loaned_message, RCL_RET_INVALID_ARGUMENT); + + env_error_str = rcutils_get_env(RCL_DISABLE_LOANED_MESSAGES_ENV_VAR, &env_val); + if (NULL != env_error_str) { + RCL_SET_ERROR_MSG_WITH_FORMAT_STRING( + "Error getting env var: '" RCUTILS_STRINGIFY(RCL_DISABLE_LOANED_MESSAGES_ENV_VAR) "': %s\n", + env_error_str); + return RCL_RET_ERROR; + } + + *disable_loaned_message = (strcmp(env_val, "1") == 0); + return RCL_RET_OK; +} #ifdef __cplusplus } #endif diff --git a/rcl/src/rcl/publisher.c b/rcl/src/rcl/publisher.c index a3a97471c..47582da3d 100644 --- a/rcl/src/rcl/publisher.c +++ b/rcl/src/rcl/publisher.c @@ -440,6 +440,13 @@ rcl_publisher_can_loan_messages(const rcl_publisher_t * publisher) if (!rcl_publisher_is_valid(publisher)) { return false; // error message already set } + + bool disable_loaned_message = false; + rcl_ret_t ret = rcl_get_disable_loaned_message(&disable_loaned_message); + if (ret == RCL_RET_OK && disable_loaned_message) { + return false; + } + return publisher->impl->rmw_handle->can_loan_messages; } diff --git a/rcl/src/rcl/subscription.c b/rcl/src/rcl/subscription.c index fcea1e767..d92fe21a4 100644 --- a/rcl/src/rcl/subscription.c +++ b/rcl/src/rcl/subscription.c @@ -435,6 +435,13 @@ rcl_subscription_can_loan_messages(const rcl_subscription_t * subscription) if (!rcl_subscription_is_valid(subscription)) { return false; // error message already set } + + bool disable_loaned_message = false; + rcl_ret_t ret = rcl_get_disable_loaned_message(&disable_loaned_message); + if (ret == RCL_RET_OK && disable_loaned_message) { + return false; + } + return subscription->impl->rmw_handle->can_loan_messages; } diff --git a/rcl/test/rcl/test_node.cpp b/rcl/test/rcl/test_node.cpp index c21576126..716fb5ff1 100644 --- a/rcl/test/rcl/test_node.cpp +++ b/rcl/test/rcl/test_node.cpp @@ -27,6 +27,7 @@ #include "./failing_allocator_functions.hpp" #include "osrf_testing_tools_cpp/memory_tools/memory_tools.hpp" #include "osrf_testing_tools_cpp/scope_exit.hpp" +#include "rcutils/env.h" #include "rcutils/testing/fault_injection.h" #include "rcl/error_handling.h" #include "rcl/logging.h" @@ -997,3 +998,48 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_resolve_nam EXPECT_STREQ("/ns/relative_ns/foo", final_name); default_allocator.deallocate(final_name, default_allocator.state); } + +/* Tests special case node_options + */ +TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_get_disable_loaned_message) { + { + EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, rcl_get_disable_loaned_message(nullptr)); + rcl_reset_error(); + } + + { + bool disable_loaned_message = false; + auto mock = mocking_utils::patch_and_return( + "lib:rcl", rcutils_get_env, "internal error"); + EXPECT_EQ(RCL_RET_ERROR, rcl_get_disable_loaned_message(&disable_loaned_message)); + rcl_reset_error(); + } + + { + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "0")); + bool disable_loaned_message = true; + EXPECT_EQ(RCL_RET_OK, rcl_get_disable_loaned_message(&disable_loaned_message)); + EXPECT_FALSE(disable_loaned_message); + } + + { + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "1")); + bool disable_loaned_message = false; + EXPECT_EQ(RCL_RET_OK, rcl_get_disable_loaned_message(&disable_loaned_message)); + EXPECT_TRUE(disable_loaned_message); + } + + { + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "2")); + bool disable_loaned_message = true; + EXPECT_EQ(RCL_RET_OK, rcl_get_disable_loaned_message(&disable_loaned_message)); + EXPECT_FALSE(disable_loaned_message); + } + + { + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "11")); + bool disable_loaned_message = true; + EXPECT_EQ(RCL_RET_OK, rcl_get_disable_loaned_message(&disable_loaned_message)); + EXPECT_FALSE(disable_loaned_message); + } +} diff --git a/rcl/test/rcl/test_publisher.cpp b/rcl/test/rcl/test_publisher.cpp index 9c853ccde..c77e78436 100644 --- a/rcl/test/rcl/test_publisher.cpp +++ b/rcl/test/rcl/test_publisher.cpp @@ -24,6 +24,8 @@ #include "mimick/mimick.h" #include "osrf_testing_tools_cpp/scope_exit.hpp" #include "rcl/error_handling.h" +#include "rcl/node.h" +#include "rcutils/env.h" #include "rmw/validate_full_topic_name.h" #include "rmw/validate_node_name.h" @@ -370,6 +372,42 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_publisher_loan) } } +TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_publisher_loan_disable) { + rcl_publisher_t publisher = rcl_get_zero_initialized_publisher(); + const rosidl_message_type_support_t * ts = + ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, BasicTypes); + constexpr char topic_name[] = "pod_msg"; + rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options(); + rcl_ret_t ret = + rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options); + ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + rcl_ret_t ret = rcl_publisher_fini(&publisher, this->node_ptr); + EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; + }); + + if (rcl_publisher_can_loan_messages(&publisher)) { + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "0")); + EXPECT_TRUE(rcl_publisher_can_loan_messages(&publisher)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "1")); + EXPECT_FALSE(rcl_publisher_can_loan_messages(&publisher)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "2")); + EXPECT_TRUE(rcl_publisher_can_loan_messages(&publisher)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "Unexpected")); + EXPECT_TRUE(rcl_publisher_can_loan_messages(&publisher)); + } else { + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "0")); + EXPECT_FALSE(rcl_publisher_can_loan_messages(&publisher)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "1")); + EXPECT_FALSE(rcl_publisher_can_loan_messages(&publisher)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "2")); + EXPECT_FALSE(rcl_publisher_can_loan_messages(&publisher)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "Unexpected")); + EXPECT_FALSE(rcl_publisher_can_loan_messages(&publisher)); + } +} + TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_invalid_publisher) { rcl_publisher_t publisher = rcl_get_zero_initialized_publisher(); const rosidl_message_type_support_t * ts = diff --git a/rcl/test/rcl/test_subscription.cpp b/rcl/test/rcl/test_subscription.cpp index adedd7bb9..6a6aa81c1 100644 --- a/rcl/test/rcl/test_subscription.cpp +++ b/rcl/test/rcl/test_subscription.cpp @@ -30,6 +30,8 @@ #include "osrf_testing_tools_cpp/scope_exit.hpp" #include "rcl/error_handling.h" +#include "rcl/node.h" +#include "rcutils/env.h" #include "wait_for_entity_helpers.hpp" #include "./allocator_testing_utils.h" @@ -712,6 +714,42 @@ TEST_F(CLASSNAME(TestSubscriptionFixture, RMW_IMPLEMENTATION), test_subscription } } +TEST_F(CLASSNAME(TestSubscriptionFixture, RMW_IMPLEMENTATION), test_subscription_loan_disable) { + rcl_subscription_t subscription = rcl_get_zero_initialized_subscription(); + const rosidl_message_type_support_t * ts = + ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, BasicTypes); + constexpr char topic[] = "pod_msg"; + rcl_subscription_options_t subscription_options = rcl_subscription_get_default_options(); + rcl_ret_t ret = + rcl_subscription_init(&subscription, this->node_ptr, ts, topic, &subscription_options); + ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + rcl_ret_t ret = rcl_subscription_fini(&subscription, this->node_ptr); + EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; + }); + + if (rcl_subscription_can_loan_messages(&subscription)) { + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "0")); + EXPECT_TRUE(rcl_subscription_can_loan_messages(&subscription)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "1")); + EXPECT_FALSE(rcl_subscription_can_loan_messages(&subscription)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "2")); + EXPECT_TRUE(rcl_subscription_can_loan_messages(&subscription)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "Unexpected")); + EXPECT_TRUE(rcl_subscription_can_loan_messages(&subscription)); + } else { + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "0")); + EXPECT_FALSE(rcl_subscription_can_loan_messages(&subscription)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "1")); + EXPECT_FALSE(rcl_subscription_can_loan_messages(&subscription)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "2")); + EXPECT_FALSE(rcl_subscription_can_loan_messages(&subscription)); + ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "Unexpected")); + EXPECT_FALSE(rcl_subscription_can_loan_messages(&subscription)); + } +} + /* Test for all failure modes in subscription take with loaned messages function. */ TEST_F(CLASSNAME(TestSubscriptionFixture, RMW_IMPLEMENTATION), test_bad_take_loaned_message) {