ROS 2 rclcpp + rcl - rolling  rolling-29de98cf
ROS 2 C++ Client Library with ROS Client Library
node_graph.cpp
1 // Copyright 2016 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "rclcpp/node_interfaces/node_graph.hpp"
16 
17 #include <algorithm>
18 #include <cstddef>
19 #include <map>
20 #include <string>
21 #include <tuple>
22 #include <utility>
23 #include <vector>
24 
25 #include "rcl/graph.h"
26 #include "rcl/remap.h"
27 #include "rclcpp/event.hpp"
28 #include "rclcpp/exceptions.hpp"
29 #include "rclcpp/expand_topic_or_service_name.hpp"
30 #include "rclcpp/graph_listener.hpp"
31 #include "rclcpp/node_interfaces/node_graph_interface.hpp"
32 #include "rclcpp/utilities.hpp"
33 #include "rcpputils/scope_exit.hpp"
34 
36 using rclcpp::exceptions::throw_from_rcl_error;
38 
39 NodeGraph::NodeGraph(rclcpp::node_interfaces::NodeBaseInterface * node_base)
40 : node_base_(node_base),
41  should_add_to_graph_listener_(true),
42  graph_users_count_(0)
43 {}
44 
45 NodeGraph::~NodeGraph()
46 {
47  // Remove self from graph listener.
48  // Exchange with false to prevent others from trying to add this node to the
49  // graph listener after checking that it was not here.
50  if (!should_add_to_graph_listener_.exchange(false)) {
51  // If it was already false, then it needs to now be removed.
52  node_base_->get_context()->get_graph_listener()->remove_node(this);
53  }
54 }
55 
56 std::map<std::string, std::vector<std::string>>
57 NodeGraph::get_topic_names_and_types(bool no_demangle) const
58 {
60 
63  node_base_->get_rcl_node_handle(),
64  &allocator,
65  no_demangle,
66  &topic_names_and_types);
67  if (ret != RCL_RET_OK) {
68  auto error_msg = std::string("failed to get topic names and types: ") +
69  rcl_get_error_string().str;
70  rcl_reset_error();
71  if (rcl_names_and_types_fini(&topic_names_and_types) != RCL_RET_OK) {
72  error_msg += std::string(", failed also to cleanup topic names and types, leaking memory: ") +
73  rcl_get_error_string().str;
74  rcl_reset_error();
75  }
76  throw std::runtime_error(error_msg);
77  }
78 
79  std::map<std::string, std::vector<std::string>> topics_and_types;
80  for (size_t i = 0; i < topic_names_and_types.names.size; ++i) {
81  std::string topic_name = topic_names_and_types.names.data[i];
82  for (size_t j = 0; j < topic_names_and_types.types[i].size; ++j) {
83  topics_and_types[topic_name].emplace_back(topic_names_and_types.types[i].data[j]);
84  }
85  }
86 
87  ret = rcl_names_and_types_fini(&topic_names_and_types);
88  if (ret != RCL_RET_OK) {
89  // *INDENT-OFF*
90  throw std::runtime_error(
91  std::string("could not destroy topic names and types: ") + rcl_get_error_string().str);
92  // *INDENT-ON*
93  }
94 
95  return topics_and_types;
96 }
97 
98 std::map<std::string, std::vector<std::string>>
100 {
102 
105  node_base_->get_rcl_node_handle(),
106  &allocator,
107  &service_names_and_types);
108  if (ret != RCL_RET_OK) {
109  auto error_msg = std::string("failed to get service names and types: ") +
110  rcl_get_error_string().str;
111  rcl_reset_error();
112  if (rcl_names_and_types_fini(&service_names_and_types) != RCL_RET_OK) {
113  error_msg +=
114  std::string(", failed also to cleanup service names and types, leaking memory: ") +
115  rcl_get_error_string().str;
116  rcl_reset_error();
117  }
118  throw std::runtime_error(error_msg);
119  }
120 
121  std::map<std::string, std::vector<std::string>> services_and_types;
122  for (size_t i = 0; i < service_names_and_types.names.size; ++i) {
123  std::string service_name = service_names_and_types.names.data[i];
124  for (size_t j = 0; j < service_names_and_types.types[i].size; ++j) {
125  services_and_types[service_name].emplace_back(service_names_and_types.types[i].data[j]);
126  }
127  }
128 
129  ret = rcl_names_and_types_fini(&service_names_and_types);
130  if (ret != RCL_RET_OK) {
131  // *INDENT-OFF*
132  throw std::runtime_error(
133  std::string("could not destroy service names and types: ") + rcl_get_error_string().str);
134  // *INDENT-ON*
135  }
136 
137  return services_and_types;
138 }
139 
140 std::map<std::string, std::vector<std::string>>
142  const std::string & node_name,
143  const std::string & namespace_) const
144 {
148  node_base_->get_rcl_node_handle(),
149  &allocator,
150  node_name.c_str(),
151  namespace_.c_str(),
152  &service_names_and_types);
153  if (ret != RCL_RET_OK) {
154  auto error_msg = std::string("failed to get service names and types by node: ") +
155  rcl_get_error_string().str;
156  rcl_reset_error();
157  if (rcl_names_and_types_fini(&service_names_and_types) != RCL_RET_OK) {
158  error_msg +=
159  std::string(", failed also to cleanup service names and types, leaking memory: ") +
160  rcl_get_error_string().str;
161  rcl_reset_error();
162  }
163  throw std::runtime_error(error_msg);
164  }
165 
166  std::map<std::string, std::vector<std::string>> services_and_types;
167  for (size_t i = 0; i < service_names_and_types.names.size; ++i) {
168  std::string service_name = service_names_and_types.names.data[i];
169  for (size_t j = 0; j < service_names_and_types.types[i].size; ++j) {
170  services_and_types[service_name].emplace_back(service_names_and_types.types[i].data[j]);
171  }
172  }
173 
174  ret = rcl_names_and_types_fini(&service_names_and_types);
175  if (ret != RCL_RET_OK) {
176  throw_from_rcl_error(ret, "could not destroy service names and types");
177  }
178 
179  return services_and_types;
180 }
181 
182 std::map<std::string, std::vector<std::string>>
184  const std::string & node_name,
185  const std::string & namespace_) const
186 {
188  auto service_names_and_types_finalizer = rcpputils::make_scope_exit(
189  [&service_names_and_types]() {
190  if (rcl_names_and_types_fini(&service_names_and_types) != RCL_RET_OK) {
191  RCLCPP_ERROR(
192  rclcpp::get_logger("rclcpp"), "could not destroy service names and types");
193  }
194  });
197  node_base_->get_rcl_node_handle(),
198  &allocator,
199  node_name.c_str(),
200  namespace_.c_str(),
201  &service_names_and_types);
202  if (ret != RCL_RET_OK) {
203  throw_from_rcl_error(ret, "failed to get service names and types by node");
204  }
205 
206  std::map<std::string, std::vector<std::string>> services_and_types;
207  for (size_t i = 0; i < service_names_and_types.names.size; ++i) {
208  std::string service_name = service_names_and_types.names.data[i];
209  for (size_t j = 0; j < service_names_and_types.types[i].size; ++j) {
210  services_and_types[service_name].emplace_back(service_names_and_types.types[i].data[j]);
211  }
212  }
213 
214  return services_and_types;
215 }
216 
217 std::map<std::string, std::vector<std::string>>
219  const std::string & node_name,
220  const std::string & namespace_,
221  bool no_demangle) const
222 {
224  auto topic_names_and_types_finalizer = rcpputils::make_scope_exit(
225  [&topic_names_and_types]() {
226  if (rcl_names_and_types_fini(&topic_names_and_types) != RCL_RET_OK) {
227  RCLCPP_ERROR(
228  rclcpp::get_logger("rclcpp"), "could not destroy topic names and types");
229  }
230  });
233  node_base_->get_rcl_node_handle(),
234  &allocator,
235  no_demangle,
236  node_name.c_str(),
237  namespace_.c_str(),
238  &topic_names_and_types);
239  if (ret != RCL_RET_OK) {
240  throw_from_rcl_error(ret, "failed to get topic names and types by node");
241  }
242 
243  std::map<std::string, std::vector<std::string>> topics_and_types;
244  for (size_t i = 0; i < topic_names_and_types.names.size; ++i) {
245  std::string topic_name = topic_names_and_types.names.data[i];
246  for (size_t j = 0; j < topic_names_and_types.types[i].size; ++j) {
247  topics_and_types[topic_name].emplace_back(topic_names_and_types.types[i].data[j]);
248  }
249  }
250 
251  return topics_and_types;
252 }
253 
254 std::map<std::string, std::vector<std::string>>
256  const std::string & node_name,
257  const std::string & namespace_,
258  bool no_demangle) const
259 {
261  auto topic_names_and_types_finalizer = rcpputils::make_scope_exit(
262  [&topic_names_and_types]() {
263  if (rcl_names_and_types_fini(&topic_names_and_types) != RCL_RET_OK) {
264  RCLCPP_ERROR(
265  rclcpp::get_logger("rclcpp"), "could not destroy topic names and types");
266  }
267  });
270  node_base_->get_rcl_node_handle(),
271  &allocator,
272  no_demangle,
273  node_name.c_str(),
274  namespace_.c_str(),
275  &topic_names_and_types);
276  if (ret != RCL_RET_OK) {
277  throw_from_rcl_error(ret, "failed to get topic names and types by node");
278  }
279 
280  std::map<std::string, std::vector<std::string>> topics_and_types;
281  for (size_t i = 0; i < topic_names_and_types.names.size; ++i) {
282  std::string topic_name = topic_names_and_types.names.data[i];
283  for (size_t j = 0; j < topic_names_and_types.types[i].size; ++j) {
284  topics_and_types[topic_name].emplace_back(topic_names_and_types.types[i].data[j]);
285  }
286  }
287 
288  return topics_and_types;
289 }
290 
291 std::vector<std::string>
293 {
294  std::vector<std::string> nodes;
295  auto names_and_namespaces = get_node_names_and_namespaces();
296 
297  std::transform(
298  names_and_namespaces.begin(),
299  names_and_namespaces.end(),
300  std::back_inserter(nodes),
301  [](std::pair<std::string, std::string> nns) {
302  std::string return_string;
303  if (nns.second.back() == '/') {
304  return_string = nns.second + nns.first;
305  } else {
306  return_string = nns.second + '/' + nns.first;
307  }
308  // Quick check to make sure that we start with a slash
309  // Since fully-qualified strings need to
310  if (return_string.front() != '/') {
311  return_string = "/" + return_string;
312  }
313  return return_string;
314  }
315  );
316  return nodes;
317 }
318 
319 std::vector<std::tuple<std::string, std::string, std::string>>
321 {
322  rcutils_string_array_t node_names_c =
323  rcutils_get_zero_initialized_string_array();
324  rcutils_string_array_t node_namespaces_c =
325  rcutils_get_zero_initialized_string_array();
326  rcutils_string_array_t node_enclaves_c =
327  rcutils_get_zero_initialized_string_array();
328 
329  auto allocator = rcl_get_default_allocator();
331  node_base_->get_rcl_node_handle(),
332  allocator,
333  &node_names_c,
334  &node_namespaces_c,
335  &node_enclaves_c);
336  if (ret != RCL_RET_OK) {
337  auto error_msg =
338  std::string("failed to get node names with enclaves: ") + rcl_get_error_string().str;
339  rcl_reset_error();
340  if (rcutils_string_array_fini(&node_names_c) != RCUTILS_RET_OK) {
341  error_msg += std::string(", failed also to cleanup node names, leaking memory: ") +
342  rcl_get_error_string().str;
343  rcl_reset_error();
344  }
345  if (rcutils_string_array_fini(&node_namespaces_c) != RCUTILS_RET_OK) {
346  error_msg += std::string(", failed also to cleanup node namespaces, leaking memory: ") +
347  rcl_get_error_string().str;
348  rcl_reset_error();
349  }
350  if (rcutils_string_array_fini(&node_enclaves_c) != RCUTILS_RET_OK) {
351  error_msg += std::string(", failed also to cleanup node enclaves, leaking memory: ") +
352  rcl_get_error_string().str;
353  rcl_reset_error();
354  }
355  throw std::runtime_error(error_msg);
356  }
357 
358  std::vector<std::tuple<std::string, std::string, std::string>> node_tuples;
359  for (size_t i = 0; i < node_names_c.size; ++i) {
360  if (node_names_c.data[i] && node_namespaces_c.data[i] && node_enclaves_c.data[i]) {
361  node_tuples.emplace_back(
362  std::make_tuple(node_names_c.data[i], node_namespaces_c.data[i], node_enclaves_c.data[i]));
363  }
364  }
365 
366  std::string error("failed to finalize array");
367  rcl_ret_t ret_names = rcutils_string_array_fini(&node_names_c);
368  if (ret_names != RCUTILS_RET_OK) {
369  error += std::string(", could not destroy node names, leaking memory: ") +
370  rcl_get_error_string().str;
371  rcl_reset_error();
372  }
373  rcl_ret_t ret_ns = rcutils_string_array_fini(&node_namespaces_c);
374  if (ret_ns != RCUTILS_RET_OK) {
375  error += std::string(", could not destroy node namespaces, leaking memory: ") +
376  rcl_get_error_string().str;
377  rcl_reset_error();
378  }
379 
380  rcl_ret_t ret_ecv = rcutils_string_array_fini(&node_enclaves_c);
381  if (ret_ecv != RCUTILS_RET_OK) {
382  error += std::string(", could not destroy node enclaves, leaking memory: ") +
383  rcl_get_error_string().str;
384  rcl_reset_error();
385  }
386 
387  if (ret_names != RCUTILS_RET_OK || ret_ns != RCUTILS_RET_OK || ret_ecv != RCUTILS_RET_OK) {
388  throw std::runtime_error(error);
389  }
390 
391  return node_tuples;
392 }
393 
394 std::vector<std::pair<std::string, std::string>>
396 {
397  rcutils_string_array_t node_names_c =
398  rcutils_get_zero_initialized_string_array();
399  rcutils_string_array_t node_namespaces_c =
400  rcutils_get_zero_initialized_string_array();
401 
402  auto allocator = rcl_get_default_allocator();
403  auto ret = rcl_get_node_names(
404  node_base_->get_rcl_node_handle(),
405  allocator,
406  &node_names_c,
407  &node_namespaces_c);
408  if (ret != RCL_RET_OK) {
409  auto error_msg = std::string("failed to get node names: ") + rcl_get_error_string().str;
410  rcl_reset_error();
411  if (rcutils_string_array_fini(&node_names_c) != RCUTILS_RET_OK) {
412  error_msg += std::string(", failed also to cleanup node names, leaking memory: ") +
413  rcl_get_error_string().str;
414  rcl_reset_error();
415  }
416  if (rcutils_string_array_fini(&node_namespaces_c) != RCUTILS_RET_OK) {
417  error_msg += std::string(", failed also to cleanup node namespaces, leaking memory: ") +
418  rcl_get_error_string().str;
419  rcl_reset_error();
420  }
421  RCUTILS_LOG_ERROR_NAMED("rclcpp", "%s", error_msg.c_str());
422  throw std::runtime_error(error_msg);
423  }
424 
425  std::vector<std::pair<std::string, std::string>> node_names;
426  node_names.reserve(node_names_c.size);
427  for (size_t i = 0; i < node_names_c.size; ++i) {
428  if (node_names_c.data[i] && node_namespaces_c.data[i]) {
429  node_names.emplace_back(node_names_c.data[i], node_namespaces_c.data[i]);
430  }
431  }
432 
433  std::string error;
434  rcl_ret_t ret_names = rcutils_string_array_fini(&node_names_c);
435  if (ret_names != RCUTILS_RET_OK) {
436  error = std::string("could not destroy node names: ") + rcl_get_error_string().str;
437  }
438  rcl_ret_t ret_ns = rcutils_string_array_fini(&node_namespaces_c);
439  if (ret_ns != RCUTILS_RET_OK) {
440  error += std::string(", could not destroy node namespaces: ") + rcl_get_error_string().str;
441  }
442 
443  if (ret_names != RCUTILS_RET_OK || ret_ns != RCUTILS_RET_OK) {
444  RCUTILS_LOG_ERROR_NAMED("rclcpp", "%s", error.c_str());
445  throw std::runtime_error(error);
446  }
447 
448  return node_names;
449 }
450 
451 size_t
452 NodeGraph::count_publishers(const std::string & topic_name) const
453 {
454  auto rcl_node_handle = node_base_->get_rcl_node_handle();
455 
457  topic_name,
458  rcl_node_get_name(rcl_node_handle),
459  rcl_node_get_namespace(rcl_node_handle),
460  false); // false = not a service
461 
462  size_t count;
463  auto ret = rcl_count_publishers(rcl_node_handle, fqdn.c_str(), &count);
464  if (ret != RMW_RET_OK) {
465  // *INDENT-OFF*
466  throw std::runtime_error(
467  std::string("could not count publishers: ") + rmw_get_error_string().str);
468  // *INDENT-ON*
469  }
470  return count;
471 }
472 
473 size_t
474 NodeGraph::count_subscribers(const std::string & topic_name) const
475 {
476  auto rcl_node_handle = node_base_->get_rcl_node_handle();
477 
479  topic_name,
480  rcl_node_get_name(rcl_node_handle),
481  rcl_node_get_namespace(rcl_node_handle),
482  false); // false = not a service
483 
484  size_t count;
485  auto ret = rcl_count_subscribers(rcl_node_handle, fqdn.c_str(), &count);
486  if (ret != RMW_RET_OK) {
487  // *INDENT-OFF*
488  throw std::runtime_error(
489  std::string("could not count subscribers: ") + rmw_get_error_string().str);
490  // *INDENT-ON*
491  }
492  return count;
493 }
494 
495 size_t
496 NodeGraph::count_clients(const std::string & service_name) const
497 {
498  auto rcl_node_handle = node_base_->get_rcl_node_handle();
499 
501  service_name,
502  rcl_node_get_name(rcl_node_handle),
503  rcl_node_get_namespace(rcl_node_handle),
504  true);
505 
506  size_t count;
507  auto ret = rcl_count_clients(rcl_node_handle, fqdn.c_str(), &count);
508  if (ret != RMW_RET_OK) {
509  // *INDENT-OFF*
510  throw std::runtime_error(
511  std::string("could not count clients: ") + rmw_get_error_string().str);
512  // *INDENT-ON*
513  }
514  return count;
515 }
516 
517 size_t
518 NodeGraph::count_services(const std::string & service_name) const
519 {
520  auto rcl_node_handle = node_base_->get_rcl_node_handle();
521 
523  service_name,
524  rcl_node_get_name(rcl_node_handle),
525  rcl_node_get_namespace(rcl_node_handle),
526  true);
527 
528  size_t count;
529  auto ret = rcl_count_services(rcl_node_handle, fqdn.c_str(), &count);
530  if (ret != RMW_RET_OK) {
531  // *INDENT-OFF*
532  throw std::runtime_error(
533  std::string("could not count services: ") + rmw_get_error_string().str);
534  // *INDENT-ON*
535  }
536  return count;
537 }
538 
539 const rcl_guard_condition_t *
541 {
543 }
544 
545 void
547 {
548  {
549  std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
550  bool bad_ptr_encountered = false;
551  for (auto & event_wptr : graph_events_) {
552  auto event_ptr = event_wptr.lock();
553  if (event_ptr) {
554  event_ptr->set();
555  } else {
556  bad_ptr_encountered = true;
557  }
558  }
559  if (bad_ptr_encountered) {
560  // remove invalid pointers with the erase-remove idiom
561  graph_events_.erase(
562  std::remove_if(
563  graph_events_.begin(),
564  graph_events_.end(),
565  [](const rclcpp::Event::WeakPtr & wptr) {
566  return wptr.expired();
567  }),
568  graph_events_.end());
569  // update graph_users_count_
570  graph_users_count_.store(graph_events_.size());
571  }
572  }
573  graph_cv_.notify_all();
574  try {
575  node_base_->trigger_notify_guard_condition();
576  } catch (const rclcpp::exceptions::RCLError & ex) {
577  throw std::runtime_error(
578  std::string("failed to notify wait set on graph change: ") + ex.what());
579  }
580 }
581 
582 void
584 {
585  // notify here anything that will not be woken up by ctrl-c or rclcpp::shutdown().
586  graph_cv_.notify_all();
587 }
588 
589 rclcpp::Event::SharedPtr
591 {
592  auto event = rclcpp::Event::make_shared();
593  {
594  std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
595  graph_events_.push_back(event);
596  graph_users_count_++;
597  }
598  // on first call, add node to graph_listener_
599  if (should_add_to_graph_listener_.exchange(false)) {
600  node_base_->get_context()->get_graph_listener()->add_node(this);
601  node_base_->get_context()->get_graph_listener()->start_if_not_started();
602  }
603  return event;
604 }
605 
606 void
608  rclcpp::Event::SharedPtr event,
609  std::chrono::nanoseconds timeout)
610 {
613  if (!event) {
614  throw InvalidEventError();
615  }
616  {
617  std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
618  bool event_in_graph_events = false;
619  for (const auto & event_wptr : graph_events_) {
620  if (event == event_wptr.lock()) {
621  event_in_graph_events = true;
622  break;
623  }
624  }
625  if (!event_in_graph_events) {
626  throw EventNotRegisteredError();
627  }
628  }
629  auto pred = [&event, context = node_base_->get_context()]() {
630  return event->check() || !rclcpp::ok(context);
631  };
632  std::unique_lock<std::mutex> graph_lock(graph_mutex_);
633  if (!pred()) {
634  graph_cv_.wait_for(graph_lock, timeout, pred);
635  }
636 }
637 
638 size_t
640 {
641  return graph_users_count_.load();
642 }
643 
644 static
645 std::vector<rclcpp::TopicEndpointInfo>
646 convert_to_topic_info_list(const rcl_topic_endpoint_info_array_t & info_array)
647 {
648  std::vector<rclcpp::TopicEndpointInfo> topic_info_list;
649  topic_info_list.reserve(info_array.size);
650  for (size_t i = 0; i < info_array.size; ++i) {
651  topic_info_list.emplace_back(info_array.info_array[i]);
652  }
653  return topic_info_list;
654 }
655 
656 template<const char * EndpointType, typename FunctionT>
657 static std::vector<rclcpp::TopicEndpointInfo>
658 get_info_by_topic(
660  const std::string & topic_name,
661  bool no_mangle,
662  FunctionT rcl_get_info_by_topic)
663 {
664  std::string fqdn;
665  auto rcl_node_handle = node_base->get_rcl_node_handle();
666 
667  if (no_mangle) {
668  fqdn = topic_name;
669  } else {
671  topic_name,
672  rcl_node_get_name(rcl_node_handle),
673  rcl_node_get_namespace(rcl_node_handle),
674  false); // false = not a service
675 
676  // Get the node options
677  const rcl_node_options_t * node_options = rcl_node_get_options(rcl_node_handle);
678  if (nullptr == node_options) {
679  throw std::runtime_error("Need valid node options in get_info_by_topic()");
680  }
681  const rcl_arguments_t * global_args = nullptr;
682  if (node_options->use_global_arguments) {
683  global_args = &(rcl_node_handle->context->global_arguments);
684  }
685 
686  char * remapped_topic_name = nullptr;
688  &(node_options->arguments),
689  global_args,
690  fqdn.c_str(),
691  rcl_node_get_name(rcl_node_handle),
692  rcl_node_get_namespace(rcl_node_handle),
693  node_options->allocator,
694  &remapped_topic_name);
695  if (RCL_RET_OK != ret) {
696  throw_from_rcl_error(ret, std::string("Failed to remap topic name ") + fqdn);
697  } else if (nullptr != remapped_topic_name) {
698  fqdn = remapped_topic_name;
699  node_options->allocator.deallocate(remapped_topic_name, node_options->allocator.state);
700  }
701  }
702 
703  rcutils_allocator_t allocator = rcutils_get_default_allocator();
705  rcl_ret_t ret =
706  rcl_get_info_by_topic(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
707  if (RCL_RET_OK != ret) {
708  auto error_msg =
709  std::string("Failed to get information by topic for ") + EndpointType + std::string(":");
710  if (RCL_RET_UNSUPPORTED == ret) {
711  error_msg += std::string("function not supported by RMW_IMPLEMENTATION");
712  } else {
713  error_msg += rcl_get_error_string().str;
714  }
715  rcl_reset_error();
716  if (RCL_RET_OK != rcl_topic_endpoint_info_array_fini(&info_array, &allocator)) {
717  error_msg += std::string(", failed also to cleanup topic info array, leaking memory: ") +
718  rcl_get_error_string().str;
719  rcl_reset_error();
720  }
721  throw_from_rcl_error(ret, error_msg);
722  }
723 
724  std::vector<rclcpp::TopicEndpointInfo> topic_info_list = convert_to_topic_info_list(info_array);
725  ret = rcl_topic_endpoint_info_array_fini(&info_array, &allocator);
726  if (RCL_RET_OK != ret) {
727  throw_from_rcl_error(ret, "rcl_topic_info_array_fini failed.");
728  }
729 
730  return topic_info_list;
731 }
732 
733 static constexpr char kPublisherEndpointTypeName[] = "publishers";
734 std::vector<rclcpp::TopicEndpointInfo>
736  const std::string & topic_name,
737  bool no_mangle) const
738 {
739  return get_info_by_topic<kPublisherEndpointTypeName>(
740  node_base_,
741  topic_name,
742  no_mangle,
744 }
745 
746 static constexpr char kSubscriptionEndpointTypeName[] = "subscriptions";
747 std::vector<rclcpp::TopicEndpointInfo>
749  const std::string & topic_name,
750  bool no_mangle) const
751 {
752  return get_info_by_topic<kSubscriptionEndpointTypeName>(
753  node_base_,
754  topic_name,
755  no_mangle,
757 }
758 
759 static
760 std::vector<rclcpp::ServiceEndpointInfo>
761 convert_to_service_info_list(const rcl_service_endpoint_info_array_t & info_array)
762 {
763  std::vector<rclcpp::ServiceEndpointInfo> service_info_list;
764  service_info_list.reserve(info_array.size);
765  for (size_t i = 0; i < info_array.size; ++i) {
766  service_info_list.emplace_back(info_array.info_array[i]);
767  }
768  return service_info_list;
769 }
770 
771 template<const char * EndpointType, typename FunctionT>
772 static std::vector<rclcpp::ServiceEndpointInfo>
773 get_info_by_service(
775  const std::string & service_name,
776  bool no_mangle,
777  FunctionT rcl_get_info_by_service)
778 {
779  std::string fqdn;
780  auto rcl_node_handle = node_base->get_rcl_node_handle();
781 
782  if (no_mangle) {
783  fqdn = service_name;
784  } else {
786  service_name,
787  rcl_node_get_name(rcl_node_handle),
788  rcl_node_get_namespace(rcl_node_handle),
789  true);
790 
791  // Get the node options
792  const rcl_node_options_t * node_options = rcl_node_get_options(rcl_node_handle);
793  if (nullptr == node_options) {
794  throw std::runtime_error("Need valid node options in get_info_by_service()");
795  }
796  const rcl_arguments_t * global_args = nullptr;
797  if (node_options->use_global_arguments) {
798  global_args = &(rcl_node_handle->context->global_arguments);
799  }
800 
801  char * remapped_service_name = nullptr;
803  &(node_options->arguments),
804  global_args,
805  fqdn.c_str(),
806  rcl_node_get_name(rcl_node_handle),
807  rcl_node_get_namespace(rcl_node_handle),
808  node_options->allocator,
809  &remapped_service_name);
810  if (RCL_RET_OK != ret) {
811  throw_from_rcl_error(ret, std::string("Failed to remap service name ") + fqdn);
812  } else if (nullptr != remapped_service_name) {
813  fqdn = remapped_service_name;
814  node_options->allocator.deallocate(remapped_service_name, node_options->allocator.state);
815  }
816  }
817 
818  rcutils_allocator_t allocator = rcutils_get_default_allocator();
819  rcl_service_endpoint_info_array_t info_array =
821  rcl_ret_t ret =
822  rcl_get_info_by_service(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
823  if (RCL_RET_OK != ret) {
824  auto error_msg =
825  std::string("Failed to get information by service for ") + EndpointType + std::string(":");
826  if (RCL_RET_UNSUPPORTED == ret) {
827  error_msg += std::string("function not supported by RMW_IMPLEMENTATION");
828  } else {
829  error_msg += rcl_get_error_string().str;
830  }
831  rcl_reset_error();
832  if (RCL_RET_OK != rcl_service_endpoint_info_array_fini(&info_array, &allocator)) {
833  error_msg += std::string(", failed also to cleanup service info array, leaking memory: ") +
834  rcl_get_error_string().str;
835  rcl_reset_error();
836  }
837  throw_from_rcl_error(ret, error_msg);
838  }
839 
840  std::vector<rclcpp::ServiceEndpointInfo> service_info_list =
841  convert_to_service_info_list(info_array);
842  ret = rcl_service_endpoint_info_array_fini(&info_array, &allocator);
843  if (RCL_RET_OK != ret) {
844  throw_from_rcl_error(ret, "rcl_service_info_array_fini failed.");
845  }
846 
847  return service_info_list;
848 }
849 
850 static constexpr char kClientEndpointTypeName[] = "clients";
851 std::vector<rclcpp::ServiceEndpointInfo>
853  const std::string & service_name,
854  bool no_mangle) const
855 {
856  return get_info_by_service<kClientEndpointTypeName>(
857  node_base_,
858  service_name,
859  no_mangle,
861 }
862 
863 static constexpr char kServerEndpointTypeName[] = "servers";
864 std::vector<rclcpp::ServiceEndpointInfo>
866  const std::string & service_name,
867  bool no_mangle) const
868 {
869  return get_info_by_service<kServerEndpointTypeName>(
870  node_base_,
871  service_name,
872  no_mangle,
874 }
875 
876 std::string &
878 {
879  return node_name_;
880 }
881 
882 const std::string &
884 {
885  return node_name_;
886 }
887 
888 std::string &
890 {
891  return node_namespace_;
892 }
893 
894 const std::string &
896 {
897  return node_namespace_;
898 }
899 
900 std::string &
902 {
903  return topic_type_;
904 }
905 
906 const std::string &
908 {
909  return topic_type_;
910 }
911 
912 rclcpp::EndpointType &
914 {
915  return endpoint_type_;
916 }
917 
918 const rclcpp::EndpointType &
920 {
921  return endpoint_type_;
922 }
923 
924 std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
926 {
927  return endpoint_gid_;
928 }
929 
930 const std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
932 {
933  return endpoint_gid_;
934 }
935 
936 rclcpp::QoS &
938 {
939  return qos_profile_;
940 }
941 
942 const rclcpp::QoS &
944 {
945  return qos_profile_;
946 }
947 
948 rosidl_type_hash_t &
950 {
951  return topic_type_hash_;
952 }
953 
954 const rosidl_type_hash_t &
956 {
957  return topic_type_hash_;
958 }
959 
960 std::string &
962 {
963  return node_name_;
964 }
965 
966 const std::string &
968 {
969  return node_name_;
970 }
971 
972 std::string &
974 {
975  return node_namespace_;
976 }
977 
978 const std::string &
980 {
981  return node_namespace_;
982 }
983 
984 std::string &
986 {
987  return service_type_;
988 }
989 
990 const std::string &
992 {
993  return service_type_;
994 }
995 
996 rclcpp::EndpointType &
998 {
999  return endpoint_type_;
1000 }
1001 
1002 const rclcpp::EndpointType &
1004 {
1005  return endpoint_type_;
1006 }
1007 
1008 size_t &
1010 {
1011  return endpoint_count_;
1012 }
1013 
1014 const size_t &
1016 {
1017  return endpoint_count_;
1018 }
1019 
1020 std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
1022 {
1023  return endpoint_gids_;
1024 }
1025 
1026 const std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
1028 {
1029  return endpoint_gids_;
1030 }
1031 
1032 std::vector<rclcpp::QoS> &
1034 {
1035  return qos_profiles_;
1036 }
1037 
1038 const std::vector<rclcpp::QoS> &
1040 {
1041  return qos_profiles_;
1042 }
1043 
1044 rosidl_type_hash_t &
1046 {
1047  return service_type_hash_;
1048 }
1049 
1050 const rosidl_type_hash_t &
1052 {
1053  return service_type_hash_;
1054 }
#define rcl_get_default_allocator
Return a properly initialized rcl_allocator_t with default values.
Definition: allocator.h:37
rcutils_allocator_t rcl_allocator_t
Encapsulation of an allocator.
Definition: allocator.h:31
Encapsulation of Quality of Service settings.
Definition: qos.hpp:114
RCLCPP_PUBLIC rclcpp::EndpointType & endpoint_type()
Get a mutable reference to the service endpoint type.
Definition: node_graph.cpp:997
RCLCPP_PUBLIC std::string & node_name()
Get a mutable reference to the node name.
Definition: node_graph.cpp:961
RCLCPP_PUBLIC size_t & endpoint_count()
Get a mutable reference to the endpoint count.
RCLCPP_PUBLIC rosidl_type_hash_t & service_type_hash()
Get a mutable reference to the type hash of the service endpoint.
RCLCPP_PUBLIC std::vector< rclcpp::QoS > & qos_profiles()
Get a mutable reference to the QoS profile of the service endpoint.
RCLCPP_PUBLIC std::string & node_namespace()
Get a mutable reference to the node namespace.
Definition: node_graph.cpp:973
RCLCPP_PUBLIC std::vector< std::array< uint8_t, RMW_GID_STORAGE_SIZE > > & endpoint_gids()
Get a mutable reference to the GID of the service endpoint.
RCLCPP_PUBLIC std::string & service_type()
Get a mutable reference to the service type string.
Definition: node_graph.cpp:985
RCLCPP_PUBLIC std::string & node_name()
Get a mutable reference to the node name.
Definition: node_graph.cpp:877
RCLCPP_PUBLIC std::string & node_namespace()
Get a mutable reference to the node namespace.
Definition: node_graph.cpp:889
RCLCPP_PUBLIC rosidl_type_hash_t & topic_type_hash()
Get a mutable reference to the type hash of the topic endpoint.
Definition: node_graph.cpp:949
RCLCPP_PUBLIC std::string & topic_type()
Get a mutable reference to the topic type string.
Definition: node_graph.cpp:901
RCLCPP_PUBLIC rclcpp::QoS & qos_profile()
Get a mutable reference to the QoS profile of the topic endpoint.
Definition: node_graph.cpp:937
RCLCPP_PUBLIC rclcpp::EndpointType & endpoint_type()
Get a mutable reference to the topic endpoint type.
Definition: node_graph.cpp:913
RCLCPP_PUBLIC std::array< uint8_t, RMW_GID_STORAGE_SIZE > & endpoint_gid()
Get a mutable reference to the GID of the topic endpoint.
Definition: node_graph.cpp:925
Thrown when an unregistered rclcpp::Event is encountered where a registered one was expected.
Definition: exceptions.hpp:236
Thrown when an invalid rclcpp::Event object or SharedPtr is encountered.
Definition: exceptions.hpp:228
Created when the return code does not match one of the other specialized exceptions.
Definition: exceptions.hpp:162
Notifies many nodes of graph changes by listening in a thread.
Pure virtual interface class for the NodeBase part of the Node API.
virtual RCLCPP_PUBLIC void trigger_notify_guard_condition()=0
Trigger the guard condition that notifies of internal node state changes.
virtual RCLCPP_PUBLIC rcl_node_t * get_rcl_node_handle()=0
Return the rcl_node_t node handle (non-const version).
virtual RCLCPP_PUBLIC rclcpp::Context::SharedPtr get_context()=0
Return the context of the node.
Implementation the NodeGraph part of the Node API.
Definition: node_graph.hpp:52
RCLCPP_PUBLIC std::vector< std::string > get_node_names() const override
Return a vector of existing node names (string).
Definition: node_graph.cpp:292
RCLCPP_PUBLIC std::map< std::string, std::vector< std::string > > get_service_names_and_types() const override
Return a map of existing service names to list of service types.
Definition: node_graph.cpp:99
RCLCPP_PUBLIC std::map< std::string, std::vector< std::string > > get_publisher_names_and_types_by_node(const std::string &node_name, const std::string &namespace_, bool no_demangle=false) const override
Return a map of existing topic names to list of topic types for a specific node.
Definition: node_graph.cpp:218
RCLCPP_PUBLIC std::vector< rclcpp::TopicEndpointInfo > get_publishers_info_by_topic(const std::string &topic_name, bool no_mangle=false) const override
Return the topic endpoint information about publishers on a given topic.
Definition: node_graph.cpp:735
RCLCPP_PUBLIC std::vector< std::pair< std::string, std::string > > get_node_names_and_namespaces() const override
Return a vector of existing node names and namespaces (pair of string).
Definition: node_graph.cpp:395
RCLCPP_PUBLIC size_t count_services(const std::string &service_name) const override
Return the number of services created for a given service.
Definition: node_graph.cpp:518
RCLCPP_PUBLIC std::map< std::string, std::vector< std::string > > get_subscriber_names_and_types_by_node(const std::string &node_name, const std::string &namespace_, bool no_demangle=false) const override
Return a map of existing topic names to list of topic types for a specific node.
Definition: node_graph.cpp:255
RCLCPP_PUBLIC size_t count_subscribers(const std::string &topic_name) const override
Return the number of subscribers who have created a subscription for a given topic.
Definition: node_graph.cpp:474
RCLCPP_PUBLIC std::map< std::string, std::vector< std::string > > get_client_names_and_types_by_node(const std::string &node_name, const std::string &namespace_) const override
Return a map of existing service names and types with a specific node.
Definition: node_graph.cpp:183
RCLCPP_PUBLIC std::vector< rclcpp::TopicEndpointInfo > get_subscriptions_info_by_topic(const std::string &topic_name, bool no_mangle=false) const override
Return the topic endpoint information about subscriptions on a given topic.
Definition: node_graph.cpp:748
RCLCPP_PUBLIC size_t count_graph_users() const override
Return the number of on loan graph events, see get_graph_event().
Definition: node_graph.cpp:639
RCLCPP_PUBLIC std::map< std::string, std::vector< std::string > > get_topic_names_and_types(bool no_demangle=false) const override
Return a map of existing topic names to list of topic types.
Definition: node_graph.cpp:57
RCLCPP_PUBLIC void wait_for_graph_change(rclcpp::Event::SharedPtr event, std::chrono::nanoseconds timeout) override
Wait for a graph event to occur by waiting on an Event to become set.
Definition: node_graph.cpp:607
RCLCPP_PUBLIC std::map< std::string, std::vector< std::string > > get_service_names_and_types_by_node(const std::string &node_name, const std::string &namespace_) const override
Return a map of existing service names to list of service types for a specific node.
Definition: node_graph.cpp:141
RCLCPP_PUBLIC rclcpp::Event::SharedPtr get_graph_event() override
Return a graph event, which will be set anytime a graph change occurs.
Definition: node_graph.cpp:590
RCLCPP_PUBLIC std::vector< rclcpp::ServiceEndpointInfo > get_clients_info_by_service(const std::string &service_name, bool no_mangle=false) const override
Return the service endpoint information about clients on a given service.
Definition: node_graph.cpp:852
RCLCPP_PUBLIC void notify_shutdown() override
Notify any and all blocking node actions that shutdown has occurred.
Definition: node_graph.cpp:583
RCLCPP_PUBLIC std::vector< std::tuple< std::string, std::string, std::string > > get_node_names_with_enclaves() const override
Return a vector of existing node names, namespaces and enclaves (tuple of string).
Definition: node_graph.cpp:320
RCLCPP_PUBLIC size_t count_publishers(const std::string &topic_name) const override
Return the number of publishers that are advertised on a given topic.
Definition: node_graph.cpp:452
RCLCPP_PUBLIC size_t count_clients(const std::string &service_name) const override
Return the number of clients created for a given service.
Definition: node_graph.cpp:496
RCLCPP_PUBLIC std::vector< rclcpp::ServiceEndpointInfo > get_servers_info_by_service(const std::string &service_name, bool no_mangle=false) const override
Return the service endpoint information about servers on a given service.
Definition: node_graph.cpp:865
RCLCPP_PUBLIC void notify_graph_change() override
Notify threads waiting on graph changes.
Definition: node_graph.cpp:546
RCLCPP_PUBLIC const rcl_guard_condition_t * get_graph_guard_condition() const override
Return the rcl guard condition which is triggered when the ROS graph changes.
Definition: node_graph.cpp:540
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_servers_info_by_service(const rcl_node_t *node, rcutils_allocator_t *allocator, const char *service_name, bool no_mangle, rcl_service_endpoint_info_array_t *servers_info)
Return a list of all servers to a service.
Definition: graph.c:866
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_count_services(const rcl_node_t *node, const char *service_name, size_t *count)
Return the number of servers on a given service.
Definition: graph.c:484
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_subscriptions_info_by_topic(const rcl_node_t *node, rcutils_allocator_t *allocator, const char *topic_name, bool no_mangle, rcl_topic_endpoint_info_array_t *subscriptions_info)
Return a list of all subscriptions to a topic.
Definition: graph.c:782
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_names_and_types_fini(rcl_names_and_types_t *names_and_types)
Finalize a rcl_names_and_types_t object.
Definition: graph.c:311
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_node_names_with_enclaves(const rcl_node_t *node, rcl_allocator_t allocator, rcutils_string_array_t *node_names, rcutils_string_array_t *node_namespaces, rcutils_string_array_t *enclaves)
Return a list of node names and their associated namespaces and enclaves in the ROS graph.
Definition: graph.c:380
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_service_names_and_types(const rcl_node_t *node, rcl_allocator_t *allocator, rcl_names_and_types_t *service_names_and_types)
Return a list of service names and their types.
Definition: graph.c:272
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_client_names_and_types_by_node(const rcl_node_t *node, rcl_allocator_t *allocator, const char *node_name, const char *node_namespace, rcl_names_and_types_t *service_names_and_types)
Return a list of service client names and types associated with a node.
Definition: graph.c:205
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_publishers_info_by_topic(const rcl_node_t *node, rcutils_allocator_t *allocator, const char *topic_name, bool no_mangle, rcl_topic_endpoint_info_array_t *publishers_info)
Return a list of all publishers to a topic.
Definition: graph.c:765
rmw_topic_endpoint_info_array_t rcl_topic_endpoint_info_array_t
An array of topic endpoint information.
Definition: graph.h:51
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_service_names_and_types_by_node(const rcl_node_t *node, rcl_allocator_t *allocator, const char *node_name, const char *node_namespace, rcl_names_and_types_t *service_names_and_types)
Return a list of service names and types associated with a node.
Definition: graph.c:165
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_subscriber_names_and_types_by_node(const rcl_node_t *node, rcl_allocator_t *allocator, bool no_demangle, const char *node_name, const char *node_namespace, rcl_names_and_types_t *topic_names_and_types)
Return a list of topic names and types for subscriptions associated with a node.
Definition: graph.c:123
#define rcl_service_endpoint_info_array_fini
Finalize a service_endpoint_info_array_t structure.
Definition: graph.h:76
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_count_subscribers(const rcl_node_t *node, const char *topic_name, size_t *count)
Return the number of subscriptions on a given topic.
Definition: graph.c:446
#define rcl_get_zero_initialized_service_endpoint_info_array
Return a zero-initialized rcl_service_endpoint_info_t structure.
Definition: graph.h:72
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_count_clients(const rcl_node_t *node, const char *service_name, size_t *count)
Return the number of clients on a given service.
Definition: graph.c:465
rmw_names_and_types_t rcl_names_and_types_t
A structure that contains topic names and types.
Definition: graph.h:43
#define rcl_topic_endpoint_info_array_fini
Finalize a topic_endpoint_info_array_t structure.
Definition: graph.h:69
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_publisher_names_and_types_by_node(const rcl_node_t *node, rcl_allocator_t *allocator, bool no_demangle, const char *node_name, const char *node_namespace, rcl_names_and_types_t *topic_names_and_types)
Return a list of topic names and types for publishers associated with a node.
Definition: graph.c:82
#define rcl_get_zero_initialized_names_and_types
Return a zero-initialized rcl_names_and_types_t structure.
Definition: graph.h:62
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_topic_names_and_types(const rcl_node_t *node, rcl_allocator_t *allocator, bool no_demangle, rcl_names_and_types_t *topic_names_and_types)
Return a list of topic names and their types.
Definition: graph.c:245
#define rcl_get_zero_initialized_topic_endpoint_info_array
Return a zero-initialized rcl_topic_endpoint_info_t structure.
Definition: graph.h:65
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_node_names(const rcl_node_t *node, rcl_allocator_t allocator, rcutils_string_array_t *node_names, rcutils_string_array_t *node_namespaces)
Return a list of node names and their associated namespaces in the ROS graph.
Definition: graph.c:321
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_get_clients_info_by_service(const rcl_node_t *node, rcutils_allocator_t *allocator, const char *service_name, bool no_mangle, rcl_service_endpoint_info_array_t *clients_info)
Return a list of all clients to a service.
Definition: graph.c:849
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_count_publishers(const rcl_node_t *node, const char *topic_name, size_t *count)
Return the number of publishers on a given topic.
Definition: graph.c:427
RCLCPP_PUBLIC std::string expand_topic_or_service_name(const std::string &name, const std::string &node_name, const std::string &namespace_, bool is_service=false)
Expand a topic or service name and throw if it is not valid.
RCLCPP_PUBLIC bool ok(const rclcpp::Context::SharedPtr &context=rclcpp::contexts::get_global_default_context())
Check rclcpp's status.
RCLCPP_PUBLIC Logger get_logger(const std::string &name)
Return a named logger.
Definition: logger.cpp:32
RCL_PUBLIC RCL_WARN_UNUSED const rcl_node_options_t * rcl_node_get_options(const rcl_node_t *node)
Return the rcl node options.
Definition: node.c:443
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_name(const rcl_node_t *node)
Return the name of the node.
Definition: node.c:416
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_namespace(const rcl_node_t *node)
Return the namespace of the node.
Definition: node.c:425
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.
Definition: node.c:484
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_remap_service_name(const rcl_arguments_t *local_arguments, const rcl_arguments_t *global_arguments, const char *service_name, const char *node_name, const char *node_namespace, rcl_allocator_t allocator, char **output_name)
Remap a service name based on given rules.
Definition: remap.c:263
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_remap_topic_name(const rcl_arguments_t *local_arguments, const rcl_arguments_t *global_arguments, const char *topic_name, const char *node_name, const char *node_namespace, rcl_allocator_t allocator, char **output_name)
Remap a topic name based on given rules.
Definition: remap.c:233
Hold output of parsing command line arguments.
Definition: arguments.h:36
Handle for a rcl guard condition.
Structure which encapsulates the options for creating a rcl_node_t.
Definition: node_options.h:35
bool use_global_arguments
If false then only use arguments in this struct, otherwise use global arguments also.
Definition: node_options.h:47
rcl_arguments_t arguments
Command line arguments that apply only to this node.
Definition: node_options.h:50
rcl_allocator_t allocator
If true, no parameter infrastructure will be setup.
Definition: node_options.h:44
#define RCL_RET_UNSUPPORTED
Unsupported return code.
Definition: types.h:37
#define RCL_RET_OK
Success return code.
Definition: types.h:27
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24