Skip to content

Commit

Permalink
Add client/service QoS getters (#941)
Browse files Browse the repository at this point in the history
* Add client/service QoS getters

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Don't allow Client/Services to use system default QoS

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Add serv/cli request/response qos getters

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Add unit tests for client/services qos getters

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Check avoid_ros_namespace_conventions in unit test

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
  • Loading branch information
mauropasse and Mauro Passerino authored Feb 18, 2022
1 parent 83ac5b0 commit cf368ca
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 0 deletions.
52 changes: 52 additions & 0 deletions rcl/include/rcl/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
* <hr>
* 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.
*
* <hr>
* 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
Expand Down
52 changes: 52 additions & 0 deletions rcl/include/rcl/service.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
* <hr>
* 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.
*
* <hr>
* 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
Expand Down
47 changes: 47 additions & 0 deletions rcl/src/rcl/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
45 changes: 45 additions & 0 deletions rcl/src/rcl/service.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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
24 changes: 24 additions & 0 deletions rcl/test/rcl/test_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Expand All @@ -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)
Expand Down
19 changes: 19 additions & 0 deletions rcl/test/rcl/test_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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));
Expand All @@ -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
Expand Down

0 comments on commit cf368ca

Please sign in to comment.