23 #include "rcl/error_handling.h"
27 #include "rcl/node_type_cache.h"
32 #include "rcutils/env.h"
33 #include "rcutils/filesystem.h"
34 #include "rcutils/find.h"
35 #include "rcutils/format_string.h"
36 #include "rcutils/logging_macros.h"
37 #include "rcutils/macros.h"
38 #include "rcutils/repl_str.h"
39 #include "rcutils/snprintf.h"
40 #include "rcutils/strdup.h"
41 #include "rcutils/types/hash_map.h"
43 #include "rmw/error_handling.h"
44 #include "rmw/security_options.h"
46 #include "rmw/validate_namespace.h"
47 #include "rmw/validate_node_name.h"
48 #include "rosidl_runtime_c/string_functions.h"
49 #include "rosidl_runtime_c/type_description/type_description__functions.h"
50 #include "rosidl_runtime_c/type_description/type_source__functions.h"
51 #include "tracetools/tracetools.h"
52 #include "type_description_interfaces/srv/get_type_description.h"
54 #include "./context_impl.h"
55 #include "./node_impl.h"
57 const char *
const RCL_DISABLE_LOANED_MESSAGES_ENV_VAR =
"ROS_DISABLE_LOANED_MESSAGES";
69 const char * rcl_create_node_logger_name(
70 const char * node_name,
71 const char * node_namespace,
75 if (strlen(node_namespace) == 1) {
76 return rcutils_strdup(node_name, *allocator);
82 const char * ns_with_separators = rcutils_repl_str(
84 "/", RCUTILS_LOGGING_SEPARATOR_STRING,
86 if (NULL == ns_with_separators) {
91 char * node_logger_name = rcutils_format_string(
92 *allocator,
"%s%s%s", ns_with_separators, RCUTILS_LOGGING_SEPARATOR_STRING, node_name);
93 allocator->deallocate((
char *)ns_with_separators, allocator->state);
94 return node_logger_name;
109 const char * namespace_,
113 const rmw_guard_condition_t * rmw_graph_guard_condition = NULL;
118 char * remapped_node_name = NULL;
119 const char * local_namespace_ = NULL;
129 RCUTILS_LOG_DEBUG_NAMED(
130 ROS_PACKAGE_NAME,
"Initializing node '%s' in namespace '%s'", name, namespace_);
132 RCL_SET_ERROR_MSG(
"node already initialized, or struct memory was unintialized");
136 RCL_CHECK_FOR_NULL_WITH_MSG(
140 "the given context is not valid, "
141 "either rcl_init() was not called or rcl_shutdown() was called.");
145 int validation_result = 0;
146 ret = rmw_validate_node_name(name, &validation_result, NULL);
147 if (ret != RMW_RET_OK) {
148 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
151 if (validation_result != RMW_NODE_NAME_VALID) {
152 const char * msg = rmw_node_name_validation_result_string(validation_result);
153 RCL_SET_ERROR_MSG(msg);
158 if (namespace_[0] ==
'\0') {
160 local_namespace_ = rcutils_strdup(
"/", *allocator);
161 }
else if (namespace_[0] ==
'/') {
162 local_namespace_ = rcutils_strdup(namespace_, *allocator);
165 local_namespace_ = rcutils_format_string(*allocator,
"/%s", namespace_);
167 RCL_CHECK_FOR_NULL_WITH_MSG(
169 "failed to format node namespace string",
173 validation_result = 0;
174 ret = rmw_validate_namespace(local_namespace_, &validation_result, NULL);
175 if (ret != RMW_RET_OK) {
176 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
179 if (validation_result != RMW_NAMESPACE_VALID) {
180 const char * msg = rmw_namespace_validation_result_string(validation_result);
181 RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
"%s, result: %d", msg, validation_result);
190 RCL_CHECK_FOR_NULL_WITH_MSG(
193 node->
impl->registered_types_by_type_hash = rcutils_get_zero_initialized_hash_map();
207 &(node->
impl->options.
arguments), global_args, name, *allocator,
208 &remapped_node_name);
212 if (NULL != remapped_node_name) {
213 name = remapped_node_name;
216 char * remapped_namespace = NULL;
219 *allocator, &remapped_namespace);
223 if (NULL != remapped_namespace) {
224 allocator->deallocate((
char *)local_namespace_, allocator->state);
225 local_namespace_ = remapped_namespace;
229 if (
'/' == local_namespace_[strlen(local_namespace_) - 1]) {
230 node->
impl->fq_name = rcutils_format_string(*allocator,
"%s%s", local_namespace_, name);
232 node->
impl->fq_name = rcutils_format_string(*allocator,
"%s/%s", local_namespace_, name);
234 RCL_CHECK_FOR_NULL_WITH_MSG(
235 node->
impl->fq_name,
"creating fully qualified name failed",
239 node->
impl->logger_name = rcl_create_node_logger_name(name, local_namespace_, allocator);
240 RCL_CHECK_FOR_NULL_WITH_MSG(
241 node->
impl->logger_name,
"creating logger name failed", ret =
RCL_RET_ERROR;
goto fail);
243 RCUTILS_LOG_DEBUG_NAMED(
244 ROS_PACKAGE_NAME,
"Using domain ID of '%zu'", context->
impl->
rmw_context.actual_domain_id);
246 node->
impl->rmw_node_handle = rmw_create_node(
248 name, local_namespace_);
249 RCL_CHECK_FOR_NULL_WITH_MSG(
250 node->
impl->rmw_node_handle, rmw_get_error_string().str, ret =
RCL_RET_ERROR;
goto fail);
253 rmw_graph_guard_condition = rmw_node_get_graph_guard_condition(node->
impl->rmw_node_handle);
254 RCL_CHECK_FOR_NULL_WITH_MSG(
255 rmw_graph_guard_condition, rmw_get_error_string().str, ret =
RCL_RET_ERROR;
goto fail);
259 RCL_CHECK_FOR_NULL_WITH_MSG(
260 node->
impl->graph_guard_condition,
"allocating memory failed",
263 graph_guard_condition_options.
allocator = *allocator;
265 node->
impl->graph_guard_condition,
266 rmw_graph_guard_condition,
268 graph_guard_condition_options);
276 ret = rcl_node_type_cache_init(node);
281 RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME,
"Node initialized");
282 TRACETOOLS_TRACEPOINT(
289 allocator->deallocate(remapped_node_name, allocator->state);
290 allocator->deallocate((
char *)local_namespace_, allocator->state);
296 if (NULL != node->
impl->registered_types_by_type_hash.impl) {
297 fail_ret = rcl_node_type_cache_fini(node);
298 RCUTILS_LOG_ERROR_EXPRESSION_NAMED(
300 ROS_PACKAGE_NAME,
"Failed to fini type cache for node: %s", rcl_get_error_string().str);
303 if (node->
impl->graph_guard_condition) {
305 RCUTILS_LOG_ERROR_EXPRESSION_NAMED(
307 "failed to fini guard condition in error recovery: %s", rcl_get_error_string().str);
309 allocator->deallocate(node->
impl->graph_guard_condition, allocator->state);
312 if (node->
impl->rmw_node_handle) {
313 fail_ret = rmw_destroy_node(node->
impl->rmw_node_handle);
314 RCUTILS_LOG_ERROR_EXPRESSION_NAMED(
315 fail_ret != RMW_RET_OK, ROS_PACKAGE_NAME,
316 "failed to fini rmw node in error recovery: %s", rmw_get_error_string().str);
319 allocator->deallocate((
char *)node->
impl->logger_name, allocator->state);
321 allocator->deallocate((
char *)node->
impl->fq_name, allocator->state);
324 RCUTILS_LOG_ERROR_EXPRESSION_NAMED(
326 "failed to fini node options: %s", rcl_get_error_string().str);
328 allocator->deallocate(node->
impl, allocator->state);
331 allocator->deallocate(remapped_node_name, allocator->state);
333 allocator->deallocate((
char *)local_namespace_, allocator->state);
343 RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME,
"Finalizing node");
352 rcl_ret = rcl_node_type_cache_fini(node);
354 RCL_SET_ERROR_MSG(
"Unable to fini type cache for node.");
357 rmw_ret_t rmw_ret = rmw_destroy_node(node->
impl->rmw_node_handle);
358 if (rmw_ret != RMW_RET_OK) {
359 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
364 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
367 allocator.deallocate(node->
impl->graph_guard_condition, allocator.state);
369 allocator.deallocate((
char *)node->
impl->logger_name, allocator.state);
370 allocator.deallocate((
char *)node->
impl->fq_name, allocator.state);
377 allocator.deallocate(node->
impl, allocator.state);
379 RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME,
"Node finalized");
386 RCL_CHECK_FOR_NULL_WITH_MSG(node,
"rcl node pointer is invalid",
return false);
387 RCL_CHECK_FOR_NULL_WITH_MSG(node->
impl,
"rcl node implementation is invalid",
return false);
388 RCL_CHECK_FOR_NULL_WITH_MSG(
389 node->
impl->rmw_node_handle,
"rcl node's rmw handle is invalid",
return false);
401 RCL_SET_ERROR_MSG(
"rcl node's context is invalid");
413 return node->
impl->rmw_node_handle->name;
422 return node->
impl->rmw_node_handle->namespace_;
431 return node->
impl->fq_name;
440 return &node->
impl->options;
463 return node->
impl->rmw_node_handle;
481 return node->
impl->graph_guard_condition;
490 return node->
impl->logger_name;
496 const char * env_val = NULL;
497 const char * env_error_str = NULL;
501 env_error_str = rcutils_get_env(RCL_DISABLE_LOANED_MESSAGES_ENV_VAR, &env_val);
502 if (NULL != env_error_str) {
503 RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
504 "Error getting env var: '" RCUTILS_STRINGIFY(RCL_DISABLE_LOANED_MESSAGES_ENV_VAR)
"': %s\n",
509 *disable_loaned_message = (strcmp(env_val,
"1") == 0);
515 const rmw_request_id_t * request_header,
516 const type_description_interfaces__srv__GetTypeDescription_Request * request,
517 type_description_interfaces__srv__GetTypeDescription_Response * response)
520 RCL_CHECK_FOR_NULL_WITH_MSG(node,
"invalid node handle",
return;);
521 RCL_CHECK_FOR_NULL_WITH_MSG(node->
impl,
"invalid node",
return;);
522 RCL_CHECK_FOR_NULL_WITH_MSG(request_header,
"invalid request header",
return;);
523 RCL_CHECK_FOR_NULL_WITH_MSG(request,
"null request pointer",
return;);
524 RCL_CHECK_FOR_NULL_WITH_MSG(response,
"null response pointer",
return;);
526 if (!type_description_interfaces__srv__GetTypeDescription_Response__init(response)) {
527 RCUTILS_LOG_ERROR_NAMED(
529 "Failed to initialize service response.");
532 response->successful =
false;
534 rosidl_type_hash_t type_hash;
535 if (RCUTILS_RET_OK !=
536 rosidl_parse_type_hash_string(request->type_hash.data, &type_hash))
538 RCUTILS_LOG_ERROR_NAMED(
539 ROS_PACKAGE_NAME,
"Failed to parse type hash '%s'",
540 request->type_hash.data);
541 rosidl_runtime_c__String__assign(
542 &response->failure_reason,
543 "Failed to parse type hash");
547 if (RCUTILS_RET_OK !=
548 rcl_node_type_cache_get_type_info(node, &type_hash, &type_info))
550 rosidl_runtime_c__String__assign(
551 &response->failure_reason,
552 "Type not currently in use by this node");
556 if (!type_description_interfaces__msg__TypeDescription__copy(
557 type_info.type_description, &response->type_description))
559 rosidl_runtime_c__String__assign(
560 &response->failure_reason,
561 "Failed to populate TypeDescription to response.");
565 if (request->include_type_sources) {
566 if (!type_description_interfaces__msg__TypeSource__Sequence__copy(
567 type_info.type_sources, &response->type_sources))
569 rosidl_runtime_c__String__assign(
570 &response->failure_reason,
571 "Failed to populate TypeSource_Sequence to response.");
576 response->successful =
true;
592 char * service_name = NULL;
593 const rosidl_service_type_support_t * type_support =
594 ROSIDL_GET_SRV_TYPE_SUPPORT(
595 type_description_interfaces, srv,
602 node,
"~/get_type_description",
603 allocator,
true,
true, &service_name);
606 "Failed to construct ~/get_type_description service name");
613 type_support, service_name, &service_ops);
614 allocator.deallocate(service_name, allocator.state);
#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 RCL_WARN_UNUSED rcl_ret_t rcl_arguments_fini(rcl_arguments_t *args)
Reclaim resources held inside rcl_arguments_t structure.
RCL_PUBLIC RCL_WARN_UNUSED rcl_context_instance_id_t rcl_context_get_instance_id(const rcl_context_t *context)
Returns an unsigned integer that is unique to the given context, or 0 if invalid.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_context_get_domain_id(rcl_context_t *context, size_t *domain_id)
Returns the context domain id.
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_context_is_valid(const rcl_context_t *context)
Return true if the given context is currently valid, otherwise false.
RCL_PUBLIC RCL_WARN_UNUSED rcl_guard_condition_t rcl_get_zero_initialized_guard_condition(void)
Return a rcl_guard_condition_t struct with members set to NULL.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_guard_condition_fini(rcl_guard_condition_t *guard_condition)
Finalize a rcl_guard_condition_t.
RCL_PUBLIC RCL_WARN_UNUSED rcl_guard_condition_options_t rcl_guard_condition_get_default_options(void)
Return the default options in a rcl_guard_condition_options_t struct.
rcl_ret_t rcl_guard_condition_init_from_rmw(rcl_guard_condition_t *guard_condition, const rmw_guard_condition_t *rmw_guard_condition, rcl_context_t *context, const rcl_guard_condition_options_t options)
Same as rcl_guard_condition_init(), but reusing an existing rmw handle.
RCL_PUBLIC RCL_WARN_UNUSED const rcl_node_options_t * rcl_node_get_options(const rcl_node_t *node)
Return the rcl node options.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_node_type_description_service_init(rcl_service_t *service, const rcl_node_t *node)
Initialize the node's ~/get_type_description service.
RCL_PUBLIC RCL_WARN_UNUSED rcl_node_t rcl_get_zero_initialized_node(void)
Return a rcl_node_t struct with members initialized to NULL.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_name(const rcl_node_t *node)
Return the name of the node.
RCL_PUBLIC bool rcl_node_is_valid(const rcl_node_t *node)
Return true if the node is valid, else false.
RCL_PUBLIC rcl_ret_t rcl_get_disable_loaned_message(bool *disable_loaned_message)
Check if loaned message is disabled, according to the environment variable.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_node_fini(rcl_node_t *node)
Finalize a rcl_node_t.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_namespace(const rcl_node_t *node)
Return the namespace of the node.
RCL_PUBLIC RCL_WARN_UNUSED const rcl_guard_condition_t * rcl_node_get_graph_guard_condition(const rcl_node_t *node)
Return a guard condition which is triggered when the ROS graph changes.
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 const char * rcl_node_get_fully_qualified_name(const rcl_node_t *node)
Return the fully qualified name of the node.
RCL_PUBLIC void rcl_node_type_description_service_handle_request(rcl_node_t *node, const rmw_request_id_t *request_header, const type_description_interfaces__srv__GetTypeDescription_Request *request, type_description_interfaces__srv__GetTypeDescription_Response *response)
Process a single pending request to the GetTypeDescription service.
RCL_PUBLIC RCL_WARN_UNUSED uint64_t rcl_node_get_rcl_instance_id(const rcl_node_t *node)
Return the associated rcl instance id.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_node_get_domain_id(const rcl_node_t *node, size_t *domain_id)
Return the ROS domain ID that the node is using.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_logger_name(const rcl_node_t *node)
Return the logger name of the node.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_node_init(rcl_node_t *node, const char *name, const char *namespace_, rcl_context_t *context, const rcl_node_options_t *options)
Initialize a ROS node.
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 rcl_ret_t rcl_node_options_copy(const rcl_node_options_t *options, rcl_node_options_t *options_out)
Copy one options structure into another.
RCL_PUBLIC rcl_node_options_t rcl_node_get_default_options(void)
Return the default node options in a rcl_node_options_t.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_node_options_fini(rcl_node_options_t *options)
Finalize the given node_options.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_remap_node_namespace(const rcl_arguments_t *local_arguments, const rcl_arguments_t *global_arguments, const char *node_name, rcl_allocator_t allocator, char **output_namespace)
Remap a namespace based on given rules.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_remap_node_name(const rcl_arguments_t *local_arguments, const rcl_arguments_t *global_arguments, const char *node_name, rcl_allocator_t allocator, char **output_name)
Remap a node name based on given rules.
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 bool rcl_service_is_valid(const rcl_service_t *service)
Check that the service is valid.
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.
Hold output of parsing command line arguments.
rcl_arguments_impl_t * impl
Private implementation pointer.
rmw_context_t rmw_context
rmw context.
rcl_allocator_t allocator
Allocator used during init and shutdown.
Encapsulates the non-global state of an init/shutdown cycle.
rcl_context_impl_t * impl
Implementation specific pointer.
rcl_arguments_t global_arguments
Global arguments for all nodes which share this context.
Options available for a rcl guard condition.
rcl_allocator_t allocator
Custom allocator for the guard condition, used for internal allocations.
Handle for a rcl guard condition.
Structure which encapsulates the options for creating a rcl_node_t.
bool use_global_arguments
If false then only use arguments in this struct, otherwise use global arguments also.
rcl_arguments_t arguments
Command line arguments that apply only to this node.
rcl_allocator_t allocator
If true, no parameter infrastructure will be setup.
Structure which encapsulates a ROS Node.
rcl_node_impl_t * impl
Private implementation pointer.
rcl_context_t * context
Context associated with this node.
Options available for a rcl service.
Structure which encapsulates a ROS Service.
#define RCL_RET_NODE_INVALID_NAMESPACE
Invalid node namespace return code.
#define RCL_RET_NOT_INIT
rcl_init() not yet called return code.
#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_NODE_INVALID
Invalid rcl_node_t given return code.
#define RCL_RET_NODE_INVALID_NAME
Invalid node name return code.
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.