28 #include "rcl/error_handling.h"
37 #include "rcutils/env.h"
38 #include "rcutils/filesystem.h"
39 #include "rcutils/find.h"
40 #include "rcutils/format_string.h"
41 #include "rcutils/logging_macros.h"
42 #include "rcutils/macros.h"
43 #include "rcutils/repl_str.h"
44 #include "rcutils/snprintf.h"
45 #include "rcutils/strdup.h"
47 #include "rmw/error_handling.h"
48 #include "rmw/security_options.h"
50 #include "rmw/validate_namespace.h"
51 #include "rmw/validate_node_name.h"
52 #include "tracetools/tracetools.h"
54 #include "./context_impl.h"
56 const char *
const RCL_DISABLE_LOANED_MESSAGES_ENV_VAR =
"ROS_DISABLE_LOANED_MESSAGES";
61 rmw_node_t * rmw_node_handle;
63 const char * logger_name;
78 const char * rcl_create_node_logger_name(
79 const char * node_name,
80 const char * node_namespace,
84 if (strlen(node_namespace) == 1) {
85 return rcutils_strdup(node_name, *allocator);
91 const char * ns_with_separators = rcutils_repl_str(
93 "/", RCUTILS_LOGGING_SEPARATOR_STRING,
95 if (NULL == ns_with_separators) {
100 char * node_logger_name = rcutils_format_string(
101 *allocator,
"%s%s%s", ns_with_separators, RCUTILS_LOGGING_SEPARATOR_STRING, node_name);
102 allocator->deallocate((
char *)ns_with_separators, allocator->state);
103 return node_logger_name;
120 const char * namespace_,
124 const rmw_guard_condition_t * rmw_graph_guard_condition = NULL;
129 char * remapped_node_name = NULL;
139 RCUTILS_LOG_DEBUG_NAMED(
140 ROS_PACKAGE_NAME,
"Initializing node '%s' in namespace '%s'", name, namespace_);
142 RCL_SET_ERROR_MSG(
"node already initialized, or struct memory was unintialized");
146 RCL_CHECK_FOR_NULL_WITH_MSG(
150 "the given context is not valid, "
151 "either rcl_init() was not called or rcl_shutdown() was called.");
155 int validation_result = 0;
156 ret = rmw_validate_node_name(name, &validation_result, NULL);
157 if (ret != RMW_RET_OK) {
158 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
161 if (validation_result != RMW_NODE_NAME_VALID) {
162 const char * msg = rmw_node_name_validation_result_string(validation_result);
163 RCL_SET_ERROR_MSG(msg);
168 size_t namespace_length = strlen(namespace_);
169 const char * local_namespace_ = namespace_;
170 bool should_free_local_namespace_ =
false;
172 if (namespace_length == 0) {
174 local_namespace_ =
"/";
178 if (namespace_length > 0 && namespace_[0] !=
'/') {
179 local_namespace_ = rcutils_format_string(*allocator,
"/%s", namespace_);
180 RCL_CHECK_FOR_NULL_WITH_MSG(
182 "failed to format node namespace string",
184 should_free_local_namespace_ =
true;
187 validation_result = 0;
188 ret = rmw_validate_namespace(local_namespace_, &validation_result, NULL);
189 if (ret != RMW_RET_OK) {
190 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
193 if (validation_result != RMW_NAMESPACE_VALID) {
194 const char * msg = rmw_namespace_validation_result_string(validation_result);
195 RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
"%s, result: %d", msg, validation_result);
203 RCL_CHECK_FOR_NULL_WITH_MSG(
205 node->
impl->rmw_node_handle = NULL;
206 node->
impl->graph_guard_condition = NULL;
207 node->
impl->logger_name = NULL;
208 node->
impl->fq_name = NULL;
223 &(node->
impl->options.
arguments), global_args, name, *allocator,
224 &remapped_node_name);
227 }
else if (NULL != remapped_node_name) {
228 name = remapped_node_name;
230 char * remapped_namespace = NULL;
233 *allocator, &remapped_namespace);
236 }
else if (NULL != remapped_namespace) {
237 if (should_free_local_namespace_) {
238 allocator->deallocate((
char *)local_namespace_, allocator->state);
240 should_free_local_namespace_ =
true;
241 local_namespace_ = remapped_namespace;
245 if (
'/' == local_namespace_[strlen(local_namespace_) - 1]) {
246 node->
impl->fq_name = rcutils_format_string(*allocator,
"%s%s", local_namespace_, name);
248 node->
impl->fq_name = rcutils_format_string(*allocator,
"%s/%s", local_namespace_, name);
252 node->
impl->logger_name = rcl_create_node_logger_name(name, local_namespace_, allocator);
253 RCL_CHECK_FOR_NULL_WITH_MSG(
254 node->
impl->logger_name,
"creating logger name failed",
goto fail);
256 RCUTILS_LOG_DEBUG_NAMED(
257 ROS_PACKAGE_NAME,
"Using domain ID of '%zu'", context->
impl->
rmw_context.actual_domain_id);
259 node->
impl->rmw_node_handle = rmw_create_node(
261 name, local_namespace_);
263 RCL_CHECK_FOR_NULL_WITH_MSG(
264 node->
impl->rmw_node_handle, rmw_get_error_string().str,
goto fail);
266 rmw_graph_guard_condition = rmw_node_get_graph_guard_condition(node->
impl->rmw_node_handle);
267 RCL_CHECK_FOR_NULL_WITH_MSG(
268 rmw_graph_guard_condition, rmw_get_error_string().str,
goto fail);
272 RCL_CHECK_FOR_NULL_WITH_MSG(
273 node->
impl->graph_guard_condition,
274 "allocating memory failed",
277 graph_guard_condition_options.
allocator = *allocator;
279 node->
impl->graph_guard_condition,
280 rmw_graph_guard_condition,
282 graph_guard_condition_options);
296 RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME,
"Node initialized");
309 node->
impl->logger_name)
312 RCUTILS_LOG_ERROR_EXPRESSION_NAMED(
314 ROS_PACKAGE_NAME,
"Failed to fini publisher for node: %i", ret);
315 allocator->deallocate((
char *)node->
impl->logger_name, allocator->state);
317 if (node->
impl->fq_name) {
318 allocator->deallocate((
char *)node->
impl->fq_name, allocator->state);
320 if (node->
impl->rmw_node_handle) {
321 ret = rmw_destroy_node(node->
impl->rmw_node_handle);
322 if (ret != RMW_RET_OK) {
323 RCUTILS_LOG_ERROR_NAMED(
325 "failed to fini rmw node in error recovery: %s", rmw_get_error_string().str
329 if (node->
impl->graph_guard_condition) {
332 RCUTILS_LOG_ERROR_NAMED(
334 "failed to fini guard condition in error recovery: %s", rcl_get_error_string().str
337 allocator->deallocate(node->
impl->graph_guard_condition, allocator->state);
342 RCUTILS_LOG_ERROR_NAMED(
344 "failed to fini arguments in error recovery: %s", rcl_get_error_string().str
348 allocator->deallocate(node->
impl, allocator->state);
355 if (should_free_local_namespace_) {
356 allocator->deallocate((
char *)local_namespace_, allocator->state);
357 local_namespace_ = NULL;
359 if (NULL != remapped_node_name) {
360 allocator->deallocate(remapped_node_name, allocator->state);
368 RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME,
"Finalizing node");
380 RCL_SET_ERROR_MSG(
"Unable to fini publisher for node.");
384 rmw_ret_t rmw_ret = rmw_destroy_node(node->
impl->rmw_node_handle);
385 if (rmw_ret != RMW_RET_OK) {
386 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
391 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
394 allocator.deallocate(node->
impl->graph_guard_condition, allocator.state);
396 allocator.deallocate((
char *)node->
impl->logger_name, allocator.state);
397 allocator.deallocate((
char *)node->
impl->fq_name, allocator.state);
404 allocator.deallocate(node->
impl, allocator.state);
406 RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME,
"Node finalized");
413 RCL_CHECK_FOR_NULL_WITH_MSG(node,
"rcl node pointer is invalid",
return false);
414 RCL_CHECK_FOR_NULL_WITH_MSG(node->
impl,
"rcl node implementation is invalid",
return false);
415 RCL_CHECK_FOR_NULL_WITH_MSG(
416 node->
impl->rmw_node_handle,
"rcl node's rmw handle is invalid",
return false);
428 RCL_SET_ERROR_MSG(
"rcl node's context is invalid");
440 return node->
impl->rmw_node_handle->name;
449 return node->
impl->rmw_node_handle->namespace_;
458 return node->
impl->fq_name;
467 return &node->
impl->options;
490 return node->
impl->rmw_node_handle;
508 return node->
impl->graph_guard_condition;
517 return node->
impl->logger_name;
523 const char * env_val = NULL;
524 const char * env_error_str = NULL;
528 env_error_str = rcutils_get_env(RCL_DISABLE_LOANED_MESSAGES_ENV_VAR, &env_val);
529 if (NULL != env_error_str) {
530 RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
531 "Error getting env var: '" RCUTILS_STRINGIFY(RCL_DISABLE_LOANED_MESSAGES_ENV_VAR)
"': %s\n",
536 *disable_loaned_message = (strcmp(env_val,
"1") == 0);
#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 bool rcl_logging_rosout_enabled(void)
See if logging rosout is enabled.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_logging_rosout_init_publisher_for_node(rcl_node_t *node)
Creates a rosout publisher for a node and registers it to be used by the logging system.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_logging_rosout_fini_publisher_for_node(rcl_node_t *node)
Deregisters a rosout publisher for a node and cleans up allocated resources.
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_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 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 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_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.
Hold output of parsing command line arguments.
rcl_arguments_impl_t * impl
Private implementation pointer.
rmw_context_t rmw_context
rmw context.
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.
bool enable_rosout
Flag to enable rosout for 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.
#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.