ROS 2 rclcpp + rcl - lyrical  lyrical
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 "rcpputils/scope_exit.hpp"
33 
35 using rclcpp::exceptions::throw_from_rcl_error;
37 
38 NodeGraph::NodeGraph(rclcpp::node_interfaces::NodeBaseInterface * node_base)
39 : node_base_(node_base),
40  should_add_to_graph_listener_(true),
41  graph_users_count_(0)
42 {}
43 
44 NodeGraph::~NodeGraph()
45 {
46  // Remove self from graph listener.
47  // Exchange with false to prevent others from trying to add this node to the
48  // graph listener after checking that it was not here.
49  if (!should_add_to_graph_listener_.exchange(false)) {
50  // If it was already false, then it needs to now be removed.
51  node_base_->get_context()->get_graph_listener()->remove_node(this);
52  }
53 }
54 
55 std::map<std::string, std::vector<std::string>>
56 NodeGraph::get_topic_names_and_types(bool no_demangle) const
57 {
59 
62  node_base_->get_rcl_node_handle(),
63  &allocator,
64  no_demangle,
65  &topic_names_and_types);
66  if (ret != RCL_RET_OK) {
67  auto error_msg = std::string("failed to get topic names and types: ") +
68  rcl_get_error_string().str;
69  rcl_reset_error();
70  if (rcl_names_and_types_fini(&topic_names_and_types) != RCL_RET_OK) {
71  error_msg += std::string(", failed also to cleanup topic names and types, leaking memory: ") +
72  rcl_get_error_string().str;
73  rcl_reset_error();
74  }
75  throw std::runtime_error(error_msg);
76  }
77 
78  std::map<std::string, std::vector<std::string>> topics_and_types;
79  for (size_t i = 0; i < topic_names_and_types.names.size; ++i) {
80  std::string topic_name = topic_names_and_types.names.data[i];
81  for (size_t j = 0; j < topic_names_and_types.types[i].size; ++j) {
82  topics_and_types[topic_name].emplace_back(topic_names_and_types.types[i].data[j]);
83  }
84  }
85 
86  ret = rcl_names_and_types_fini(&topic_names_and_types);
87  if (ret != RCL_RET_OK) {
88  // *INDENT-OFF*
89  throw std::runtime_error(
90  std::string("could not destroy topic names and types: ") + rcl_get_error_string().str);
91  // *INDENT-ON*
92  }
93 
94  return topics_and_types;
95 }
96 
97 std::map<std::string, std::vector<std::string>>
99 {
101 
104  node_base_->get_rcl_node_handle(),
105  &allocator,
106  &service_names_and_types);
107  if (ret != RCL_RET_OK) {
108  auto error_msg = std::string("failed to get service names and types: ") +
109  rcl_get_error_string().str;
110  rcl_reset_error();
111  if (rcl_names_and_types_fini(&service_names_and_types) != RCL_RET_OK) {
112  error_msg +=
113  std::string(", failed also to cleanup service names and types, leaking memory: ") +
114  rcl_get_error_string().str;
115  rcl_reset_error();
116  }
117  throw std::runtime_error(error_msg);
118  }
119 
120  std::map<std::string, std::vector<std::string>> services_and_types;
121  for (size_t i = 0; i < service_names_and_types.names.size; ++i) {
122  std::string service_name = service_names_and_types.names.data[i];
123  for (size_t j = 0; j < service_names_and_types.types[i].size; ++j) {
124  services_and_types[service_name].emplace_back(service_names_and_types.types[i].data[j]);
125  }
126  }
127 
128  ret = rcl_names_and_types_fini(&service_names_and_types);
129  if (ret != RCL_RET_OK) {
130  // *INDENT-OFF*
131  throw std::runtime_error(
132  std::string("could not destroy service names and types: ") + rcl_get_error_string().str);
133  // *INDENT-ON*
134  }
135 
136  return services_and_types;
137 }
138 
139 std::map<std::string, std::vector<std::string>>
141  const std::string & node_name,
142  const std::string & namespace_) const
143 {
147  node_base_->get_rcl_node_handle(),
148  &allocator,
149  node_name.c_str(),
150  namespace_.c_str(),
151  &service_names_and_types);
152  if (ret != RCL_RET_OK) {
153  auto error_msg = std::string("failed to get service names and types by node: ") +
154  rcl_get_error_string().str;
155  rcl_reset_error();
156  if (rcl_names_and_types_fini(&service_names_and_types) != RCL_RET_OK) {
157  error_msg +=
158  std::string(", failed also to cleanup service names and types, leaking memory: ") +
159  rcl_get_error_string().str;
160  rcl_reset_error();
161  }
162  throw std::runtime_error(error_msg);
163  }
164 
165  std::map<std::string, std::vector<std::string>> services_and_types;
166  for (size_t i = 0; i < service_names_and_types.names.size; ++i) {
167  std::string service_name = service_names_and_types.names.data[i];
168  for (size_t j = 0; j < service_names_and_types.types[i].size; ++j) {
169  services_and_types[service_name].emplace_back(service_names_and_types.types[i].data[j]);
170  }
171  }
172 
173  ret = rcl_names_and_types_fini(&service_names_and_types);
174  if (ret != RCL_RET_OK) {
175  throw_from_rcl_error(ret, "could not destroy service names and types");
176  }
177 
178  return services_and_types;
179 }
180 
181 std::map<std::string, std::vector<std::string>>
183  const std::string & node_name,
184  const std::string & namespace_) const
185 {
187  auto service_names_and_types_finalizer = rcpputils::make_scope_exit(
188  [&service_names_and_types]() {
189  if (rcl_names_and_types_fini(&service_names_and_types) != RCL_RET_OK) {
190  RCLCPP_ERROR(
191  rclcpp::get_logger("rclcpp"), "could not destroy service names and types");
192  }
193  });
196  node_base_->get_rcl_node_handle(),
197  &allocator,
198  node_name.c_str(),
199  namespace_.c_str(),
200  &service_names_and_types);
201  if (ret != RCL_RET_OK) {
202  throw_from_rcl_error(ret, "failed to get service names and types by node");
203  }
204 
205  std::map<std::string, std::vector<std::string>> services_and_types;
206  for (size_t i = 0; i < service_names_and_types.names.size; ++i) {
207  std::string service_name = service_names_and_types.names.data[i];
208  for (size_t j = 0; j < service_names_and_types.types[i].size; ++j) {
209  services_and_types[service_name].emplace_back(service_names_and_types.types[i].data[j]);
210  }
211  }
212 
213  return services_and_types;
214 }
215 
216 std::map<std::string, std::vector<std::string>>
218  const std::string & node_name,
219  const std::string & namespace_,
220  bool no_demangle) const
221 {
223  auto topic_names_and_types_finalizer = rcpputils::make_scope_exit(
224  [&topic_names_and_types]() {
225  if (rcl_names_and_types_fini(&topic_names_and_types) != RCL_RET_OK) {
226  RCLCPP_ERROR(
227  rclcpp::get_logger("rclcpp"), "could not destroy topic names and types");
228  }
229  });
232  node_base_->get_rcl_node_handle(),
233  &allocator,
234  no_demangle,
235  node_name.c_str(),
236  namespace_.c_str(),
237  &topic_names_and_types);
238  if (ret != RCL_RET_OK) {
239  throw_from_rcl_error(ret, "failed to get topic names and types by node");
240  }
241 
242  std::map<std::string, std::vector<std::string>> topics_and_types;
243  for (size_t i = 0; i < topic_names_and_types.names.size; ++i) {
244  std::string topic_name = topic_names_and_types.names.data[i];
245  for (size_t j = 0; j < topic_names_and_types.types[i].size; ++j) {
246  topics_and_types[topic_name].emplace_back(topic_names_and_types.types[i].data[j]);
247  }
248  }
249 
250  return topics_and_types;
251 }
252 
253 std::map<std::string, std::vector<std::string>>
255  const std::string & node_name,
256  const std::string & namespace_,
257  bool no_demangle) const
258 {
260  auto topic_names_and_types_finalizer = rcpputils::make_scope_exit(
261  [&topic_names_and_types]() {
262  if (rcl_names_and_types_fini(&topic_names_and_types) != RCL_RET_OK) {
263  RCLCPP_ERROR(
264  rclcpp::get_logger("rclcpp"), "could not destroy topic names and types");
265  }
266  });
269  node_base_->get_rcl_node_handle(),
270  &allocator,
271  no_demangle,
272  node_name.c_str(),
273  namespace_.c_str(),
274  &topic_names_and_types);
275  if (ret != RCL_RET_OK) {
276  throw_from_rcl_error(ret, "failed to get topic names and types by node");
277  }
278 
279  std::map<std::string, std::vector<std::string>> topics_and_types;
280  for (size_t i = 0; i < topic_names_and_types.names.size; ++i) {
281  std::string topic_name = topic_names_and_types.names.data[i];
282  for (size_t j = 0; j < topic_names_and_types.types[i].size; ++j) {
283  topics_and_types[topic_name].emplace_back(topic_names_and_types.types[i].data[j]);
284  }
285  }
286 
287  return topics_and_types;
288 }
289 
290 std::vector<std::string>
292 {
293  std::vector<std::string> nodes;
294  auto names_and_namespaces = get_node_names_and_namespaces();
295 
296  std::transform(
297  names_and_namespaces.begin(),
298  names_and_namespaces.end(),
299  std::back_inserter(nodes),
300  [](std::pair<std::string, std::string> nns) {
301  std::string return_string;
302  if (nns.second.back() == '/') {
303  return_string = nns.second + nns.first;
304  } else {
305  return_string = nns.second + '/' + nns.first;
306  }
307  // Quick check to make sure that we start with a slash
308  // Since fully-qualified strings need to
309  if (return_string.front() != '/') {
310  return_string = "/" + return_string;
311  }
312  return return_string;
313  }
314  );
315  return nodes;
316 }
317 
318 std::vector<std::tuple<std::string, std::string, std::string>>
320 {
321  rcutils_string_array_t node_names_c =
322  rcutils_get_zero_initialized_string_array();
323  rcutils_string_array_t node_namespaces_c =
324  rcutils_get_zero_initialized_string_array();
325  rcutils_string_array_t node_enclaves_c =
326  rcutils_get_zero_initialized_string_array();
327 
328  auto allocator = rcl_get_default_allocator();
330  node_base_->get_rcl_node_handle(),
331  allocator,
332  &node_names_c,
333  &node_namespaces_c,
334  &node_enclaves_c);
335  if (ret != RCL_RET_OK) {
336  auto error_msg =
337  std::string("failed to get node names with enclaves: ") + rcl_get_error_string().str;
338  rcl_reset_error();
339  if (rcutils_string_array_fini(&node_names_c) != RCUTILS_RET_OK) {
340  error_msg += std::string(", failed also to cleanup node names, leaking memory: ") +
341  rcl_get_error_string().str;
342  rcl_reset_error();
343  }
344  if (rcutils_string_array_fini(&node_namespaces_c) != RCUTILS_RET_OK) {
345  error_msg += std::string(", failed also to cleanup node namespaces, leaking memory: ") +
346  rcl_get_error_string().str;
347  rcl_reset_error();
348  }
349  if (rcutils_string_array_fini(&node_enclaves_c) != RCUTILS_RET_OK) {
350  error_msg += std::string(", failed also to cleanup node enclaves, leaking memory: ") +
351  rcl_get_error_string().str;
352  rcl_reset_error();
353  }
354  throw std::runtime_error(error_msg);
355  }
356 
357  std::vector<std::tuple<std::string, std::string, std::string>> node_tuples;
358  for (size_t i = 0; i < node_names_c.size; ++i) {
359  if (node_names_c.data[i] && node_namespaces_c.data[i] && node_enclaves_c.data[i]) {
360  node_tuples.emplace_back(
361  std::make_tuple(node_names_c.data[i], node_namespaces_c.data[i], node_enclaves_c.data[i]));
362  }
363  }
364 
365  std::string error("failed to finalize array");
366  rcl_ret_t ret_names = rcutils_string_array_fini(&node_names_c);
367  if (ret_names != RCUTILS_RET_OK) {
368  error += std::string(", could not destroy node names, leaking memory: ") +
369  rcl_get_error_string().str;
370  rcl_reset_error();
371  }
372  rcl_ret_t ret_ns = rcutils_string_array_fini(&node_namespaces_c);
373  if (ret_ns != RCUTILS_RET_OK) {
374  error += std::string(", could not destroy node namespaces, leaking memory: ") +
375  rcl_get_error_string().str;
376  rcl_reset_error();
377  }
378 
379  rcl_ret_t ret_ecv = rcutils_string_array_fini(&node_enclaves_c);
380  if (ret_ecv != RCUTILS_RET_OK) {
381  error += std::string(", could not destroy node enclaves, leaking memory: ") +
382  rcl_get_error_string().str;
383  rcl_reset_error();
384  }
385 
386  if (ret_names != RCUTILS_RET_OK || ret_ns != RCUTILS_RET_OK || ret_ecv != RCUTILS_RET_OK) {
387  throw std::runtime_error(error);
388  }
389 
390  return node_tuples;
391 }
392 
393 std::vector<std::pair<std::string, std::string>>
395 {
396  rcutils_string_array_t node_names_c =
397  rcutils_get_zero_initialized_string_array();
398  rcutils_string_array_t node_namespaces_c =
399  rcutils_get_zero_initialized_string_array();
400 
401  auto allocator = rcl_get_default_allocator();
402  auto ret = rcl_get_node_names(
403  node_base_->get_rcl_node_handle(),
404  allocator,
405  &node_names_c,
406  &node_namespaces_c);
407  if (ret != RCL_RET_OK) {
408  auto error_msg = std::string("failed to get node names: ") + rcl_get_error_string().str;
409  rcl_reset_error();
410  if (rcutils_string_array_fini(&node_names_c) != RCUTILS_RET_OK) {
411  error_msg += std::string(", failed also to cleanup node names, leaking memory: ") +
412  rcl_get_error_string().str;
413  rcl_reset_error();
414  }
415  if (rcutils_string_array_fini(&node_namespaces_c) != RCUTILS_RET_OK) {
416  error_msg += std::string(", failed also to cleanup node namespaces, leaking memory: ") +
417  rcl_get_error_string().str;
418  rcl_reset_error();
419  }
420  RCUTILS_LOG_ERROR_NAMED("rclcpp", "%s", error_msg.c_str());
421  throw std::runtime_error(error_msg);
422  }
423 
424  std::vector<std::pair<std::string, std::string>> node_names;
425  node_names.reserve(node_names_c.size);
426  for (size_t i = 0; i < node_names_c.size; ++i) {
427  if (node_names_c.data[i] && node_namespaces_c.data[i]) {
428  node_names.emplace_back(node_names_c.data[i], node_namespaces_c.data[i]);
429  }
430  }
431 
432  std::string error;
433  rcl_ret_t ret_names = rcutils_string_array_fini(&node_names_c);
434  if (ret_names != RCUTILS_RET_OK) {
435  error = std::string("could not destroy node names: ") + rcl_get_error_string().str;
436  }
437  rcl_ret_t ret_ns = rcutils_string_array_fini(&node_namespaces_c);
438  if (ret_ns != RCUTILS_RET_OK) {
439  error += std::string(", could not destroy node namespaces: ") + rcl_get_error_string().str;
440  }
441 
442  if (ret_names != RCUTILS_RET_OK || ret_ns != RCUTILS_RET_OK) {
443  RCUTILS_LOG_ERROR_NAMED("rclcpp", "%s", error.c_str());
444  throw std::runtime_error(error);
445  }
446 
447  return node_names;
448 }
449 
450 size_t
451 NodeGraph::count_publishers(const std::string & topic_name) const
452 {
453  auto rcl_node_handle = node_base_->get_rcl_node_handle();
454 
456  topic_name,
457  rcl_node_get_name(rcl_node_handle),
458  rcl_node_get_namespace(rcl_node_handle),
459  false); // false = not a service
460 
461  size_t count;
462  auto ret = rcl_count_publishers(rcl_node_handle, fqdn.c_str(), &count);
463  if (ret != RMW_RET_OK) {
464  // *INDENT-OFF*
465  throw std::runtime_error(
466  std::string("could not count publishers: ") + rmw_get_error_string().str);
467  // *INDENT-ON*
468  }
469  return count;
470 }
471 
472 size_t
473 NodeGraph::count_subscribers(const std::string & topic_name) const
474 {
475  auto rcl_node_handle = node_base_->get_rcl_node_handle();
476 
478  topic_name,
479  rcl_node_get_name(rcl_node_handle),
480  rcl_node_get_namespace(rcl_node_handle),
481  false); // false = not a service
482 
483  size_t count;
484  auto ret = rcl_count_subscribers(rcl_node_handle, fqdn.c_str(), &count);
485  if (ret != RMW_RET_OK) {
486  // *INDENT-OFF*
487  throw std::runtime_error(
488  std::string("could not count subscribers: ") + rmw_get_error_string().str);
489  // *INDENT-ON*
490  }
491  return count;
492 }
493 
494 size_t
495 NodeGraph::count_clients(const std::string & service_name) const
496 {
497  auto rcl_node_handle = node_base_->get_rcl_node_handle();
498 
500  service_name,
501  rcl_node_get_name(rcl_node_handle),
502  rcl_node_get_namespace(rcl_node_handle),
503  true);
504 
505  size_t count;
506  auto ret = rcl_count_clients(rcl_node_handle, fqdn.c_str(), &count);
507  if (ret != RMW_RET_OK) {
508  // *INDENT-OFF*
509  throw std::runtime_error(
510  std::string("could not count clients: ") + rmw_get_error_string().str);
511  // *INDENT-ON*
512  }
513  return count;
514 }
515 
516 size_t
517 NodeGraph::count_services(const std::string & service_name) const
518 {
519  auto rcl_node_handle = node_base_->get_rcl_node_handle();
520 
522  service_name,
523  rcl_node_get_name(rcl_node_handle),
524  rcl_node_get_namespace(rcl_node_handle),
525  true);
526 
527  size_t count;
528  auto ret = rcl_count_services(rcl_node_handle, fqdn.c_str(), &count);
529  if (ret != RMW_RET_OK) {
530  // *INDENT-OFF*
531  throw std::runtime_error(
532  std::string("could not count services: ") + rmw_get_error_string().str);
533  // *INDENT-ON*
534  }
535  return count;
536 }
537 
538 const rcl_guard_condition_t *
540 {
542 }
543 
544 void
546 {
547  {
548  std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
549  bool bad_ptr_encountered = false;
550  for (auto & event_wptr : graph_events_) {
551  auto event_ptr = event_wptr.lock();
552  if (event_ptr) {
553  event_ptr->set();
554  } else {
555  bad_ptr_encountered = true;
556  }
557  }
558  if (bad_ptr_encountered) {
559  // remove invalid pointers with the erase-remove idiom
560  graph_events_.erase(
561  std::remove_if(
562  graph_events_.begin(),
563  graph_events_.end(),
564  [](const rclcpp::Event::WeakPtr & wptr) {
565  return wptr.expired();
566  }),
567  graph_events_.end());
568  // update graph_users_count_
569  graph_users_count_.store(graph_events_.size());
570  }
571  }
572  graph_cv_.notify_all();
573  try {
574  node_base_->trigger_notify_guard_condition();
575  } catch (const rclcpp::exceptions::RCLError & ex) {
576  throw std::runtime_error(
577  std::string("failed to notify wait set on graph change: ") + ex.what());
578  }
579 }
580 
581 void
583 {
584  // notify here anything that will not be woken up by ctrl-c or rclcpp::shutdown().
585  graph_cv_.notify_all();
586 }
587 
588 rclcpp::Event::SharedPtr
590 {
591  auto event = rclcpp::Event::make_shared();
592  {
593  std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
594  graph_events_.push_back(event);
595  graph_users_count_++;
596  }
597  // on first call, add node to graph_listener_
598  if (should_add_to_graph_listener_.exchange(false)) {
599  node_base_->get_context()->get_graph_listener()->add_node(this);
600  node_base_->get_context()->get_graph_listener()->start_if_not_started();
601  }
602  return event;
603 }
604 
605 void
607  rclcpp::Event::SharedPtr event,
608  std::chrono::nanoseconds timeout)
609 {
612  if (!event) {
613  throw InvalidEventError();
614  }
615  {
616  std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
617  bool event_in_graph_events = false;
618  for (const auto & event_wptr : graph_events_) {
619  if (event == event_wptr.lock()) {
620  event_in_graph_events = true;
621  break;
622  }
623  }
624  if (!event_in_graph_events) {
625  throw EventNotRegisteredError();
626  }
627  }
628  auto pred = [&event, context = node_base_->get_context()]() {
629  return event->check() || !rclcpp::ok(context);
630  };
631  std::unique_lock<std::mutex> graph_lock(graph_mutex_);
632  if (!pred()) {
633  graph_cv_.wait_for(graph_lock, timeout, pred);
634  }
635 }
636 
637 size_t
639 {
640  return graph_users_count_.load();
641 }
642 
643 static
644 std::vector<rclcpp::TopicEndpointInfo>
645 convert_to_topic_info_list(const rcl_topic_endpoint_info_array_t & info_array)
646 {
647  std::vector<rclcpp::TopicEndpointInfo> topic_info_list;
648  topic_info_list.reserve(info_array.size);
649  for (size_t i = 0; i < info_array.size; ++i) {
650  topic_info_list.emplace_back(info_array.info_array[i]);
651  }
652  return topic_info_list;
653 }
654 
655 template<const char * EndpointType, typename FunctionT>
656 static std::vector<rclcpp::TopicEndpointInfo>
657 get_info_by_topic(
659  const std::string & topic_name,
660  bool no_mangle,
661  FunctionT rcl_get_info_by_topic)
662 {
663  std::string fqdn;
664  auto rcl_node_handle = node_base->get_rcl_node_handle();
665 
666  if (no_mangle) {
667  fqdn = topic_name;
668  } else {
670  topic_name,
671  rcl_node_get_name(rcl_node_handle),
672  rcl_node_get_namespace(rcl_node_handle),
673  false); // false = not a service
674 
675  // Get the node options
676  const rcl_node_options_t * node_options = rcl_node_get_options(rcl_node_handle);
677  if (nullptr == node_options) {
678  throw std::runtime_error("Need valid node options in get_info_by_topic()");
679  }
680  const rcl_arguments_t * global_args = nullptr;
681  if (node_options->use_global_arguments) {
682  global_args = &(rcl_node_handle->context->global_arguments);
683  }
684 
685  char * remapped_topic_name = nullptr;
687  &(node_options->arguments),
688  global_args,
689  fqdn.c_str(),
690  rcl_node_get_name(rcl_node_handle),
691  rcl_node_get_namespace(rcl_node_handle),
692  node_options->allocator,
693  &remapped_topic_name);
694  if (RCL_RET_OK != ret) {
695  throw_from_rcl_error(ret, std::string("Failed to remap topic name ") + fqdn);
696  } else if (nullptr != remapped_topic_name) {
697  fqdn = remapped_topic_name;
698  node_options->allocator.deallocate(remapped_topic_name, node_options->allocator.state);
699  }
700  }
701 
702  rcutils_allocator_t allocator = rcutils_get_default_allocator();
704  rcl_ret_t ret =
705  rcl_get_info_by_topic(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
706  if (RCL_RET_OK != ret) {
707  auto error_msg =
708  std::string("Failed to get information by topic for ") + EndpointType + std::string(":");
709  if (RCL_RET_UNSUPPORTED == ret) {
710  error_msg += std::string("function not supported by RMW_IMPLEMENTATION");
711  } else {
712  error_msg += rcl_get_error_string().str;
713  }
714  rcl_reset_error();
715  if (RCL_RET_OK != rcl_topic_endpoint_info_array_fini(&info_array, &allocator)) {
716  error_msg += std::string(", failed also to cleanup topic info array, leaking memory: ") +
717  rcl_get_error_string().str;
718  rcl_reset_error();
719  }
720  throw_from_rcl_error(ret, error_msg);
721  }
722 
723  std::vector<rclcpp::TopicEndpointInfo> topic_info_list = convert_to_topic_info_list(info_array);
724  ret = rcl_topic_endpoint_info_array_fini(&info_array, &allocator);
725  if (RCL_RET_OK != ret) {
726  throw_from_rcl_error(ret, "rcl_topic_info_array_fini failed.");
727  }
728 
729  return topic_info_list;
730 }
731 
732 static constexpr char kPublisherEndpointTypeName[] = "publishers";
733 std::vector<rclcpp::TopicEndpointInfo>
735  const std::string & topic_name,
736  bool no_mangle) const
737 {
738  return get_info_by_topic<kPublisherEndpointTypeName>(
739  node_base_,
740  topic_name,
741  no_mangle,
743 }
744 
745 static constexpr char kSubscriptionEndpointTypeName[] = "subscriptions";
746 std::vector<rclcpp::TopicEndpointInfo>
748  const std::string & topic_name,
749  bool no_mangle) const
750 {
751  return get_info_by_topic<kSubscriptionEndpointTypeName>(
752  node_base_,
753  topic_name,
754  no_mangle,
756 }
757 
758 static
759 std::vector<rclcpp::ServiceEndpointInfo>
760 convert_to_service_info_list(const rcl_service_endpoint_info_array_t & info_array)
761 {
762  std::vector<rclcpp::ServiceEndpointInfo> service_info_list;
763  service_info_list.reserve(info_array.size);
764  for (size_t i = 0; i < info_array.size; ++i) {
765  service_info_list.emplace_back(info_array.info_array[i]);
766  }
767  return service_info_list;
768 }
769 
770 template<const char * EndpointType, typename FunctionT>
771 static std::vector<rclcpp::ServiceEndpointInfo>
772 get_info_by_service(
774  const std::string & service_name,
775  bool no_mangle,
776  FunctionT rcl_get_info_by_service)
777 {
778  std::string fqdn;
779  auto rcl_node_handle = node_base->get_rcl_node_handle();
780 
781  if (no_mangle) {
782  fqdn = service_name;
783  } else {
785  service_name,
786  rcl_node_get_name(rcl_node_handle),
787  rcl_node_get_namespace(rcl_node_handle),
788  true);
789 
790  // Get the node options
791  const rcl_node_options_t * node_options = rcl_node_get_options(rcl_node_handle);
792  if (nullptr == node_options) {
793  throw std::runtime_error("Need valid node options in get_info_by_service()");
794  }
795  const rcl_arguments_t * global_args = nullptr;
796  if (node_options->use_global_arguments) {
797  global_args = &(rcl_node_handle->context->global_arguments);
798  }
799 
800  char * remapped_service_name = nullptr;
802  &(node_options->arguments),
803  global_args,
804  fqdn.c_str(),
805  rcl_node_get_name(rcl_node_handle),
806  rcl_node_get_namespace(rcl_node_handle),
807  node_options->allocator,
808  &remapped_service_name);
809  if (RCL_RET_OK != ret) {
810  throw_from_rcl_error(ret, std::string("Failed to remap service name ") + fqdn);
811  } else if (nullptr != remapped_service_name) {
812  fqdn = remapped_service_name;
813  node_options->allocator.deallocate(remapped_service_name, node_options->allocator.state);
814  }
815  }
816 
817  rcutils_allocator_t allocator = rcutils_get_default_allocator();
818  rcl_service_endpoint_info_array_t info_array =
820  rcl_ret_t ret =
821  rcl_get_info_by_service(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
822  if (RCL_RET_OK != ret) {
823  auto error_msg =
824  std::string("Failed to get information by service for ") + EndpointType + std::string(":");
825  if (RCL_RET_UNSUPPORTED == ret) {
826  error_msg += std::string("function not supported by RMW_IMPLEMENTATION");
827  } else {
828  error_msg += rcl_get_error_string().str;
829  }
830  rcl_reset_error();
831  if (RCL_RET_OK != rcl_service_endpoint_info_array_fini(&info_array, &allocator)) {
832  error_msg += std::string(", failed also to cleanup service info array, leaking memory: ") +
833  rcl_get_error_string().str;
834  rcl_reset_error();
835  }
836  throw_from_rcl_error(ret, error_msg);
837  }
838 
839  std::vector<rclcpp::ServiceEndpointInfo> service_info_list =
840  convert_to_service_info_list(info_array);
841  ret = rcl_service_endpoint_info_array_fini(&info_array, &allocator);
842  if (RCL_RET_OK != ret) {
843  throw_from_rcl_error(ret, "rcl_service_info_array_fini failed.");
844  }
845 
846  return service_info_list;
847 }
848 
849 static constexpr char kClientEndpointTypeName[] = "clients";
850 std::vector<rclcpp::ServiceEndpointInfo>
852  const std::string & service_name,
853  bool no_mangle) const
854 {
855  return get_info_by_service<kClientEndpointTypeName>(
856  node_base_,
857  service_name,
858  no_mangle,
860 }
861 
862 static constexpr char kServerEndpointTypeName[] = "servers";
863 std::vector<rclcpp::ServiceEndpointInfo>
865  const std::string & service_name,
866  bool no_mangle) const
867 {
868  return get_info_by_service<kServerEndpointTypeName>(
869  node_base_,
870  service_name,
871  no_mangle,
873 }
874 
875 std::string &
877 {
878  return node_name_;
879 }
880 
881 const std::string &
883 {
884  return node_name_;
885 }
886 
887 std::string &
889 {
890  return node_namespace_;
891 }
892 
893 const std::string &
895 {
896  return node_namespace_;
897 }
898 
899 std::string &
901 {
902  return topic_type_;
903 }
904 
905 const std::string &
907 {
908  return topic_type_;
909 }
910 
911 rclcpp::EndpointType &
913 {
914  return endpoint_type_;
915 }
916 
917 const rclcpp::EndpointType &
919 {
920  return endpoint_type_;
921 }
922 
923 std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
925 {
926  return endpoint_gid_;
927 }
928 
929 const std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
931 {
932  return endpoint_gid_;
933 }
934 
935 rclcpp::QoS &
937 {
938  return qos_profile_;
939 }
940 
941 const rclcpp::QoS &
943 {
944  return qos_profile_;
945 }
946 
947 rosidl_type_hash_t &
949 {
950  return topic_type_hash_;
951 }
952 
953 const rosidl_type_hash_t &
955 {
956  return topic_type_hash_;
957 }
958 
959 std::string &
961 {
962  return node_name_;
963 }
964 
965 const std::string &
967 {
968  return node_name_;
969 }
970 
971 std::string &
973 {
974  return node_namespace_;
975 }
976 
977 const std::string &
979 {
980  return node_namespace_;
981 }
982 
983 std::string &
985 {
986  return service_type_;
987 }
988 
989 const std::string &
991 {
992  return service_type_;
993 }
994 
995 rclcpp::EndpointType &
997 {
998  return endpoint_type_;
999 }
1000 
1001 const rclcpp::EndpointType &
1003 {
1004  return endpoint_type_;
1005 }
1006 
1007 size_t &
1009 {
1010  return endpoint_count_;
1011 }
1012 
1013 const size_t &
1015 {
1016  return endpoint_count_;
1017 }
1018 
1019 std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
1021 {
1022  return endpoint_gids_;
1023 }
1024 
1025 const std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
1027 {
1028  return endpoint_gids_;
1029 }
1030 
1031 std::vector<rclcpp::QoS> &
1033 {
1034  return qos_profiles_;
1035 }
1036 
1037 const std::vector<rclcpp::QoS> &
1039 {
1040  return qos_profiles_;
1041 }
1042 
1043 rosidl_type_hash_t &
1045 {
1046  return service_type_hash_;
1047 }
1048 
1049 const rosidl_type_hash_t &
1051 {
1052  return service_type_hash_;
1053 }
#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:116
RCLCPP_PUBLIC rclcpp::EndpointType & endpoint_type()
Get a mutable reference to the service endpoint type.
Definition: node_graph.cpp:996
RCLCPP_PUBLIC std::string & node_name()
Get a mutable reference to the node name.
Definition: node_graph.cpp:960
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:972
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:984
RCLCPP_PUBLIC std::string & node_name()
Get a mutable reference to the node name.
Definition: node_graph.cpp:876
RCLCPP_PUBLIC std::string & node_namespace()
Get a mutable reference to the node namespace.
Definition: node_graph.cpp:888
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:948
RCLCPP_PUBLIC std::string & topic_type()
Get a mutable reference to the topic type string.
Definition: node_graph.cpp:900
RCLCPP_PUBLIC rclcpp::QoS & qos_profile()
Get a mutable reference to the QoS profile of the topic endpoint.
Definition: node_graph.cpp:936
RCLCPP_PUBLIC rclcpp::EndpointType & endpoint_type()
Get a mutable reference to the topic endpoint type.
Definition: node_graph.cpp:912
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:924
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:291
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:98
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:217
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:734
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:394
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:517
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:254
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:473
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:182
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:747
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:638
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:56
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:606
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:140
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:589
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:851
RCLCPP_PUBLIC void notify_shutdown() override
Notify any and all blocking node actions that shutdown has occurred.
Definition: node_graph.cpp:582
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:319
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:451
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:495
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:864
RCLCPP_PUBLIC void notify_graph_change() override
Notify threads waiting on graph changes.
Definition: node_graph.cpp:545
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:539
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:34
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