diff --git a/rcl/include/rcl/client.h b/rcl/include/rcl/client.h
index 39715f181..94290982a 100644
--- a/rcl/include/rcl/client.h
+++ b/rcl/include/rcl/client.h
@@ -409,6 +409,58 @@ RCL_PUBLIC
bool
rcl_client_is_valid(const rcl_client_t * client);
+/// Get the actual qos settings of the client's request publisher.
+/**
+ * Used to get the actual qos settings of the client's request publisher.
+ * The actual configuration applied when using RMW_*_SYSTEM_DEFAULT
+ * can only be resolved after the creation of the client, and it
+ * depends on the underlying rmw implementation.
+ * If the underlying setting in use can't be represented in ROS terms,
+ * it will be set to RMW_*_UNKNOWN.
+ * The returned struct is only valid as long as the rcl_client_t is valid.
+ *
+ *
+ * Attribute | Adherence
+ * ------------------ | -------------
+ * Allocates Memory | No
+ * Thread-Safe | Yes
+ * Uses Atomics | No
+ * Lock-Free | Yes
+ *
+ * \param[in] client pointer to the rcl client
+ * \return qos struct if successful, otherwise `NULL`
+ */
+RCL_PUBLIC
+RCL_WARN_UNUSED
+const rmw_qos_profile_t *
+rcl_client_request_publisher_get_actual_qos(const rcl_client_t * client);
+
+/// Get the actual qos settings of the client's response subscription.
+/**
+ * Used to get the actual qos settings of the client's response subscription.
+ * The actual configuration applied when using RMW_*_SYSTEM_DEFAULT
+ * can only be resolved after the creation of the client, and it
+ * depends on the underlying rmw implementation.
+ * If the underlying setting in use can't be represented in ROS terms,
+ * it will be set to RMW_*_UNKNOWN.
+ * The returned struct is only valid as long as the rcl_client_t is valid.
+ *
+ *
+ * Attribute | Adherence
+ * ------------------ | -------------
+ * Allocates Memory | No
+ * Thread-Safe | Yes
+ * Uses Atomics | No
+ * Lock-Free | Yes
+ *
+ * \param[in] client pointer to the rcl client
+ * \return qos struct if successful, otherwise `NULL`
+ */
+RCL_PUBLIC
+RCL_WARN_UNUSED
+const rmw_qos_profile_t *
+rcl_client_response_subscription_get_actual_qos(const rcl_client_t * client);
+
#ifdef __cplusplus
}
#endif
diff --git a/rcl/include/rcl/service.h b/rcl/include/rcl/service.h
index 82c33c110..b102d14c9 100644
--- a/rcl/include/rcl/service.h
+++ b/rcl/include/rcl/service.h
@@ -440,6 +440,58 @@ RCL_PUBLIC
bool
rcl_service_is_valid(const rcl_service_t * service);
+/// Get the actual qos settings of the service's request subscription.
+/**
+ * Used to get the actual qos settings of the service's request subscription.
+ * The actual configuration applied when using RMW_*_SYSTEM_DEFAULT
+ * can only be resolved after the creation of the service, and it
+ * depends on the underlying rmw implementation.
+ * If the underlying setting in use can't be represented in ROS terms,
+ * it will be set to RMW_*_UNKNOWN.
+ * The returned struct is only valid as long as the rcl_service_t is valid.
+ *
+ *
+ * Attribute | Adherence
+ * ------------------ | -------------
+ * Allocates Memory | No
+ * Thread-Safe | Yes
+ * Uses Atomics | No
+ * Lock-Free | Yes
+ *
+ * \param[in] service pointer to the rcl service
+ * \return qos struct if successful, otherwise `NULL`
+ */
+RCL_PUBLIC
+RCL_WARN_UNUSED
+const rmw_qos_profile_t *
+rcl_service_request_subscription_get_actual_qos(const rcl_service_t * service);
+
+/// Get the actual qos settings of the service's response publisher.
+/**
+ * Used to get the actual qos settings of the service's response publisher.
+ * The actual configuration applied when using RMW_*_SYSTEM_DEFAULT
+ * can only be resolved after the creation of the service, and it
+ * depends on the underlying rmw implementation.
+ * If the underlying setting in use can't be represented in ROS terms,
+ * it will be set to RMW_*_UNKNOWN.
+ * The returned struct is only valid as long as the rcl_service_t is valid.
+ *
+ *
+ * Attribute | Adherence
+ * ------------------ | -------------
+ * Allocates Memory | No
+ * Thread-Safe | Yes
+ * Uses Atomics | No
+ * Lock-Free | Yes
+ *
+ * \param[in] service pointer to the rcl service
+ * \return qos struct if successful, otherwise `NULL`
+ */
+RCL_PUBLIC
+RCL_WARN_UNUSED
+const rmw_qos_profile_t *
+rcl_service_response_publisher_get_actual_qos(const rcl_service_t * service);
+
#ifdef __cplusplus
}
#endif
diff --git a/rcl/src/rcl/client.c b/rcl/src/rcl/client.c
index 433ed3f04..bd38efa7a 100644
--- a/rcl/src/rcl/client.c
+++ b/rcl/src/rcl/client.c
@@ -36,6 +36,8 @@ extern "C"
struct rcl_client_impl_s
{
rcl_client_options_t options;
+ rmw_qos_profile_t actual_request_publisher_qos;
+ rmw_qos_profile_t actual_response_subscription_qos;
rmw_client_t * rmw_handle;
atomic_int_least64_t sequence_number;
};
@@ -111,6 +113,33 @@ rcl_client_init(
RCL_SET_ERROR_MSG(rmw_get_error_string().str);
goto fail;
}
+
+ // get actual qos, and store it
+ rmw_ret_t rmw_ret = rmw_client_request_publisher_get_actual_qos(
+ client->impl->rmw_handle,
+ &client->impl->actual_request_publisher_qos);
+
+ if (RMW_RET_OK != rmw_ret) {
+ RCL_SET_ERROR_MSG(rmw_get_error_string().str);
+ goto fail;
+ }
+
+ rmw_ret = rmw_client_response_subscription_get_actual_qos(
+ client->impl->rmw_handle,
+ &client->impl->actual_response_subscription_qos);
+
+ if (RMW_RET_OK != rmw_ret) {
+ RCL_SET_ERROR_MSG(rmw_get_error_string().str);
+ goto fail;
+ }
+
+ // ROS specific namespacing conventions avoidance
+ // is not retrieved by get_actual_qos
+ client->impl->actual_request_publisher_qos.avoid_ros_namespace_conventions =
+ options->qos.avoid_ros_namespace_conventions;
+ client->impl->actual_response_subscription_qos.avoid_ros_namespace_conventions =
+ options->qos.avoid_ros_namespace_conventions;
+
// options
client->impl->options = *options;
atomic_init(&client->impl->sequence_number, 0);
@@ -280,6 +309,24 @@ rcl_client_is_valid(const rcl_client_t * client)
client->impl->rmw_handle, "client's rmw handle is invalid", return false);
return true;
}
+
+const rmw_qos_profile_t *
+rcl_client_request_publisher_get_actual_qos(const rcl_client_t * client)
+{
+ if (!rcl_client_is_valid(client)) {
+ return NULL;
+ }
+ return &client->impl->actual_request_publisher_qos;
+}
+
+const rmw_qos_profile_t *
+rcl_client_response_subscription_get_actual_qos(const rcl_client_t * client)
+{
+ if (!rcl_client_is_valid(client)) {
+ return NULL;
+ }
+ return &client->impl->actual_response_subscription_qos;
+}
#ifdef __cplusplus
}
#endif
diff --git a/rcl/src/rcl/service.c b/rcl/src/rcl/service.c
index f97110659..42222b996 100644
--- a/rcl/src/rcl/service.c
+++ b/rcl/src/rcl/service.c
@@ -33,6 +33,8 @@ extern "C"
struct rcl_service_impl_s
{
rcl_service_options_t options;
+ rmw_qos_profile_t actual_request_subscription_qos;
+ rmw_qos_profile_t actual_response_publisher_qos;
rmw_service_t * rmw_handle;
};
@@ -122,6 +124,31 @@ rcl_service_init(
RCL_SET_ERROR_MSG(rmw_get_error_string().str);
goto fail;
}
+ // get actual qos, and store it
+ rmw_ret_t rmw_ret = rmw_service_request_subscription_get_actual_qos(
+ service->impl->rmw_handle,
+ &service->impl->actual_request_subscription_qos);
+
+ if (RMW_RET_OK != rmw_ret) {
+ RCL_SET_ERROR_MSG(rmw_get_error_string().str);
+ goto fail;
+ }
+
+ rmw_ret = rmw_service_response_publisher_get_actual_qos(
+ service->impl->rmw_handle,
+ &service->impl->actual_response_publisher_qos);
+
+ if (RMW_RET_OK != rmw_ret) {
+ RCL_SET_ERROR_MSG(rmw_get_error_string().str);
+ goto fail;
+ }
+
+ // ROS specific namespacing conventions is not retrieved by get_actual_qos
+ service->impl->actual_request_subscription_qos.avoid_ros_namespace_conventions =
+ options->qos.avoid_ros_namespace_conventions;
+ service->impl->actual_response_publisher_qos.avoid_ros_namespace_conventions =
+ options->qos.avoid_ros_namespace_conventions;
+
// options
service->impl->options = *options;
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Service initialized");
@@ -301,6 +328,24 @@ rcl_service_is_valid(const rcl_service_t * service)
return true;
}
+const rmw_qos_profile_t *
+rcl_service_request_subscription_get_actual_qos(const rcl_service_t * service)
+{
+ if (!rcl_service_is_valid(service)) {
+ return NULL;
+ }
+ return &service->impl->actual_request_subscription_qos;
+}
+
+const rmw_qos_profile_t *
+rcl_service_response_publisher_get_actual_qos(const rcl_service_t * service)
+{
+ if (!rcl_service_is_valid(service)) {
+ return NULL;
+ }
+ return &service->impl->actual_response_publisher_qos;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/rcl/test/rcl/test_client.cpp b/rcl/test/rcl/test_client.cpp
index 72bfa3ce9..9c3330b54 100644
--- a/rcl/test/rcl/test_client.cpp
+++ b/rcl/test/rcl/test_client.cpp
@@ -91,6 +91,26 @@ TEST_F(TestClientFixture, test_client_nominal) {
EXPECT_EQ(rmw_qos_profile_services_default.depth, client_internal_options->qos.depth);
EXPECT_EQ(rmw_qos_profile_services_default.durability, client_internal_options->qos.durability);
+ const rmw_qos_profile_t * request_publisher_qos =
+ rcl_client_request_publisher_get_actual_qos(&client);
+ EXPECT_EQ(rmw_qos_profile_services_default.reliability, request_publisher_qos->reliability);
+ EXPECT_EQ(rmw_qos_profile_services_default.history, request_publisher_qos->history);
+ EXPECT_EQ(rmw_qos_profile_services_default.depth, request_publisher_qos->depth);
+ EXPECT_EQ(rmw_qos_profile_services_default.durability, request_publisher_qos->durability);
+ EXPECT_EQ(
+ rmw_qos_profile_services_default.avoid_ros_namespace_conventions,
+ request_publisher_qos->avoid_ros_namespace_conventions);
+
+ const rmw_qos_profile_t * response_subscription_qos =
+ rcl_client_response_subscription_get_actual_qos(&client);
+ EXPECT_EQ(rmw_qos_profile_services_default.reliability, response_subscription_qos->reliability);
+ EXPECT_EQ(rmw_qos_profile_services_default.history, response_subscription_qos->history);
+ EXPECT_EQ(rmw_qos_profile_services_default.depth, response_subscription_qos->depth);
+ EXPECT_EQ(rmw_qos_profile_services_default.durability, response_subscription_qos->durability);
+ EXPECT_EQ(
+ rmw_qos_profile_services_default.avoid_ros_namespace_conventions,
+ response_subscription_qos->avoid_ros_namespace_conventions);
+
// Check the return code of initialization and that the service name matches what's expected
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
EXPECT_EQ(strcmp(rcl_client_get_service_name(&client), expected_topic_name), 0);
@@ -261,6 +281,8 @@ TEST_F(TestClientFixture, test_client_bad_arguments) {
RCL_RET_CLIENT_INVALID, rcl_send_request(
nullptr, &client_request, &sequence_number)) << rcl_get_error_string().str;
EXPECT_EQ(24, sequence_number);
+ EXPECT_EQ(nullptr, rcl_client_request_publisher_get_actual_qos(nullptr));
+ EXPECT_EQ(nullptr, rcl_client_response_subscription_get_actual_qos(nullptr));
// Not init client
EXPECT_EQ(nullptr, rcl_client_get_rmw_handle(&client));
@@ -277,6 +299,8 @@ TEST_F(TestClientFixture, test_client_bad_arguments) {
RCL_RET_CLIENT_INVALID, rcl_send_request(
&client, &client_request, &sequence_number)) << rcl_get_error_string().str;
EXPECT_EQ(24, sequence_number);
+ EXPECT_EQ(nullptr, rcl_client_request_publisher_get_actual_qos(&client));
+ EXPECT_EQ(nullptr, rcl_client_response_subscription_get_actual_qos(&client));
}
TEST_F(TestClientFixture, test_client_init_fini_maybe_fail)
diff --git a/rcl/test/rcl/test_service.cpp b/rcl/test/rcl/test_service.cpp
index b4f6df67c..047eb3ebb 100644
--- a/rcl/test/rcl/test_service.cpp
+++ b/rcl/test/rcl/test_service.cpp
@@ -93,6 +93,20 @@ TEST_F(CLASSNAME(TestServiceFixture, RMW_IMPLEMENTATION), test_service_nominal)
ret = rcl_service_init(&service, this->node_ptr, ts, topic, &service_options);
EXPECT_EQ(RCL_RET_ALREADY_INIT, ret) << rcl_get_error_string().str;
+ const rmw_qos_profile_t * request_subscription_qos =
+ rcl_service_request_subscription_get_actual_qos(&service);
+ EXPECT_EQ(rmw_qos_profile_services_default.reliability, request_subscription_qos->reliability);
+ EXPECT_EQ(rmw_qos_profile_services_default.history, request_subscription_qos->history);
+ EXPECT_EQ(rmw_qos_profile_services_default.depth, request_subscription_qos->depth);
+ EXPECT_EQ(rmw_qos_profile_services_default.durability, request_subscription_qos->durability);
+
+ const rmw_qos_profile_t * response_publisher_qos =
+ rcl_service_response_publisher_get_actual_qos(&service);
+ EXPECT_EQ(rmw_qos_profile_services_default.reliability, response_publisher_qos->reliability);
+ EXPECT_EQ(rmw_qos_profile_services_default.history, response_publisher_qos->history);
+ EXPECT_EQ(rmw_qos_profile_services_default.depth, response_publisher_qos->depth);
+ EXPECT_EQ(rmw_qos_profile_services_default.durability, response_publisher_qos->durability);
+
ret = rcl_service_fini(&service, this->node_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
@@ -388,6 +402,8 @@ TEST_F(CLASSNAME(TestServiceFixture, RMW_IMPLEMENTATION), test_bad_arguments) {
RCL_RET_SERVICE_INVALID, rcl_send_response(nullptr, &header.request_id, &service_response));
EXPECT_EQ(
RCL_RET_SERVICE_INVALID, rcl_take_request(nullptr, &(header.request_id), &service_request));
+ EXPECT_EQ(nullptr, rcl_service_request_subscription_get_actual_qos(nullptr));
+ EXPECT_EQ(nullptr, rcl_service_response_publisher_get_actual_qos(nullptr));
EXPECT_EQ(nullptr, rcl_service_get_service_name(&service));
EXPECT_EQ(nullptr, rcl_service_get_options(&service));
@@ -404,6 +420,9 @@ TEST_F(CLASSNAME(TestServiceFixture, RMW_IMPLEMENTATION), test_bad_arguments) {
RCL_RET_BAD_ALLOC, rcl_service_init(
&service, this->node_ptr, ts,
topic, &service_options_bad_alloc)) << rcl_get_error_string().str;
+
+ EXPECT_EQ(nullptr, rcl_service_request_subscription_get_actual_qos(&service));
+ EXPECT_EQ(nullptr, rcl_service_response_publisher_get_actual_qos(&service));
}
/* Name failed tests