26 #include "rcl/error_handling.h"
28 #include "rcl/node_type_cache.h"
32 #include "rcutils/error_handling.h"
33 #include "rcutils/logging_macros.h"
34 #include "rcutils/macros.h"
35 #include "rmw/error_handling.h"
36 #include "rmw/qos_profiles.h"
37 #include "rmw/ret_types.h"
39 #include "rmw/types.h"
40 #include "service_msgs/msg/service_event_info.h"
41 #include "tracetools/tracetools.h"
43 #include "rosidl_runtime_c/service_type_support_struct.h"
46 #include "./service_event_publisher.h"
47 #include "./service_impl.h"
59 unconfigure_service_introspection(
64 if (service_impl == NULL) {
68 if (service_impl->service_event_publisher == NULL) {
72 rcl_ret_t ret = rcl_service_event_publisher_fini(service_impl->service_event_publisher, node);
74 allocator->deallocate(service_impl->service_event_publisher, allocator->state);
75 service_impl->service_event_publisher = NULL;
84 const rosidl_service_type_support_t * type_support,
85 const char * service_name,
106 RCUTILS_LOG_DEBUG_NAMED(
107 ROS_PACKAGE_NAME,
"Initializing service for service name '%s'", service_name);
109 RCL_SET_ERROR_MSG(
"service already initialized, or memory was unintialized");
116 RCL_CHECK_FOR_NULL_WITH_MSG(
117 service->
impl,
"allocating memory failed",
127 &service->
impl->remapped_service_name);
134 goto free_service_impl;
136 RCUTILS_LOG_DEBUG_NAMED(
137 ROS_PACKAGE_NAME,
"Expanded and remapped service name '%s'",
138 service->
impl->remapped_service_name);
140 if (RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL == options->
qos.durability) {
141 RCUTILS_LOG_WARN_NAMED(
143 "Warning: Setting QoS durability to 'transient local' for service servers "
144 "can cause them to receive requests from clients that have since terminated.");
149 service->
impl->rmw_handle = rmw_create_service(
152 service->
impl->remapped_service_name,
154 if (!service->
impl->rmw_handle) {
155 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
157 goto free_remapped_service_name;
161 rmw_ret_t rmw_ret = rmw_service_request_subscription_get_actual_qos(
162 service->
impl->rmw_handle,
163 &service->
impl->actual_request_subscription_qos);
164 if (RMW_RET_OK != rmw_ret) {
165 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
166 ret = rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
167 goto destroy_service;
170 rmw_ret = rmw_service_response_publisher_get_actual_qos(
171 service->
impl->rmw_handle,
172 &service->
impl->actual_response_publisher_qos);
173 if (RMW_RET_OK != rmw_ret) {
174 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
175 ret = rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
176 goto destroy_service;
180 service->
impl->actual_request_subscription_qos.avoid_ros_namespace_conventions =
181 options->
qos.avoid_ros_namespace_conventions;
182 service->
impl->actual_response_publisher_qos.avoid_ros_namespace_conventions =
183 options->
qos.avoid_ros_namespace_conventions;
186 service->
impl->options = *options;
187 service->
impl->in_use_by_waitset =
false;
189 if (
RCL_RET_OK != rcl_node_type_cache_register_type(
190 node, type_support->get_type_hash_func(type_support),
191 type_support->get_type_description_func(type_support),
192 type_support->get_type_description_sources_func(type_support)))
194 rcutils_reset_error();
195 RCL_SET_ERROR_MSG(
"Failed to register type for service");
197 goto destroy_service;
199 service->
impl->type_hash = *type_support->get_type_hash_func(type_support);
201 RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME,
"Service initialized");
202 TRACETOOLS_TRACEPOINT(
204 (
const void *)service,
206 (
const void *)service->
impl->rmw_handle,
207 service->
impl->remapped_service_name);
213 if (RMW_RET_OK != rmw_ret) {
214 RCUTILS_SAFE_FWRITE_TO_STDERR(rmw_get_error_string().str);
215 RCUTILS_SAFE_FWRITE_TO_STDERR(
"\n");
218 free_remapped_service_name:
219 allocator->deallocate(service->
impl->remapped_service_name, allocator->state);
220 service->
impl->remapped_service_name = NULL;
223 allocator->deallocate(service->
impl, allocator->state);
224 service->
impl = NULL;
237 RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME,
"Finalizing service");
251 rcl_ret_t rcl_ret = unconfigure_service_introspection(node, service->
impl, &allocator);
253 RCL_SET_ERROR_MSG(rcl_get_error_string().str);
257 rmw_ret_t ret = rmw_destroy_service(rmw_node, service->
impl->rmw_handle);
258 if (ret != RMW_RET_OK) {
259 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
264 ROSIDL_TYPE_HASH_VERSION_UNSET != service->
impl->type_hash.version &&
265 RCL_RET_OK != rcl_node_type_cache_unregister_type(node, &service->
impl->type_hash))
267 RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
271 allocator.deallocate(service->
impl->remapped_service_name, allocator.state);
272 service->
impl->remapped_service_name = NULL;
274 allocator.deallocate(service->
impl, allocator.state);
275 service->
impl = NULL;
277 RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME,
"Service finalized");
287 default_options.
qos = rmw_qos_profile_services_default;
289 return default_options;
299 RCL_CHECK_FOR_NULL_WITH_MSG(service->
impl->rmw_handle,
"service is invalid",
return NULL);
300 return service->
impl->rmw_handle->service_name;
309 return &service->
impl->options;
318 return service->
impl->rmw_handle;
324 rmw_service_info_t * request_header,
327 RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME,
"Service server taking service request");
334 RCL_CHECK_FOR_NULL_WITH_MSG(options,
"Failed to get service options",
return RCL_RET_ERROR);
337 rmw_ret_t ret = rmw_take_request(
338 service->
impl->rmw_handle, request_header, ros_request, &taken);
339 if (RMW_RET_OK != ret) {
340 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
341 if (RMW_RET_BAD_ALLOC == ret) {
346 RCUTILS_LOG_DEBUG_NAMED(
347 ROS_PACKAGE_NAME,
"Service take request succeeded: %s", taken ?
"true" :
"false");
351 if (service->
impl->service_event_publisher != NULL) {
352 rcl_ret_t rclret = rcl_send_service_event_message(
353 service->
impl->service_event_publisher,
354 service_msgs__msg__ServiceEventInfo__REQUEST_RECEIVED,
356 request_header->request_id.sequence_number,
357 request_header->request_id.writer_guid);
359 RCL_SET_ERROR_MSG(rcl_get_error_string().str);
369 rmw_request_id_t * request_header,
372 rmw_service_info_t header;
373 header.request_id = *request_header;
375 *request_header = header.request_id;
382 rmw_request_id_t * request_header,
386 RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME,
"Sending service response");
393 RCL_CHECK_FOR_NULL_WITH_MSG(options,
"Failed to get service options",
return RCL_RET_ERROR);
395 ret = rmw_send_response(service->
impl->rmw_handle, request_header, ros_response);
396 if (ret != RMW_RET_OK) {
397 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
398 if (ret == RMW_RET_TIMEOUT) {
405 if (service->
impl->service_event_publisher != NULL) {
406 ret = rcl_send_service_event_message(
407 service->
impl->service_event_publisher,
408 service_msgs__msg__ServiceEventInfo__RESPONSE_SENT,
410 request_header->sequence_number,
411 request_header->writer_guid);
413 RCL_SET_ERROR_MSG(rcl_get_error_string().str);
423 RCL_CHECK_FOR_NULL_WITH_MSG(service,
"service pointer is invalid",
return false);
424 RCL_CHECK_FOR_NULL_WITH_MSG(
425 service->
impl,
"service's implementation is invalid",
return false);
426 RCL_CHECK_FOR_NULL_WITH_MSG(
427 service->
impl->rmw_handle,
"service's rmw handle is invalid",
return false);
431 const rmw_qos_profile_t *
437 return &service->
impl->actual_request_subscription_qos;
440 const rmw_qos_profile_t *
446 return &service->
impl->actual_response_publisher_qos;
452 rcl_event_callback_t callback,
453 const void * user_data)
460 return rmw_service_set_on_new_request_callback(
461 service->
impl->rmw_handle,
471 const rosidl_service_type_support_t * type_support,
473 rcl_service_introspection_state_t introspection_state)
484 if (introspection_state == RCL_SERVICE_INTROSPECTION_OFF) {
485 return unconfigure_service_introspection(node, service->
impl, &allocator);
488 if (service->
impl->service_event_publisher == NULL) {
491 service->
impl->service_event_publisher = allocator.allocate(
493 RCL_CHECK_FOR_NULL_WITH_MSG(
494 service->
impl->service_event_publisher,
"allocating memory failed",
497 *service->
impl->service_event_publisher = rcl_get_zero_initialized_service_event_publisher();
498 rcl_ret_t ret = rcl_service_event_publisher_init(
499 service->
impl->service_event_publisher, node, clock, publisher_options,
500 service->
impl->remapped_service_name, type_support);
502 allocator.deallocate(service->
impl->service_event_publisher, allocator.state);
503 service->
impl->service_event_publisher = NULL;
508 return rcl_service_event_publisher_change_state(
509 service->
impl->service_event_publisher, introspection_state);
#define rcl_get_default_allocator
Return a properly initialized rcl_allocator_t with default values.
#define RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, msg, fail_statement)
Check that the given allocator is initialized, or fail with a message.
rcutils_allocator_t rcl_allocator_t
Encapsulation of an allocator.
RCL_PUBLIC bool rcl_node_is_valid(const rcl_node_t *node)
Return true if the node is valid, else false.
RCL_PUBLIC RCL_WARN_UNUSED rmw_node_t * rcl_node_get_rmw_handle(const rcl_node_t *node)
Return the rmw node handle.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_node_resolve_name(const rcl_node_t *node, const char *input_name, rcl_allocator_t allocator, bool is_service, bool only_expand, char **output_name)
Expand a given name into a fully-qualified topic name and apply remapping rules.
RCL_PUBLIC bool rcl_node_is_valid_except_context(const rcl_node_t *node)
Return true if node is valid, except for the context being valid.
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 request subscription.
RCL_PUBLIC RCL_WARN_UNUSED rmw_service_t * rcl_service_get_rmw_handle(const rcl_service_t *service)
Return the rmw service handle.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_service_get_service_name(const rcl_service_t *service)
Get the topic name for the service.
RCL_PUBLIC RCL_WARN_UNUSED const rmw_qos_profile_t * rcl_service_response_publisher_get_actual_qos(const rcl_service_t *service)
Get the actual qos settings of the service's response publisher.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_service_init(rcl_service_t *service, const rcl_node_t *node, const rosidl_service_type_support_t *type_support, const char *service_name, const rcl_service_options_t *options)
Initialize a rcl service.
RCL_PUBLIC RCL_WARN_UNUSED const rcl_service_options_t * rcl_service_get_options(const rcl_service_t *service)
Return the rcl service options.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_service_configure_service_introspection(rcl_service_t *service, rcl_node_t *node, rcl_clock_t *clock, const rosidl_service_type_support_t *type_support, const rcl_publisher_options_t publisher_options, rcl_service_introspection_state_t introspection_state)
Configure service introspection features for the service.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_request_with_info(const rcl_service_t *service, rmw_service_info_t *request_header, void *ros_request)
Take a pending ROS request using a rcl service.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_service_set_on_new_request_callback(const rcl_service_t *service, rcl_event_callback_t callback, const void *user_data)
Set the on new request callback function for the service.
RCL_PUBLIC bool rcl_service_is_valid(const rcl_service_t *service)
Check that the service is valid.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_service_fini(rcl_service_t *service, rcl_node_t *node)
Finalize a rcl_service_t.
RCL_PUBLIC RCL_WARN_UNUSED rcl_service_options_t rcl_service_get_default_options(void)
Return the default service options in a rcl_service_options_t.
RCL_PUBLIC RCL_WARN_UNUSED rcl_service_t rcl_get_zero_initialized_service(void)
Return a rcl_service_t struct with members set to NULL.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_request(const rcl_service_t *service, rmw_request_id_t *request_header, void *ros_request)
Backwards compatibility function to take a pending ROS request using a rcl service.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_send_response(const rcl_service_t *service, rmw_request_id_t *response_header, void *ros_response)
Send a ROS response to a client using a service.
Encapsulation of a time source.
Structure which encapsulates a ROS Node.
Options available for a rcl publisher.
Options available for a rcl service.
rmw_qos_profile_t qos
Middleware quality of service settings for the service.
rcl_allocator_t allocator
Custom allocator for the service, used for incidental allocations.
Structure which encapsulates a ROS Service.
rcl_service_impl_t * impl
Pointer to the service implementation.
#define RCL_RET_SERVICE_INVALID
Invalid rcl_service_t given return code.
#define RCL_RET_UNKNOWN_SUBSTITUTION
Topic name substitution is unknown.
#define RCL_RET_SERVICE_NAME_INVALID
Service name (same as topic name) does not pass validation.
#define RCL_RET_ALREADY_INIT
rcl_init() already called return code.
#define RCL_RET_OK
Success return code.
#define RCL_RET_BAD_ALLOC
Failed to allocate memory return code.
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
#define RCL_RET_ERROR
Unspecified error return code.
#define RCL_RET_SERVICE_TAKE_FAILED
Failed to take a request from the service return code.
#define RCL_RET_NODE_INVALID
Invalid rcl_node_t given return code.
#define RCL_RET_TIMEOUT
Timeout occurred return code.
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.