ROS 2 rclcpp + rcl - rolling  rolling-4d14414d
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 <map>
19 #include <string>
20 #include <tuple>
21 #include <utility>
22 #include <vector>
23 
24 #include "rcl/graph.h"
25 #include "rcl/remap.h"
26 #include "rclcpp/event.hpp"
27 #include "rclcpp/exceptions.hpp"
28 #include "rclcpp/expand_topic_or_service_name.hpp"
29 #include "rclcpp/graph_listener.hpp"
30 #include "rclcpp/node_interfaces/node_graph_interface.hpp"
31 #include "rcpputils/scope_exit.hpp"
32 
34 using rclcpp::exceptions::throw_from_rcl_error;
36 
37 NodeGraph::NodeGraph(rclcpp::node_interfaces::NodeBaseInterface * node_base)
38 : node_base_(node_base),
39  should_add_to_graph_listener_(true),
40  graph_users_count_(0)
41 {}
42 
43 NodeGraph::~NodeGraph()
44 {
45  // Remove self from graph listener.
46  // Exchange with false to prevent others from trying to add this node to the
47  // graph listener after checking that it was not here.
48  if (!should_add_to_graph_listener_.exchange(false)) {
49  // If it was already false, then it needs to now be removed.
50  node_base_->get_context()->get_graph_listener()->remove_node(this);
51  }
52 }
53 
54 std::map<std::string, std::vector<std::string>>
55 NodeGraph::get_topic_names_and_types(bool no_demangle) const
56 {
58 
61  node_base_->get_rcl_node_handle(),
62  &allocator,
63  no_demangle,
64  &topic_names_and_types);
65  if (ret != RCL_RET_OK) {
66  auto error_msg = std::string("failed to get topic names and types: ") +
67  rcl_get_error_string().str;
68  rcl_reset_error();
69  if (rcl_names_and_types_fini(&topic_names_and_types) != RCL_RET_OK) {
70  error_msg += std::string(", failed also to cleanup topic names and types, leaking memory: ") +
71  rcl_get_error_string().str;
72  rcl_reset_error();
73  }
74  throw std::runtime_error(error_msg);
75  }
76 
77  std::map<std::string, std::vector<std::string>> topics_and_types;
78  for (size_t i = 0; i < topic_names_and_types.names.size; ++i) {
79  std::string topic_name = topic_names_and_types.names.data[i];
80  for (size_t j = 0; j < topic_names_and_types.types[i].size; ++j) {
81  topics_and_types[topic_name].emplace_back(topic_names_and_types.types[i].data[j]);
82  }
83  }
84 
85  ret = rcl_names_and_types_fini(&topic_names_and_types);
86  if (ret != RCL_RET_OK) {
87  // *INDENT-OFF*
88  throw std::runtime_error(
89  std::string("could not destroy topic names and types: ") + rcl_get_error_string().str);
90  // *INDENT-ON*
91  }
92 
93  return topics_and_types;
94 }
95 
96 std::map<std::string, std::vector<std::string>>
98 {
100 
103  node_base_->get_rcl_node_handle(),
104  &allocator,
105  &service_names_and_types);
106  if (ret != RCL_RET_OK) {
107  auto error_msg = std::string("failed to get service names and types: ") +
108  rcl_get_error_string().str;
109  rcl_reset_error();
110  if (rcl_names_and_types_fini(&service_names_and_types) != RCL_RET_OK) {
111  error_msg +=
112  std::string(", failed also to cleanup service names and types, leaking memory: ") +
113  rcl_get_error_string().str;
114  rcl_reset_error();
115  }
116  throw std::runtime_error(error_msg);
117  }
118 
119  std::map<std::string, std::vector<std::string>> services_and_types;
120  for (size_t i = 0; i < service_names_and_types.names.size; ++i) {
121  std::string service_name = service_names_and_types.names.data[i];
122  for (size_t j = 0; j < service_names_and_types.types[i].size; ++j) {
123  services_and_types[service_name].emplace_back(service_names_and_types.types[i].data[j]);
124  }
125  }
126 
127  ret = rcl_names_and_types_fini(&service_names_and_types);
128  if (ret != RCL_RET_OK) {
129  // *INDENT-OFF*
130  throw std::runtime_error(
131  std::string("could not destroy service names and types: ") + rcl_get_error_string().str);
132  // *INDENT-ON*
133  }
134 
135  return services_and_types;
136 }
137 
138 std::map<std::string, std::vector<std::string>>
140  const std::string & node_name,
141  const std::string & namespace_) const
142 {
146  node_base_->get_rcl_node_handle(),
147  &allocator,
148  node_name.c_str(),
149  namespace_.c_str(),
150  &service_names_and_types);
151  if (ret != RCL_RET_OK) {
152  auto error_msg = std::string("failed to get service names and types by node: ") +
153  rcl_get_error_string().str;
154  rcl_reset_error();
155  if (rcl_names_and_types_fini(&service_names_and_types) != RCL_RET_OK) {
156  error_msg +=
157  std::string(", failed also to cleanup service names and types, leaking memory: ") +
158  rcl_get_error_string().str;
159  rcl_reset_error();
160  }
161  throw std::runtime_error(error_msg);
162  }
163 
164  std::map<std::string, std::vector<std::string>> services_and_types;
165  for (size_t i = 0; i < service_names_and_types.names.size; ++i) {
166  std::string service_name = service_names_and_types.names.data[i];
167  for (size_t j = 0; j < service_names_and_types.types[i].size; ++j) {
168  services_and_types[service_name].emplace_back(service_names_and_types.types[i].data[j]);
169  }
170  }
171 
172  ret = rcl_names_and_types_fini(&service_names_and_types);
173  if (ret != RCL_RET_OK) {
174  throw_from_rcl_error(ret, "could not destroy service names and types");
175  }
176 
177  return services_and_types;
178 }
179 
180 std::map<std::string, std::vector<std::string>>
182  const std::string & node_name,
183  const std::string & namespace_) const
184 {
186  auto service_names_and_types_finalizer = rcpputils::make_scope_exit(
187  [&service_names_and_types]() {
188  if (rcl_names_and_types_fini(&service_names_and_types) != RCL_RET_OK) {
189  RCLCPP_ERROR(
190  rclcpp::get_logger("rclcpp"), "could not destroy service names and types");
191  }
192  });
195  node_base_->get_rcl_node_handle(),
196  &allocator,
197  node_name.c_str(),
198  namespace_.c_str(),
199  &service_names_and_types);
200  if (ret != RCL_RET_OK) {
201  throw_from_rcl_error(ret, "failed to get service names and types by node");
202  }
203 
204  std::map<std::string, std::vector<std::string>> services_and_types;
205  for (size_t i = 0; i < service_names_and_types.names.size; ++i) {
206  std::string service_name = service_names_and_types.names.data[i];
207  for (size_t j = 0; j < service_names_and_types.types[i].size; ++j) {
208  services_and_types[service_name].emplace_back(service_names_and_types.types[i].data[j]);
209  }
210  }
211 
212  return services_and_types;
213 }
214 
215 std::map<std::string, std::vector<std::string>>
217  const std::string & node_name,
218  const std::string & namespace_,
219  bool no_demangle) const
220 {
222  auto topic_names_and_types_finalizer = rcpputils::make_scope_exit(
223  [&topic_names_and_types]() {
224  if (rcl_names_and_types_fini(&topic_names_and_types) != RCL_RET_OK) {
225  RCLCPP_ERROR(
226  rclcpp::get_logger("rclcpp"), "could not destroy topic names and types");
227  }
228  });
231  node_base_->get_rcl_node_handle(),
232  &allocator,
233  no_demangle,
234  node_name.c_str(),
235  namespace_.c_str(),
236  &topic_names_and_types);
237  if (ret != RCL_RET_OK) {
238  throw_from_rcl_error(ret, "failed to get topic names and types by node");
239  }
240 
241  std::map<std::string, std::vector<std::string>> topics_and_types;
242  for (size_t i = 0; i < topic_names_and_types.names.size; ++i) {
243  std::string topic_name = topic_names_and_types.names.data[i];
244  for (size_t j = 0; j < topic_names_and_types.types[i].size; ++j) {
245  topics_and_types[topic_name].emplace_back(topic_names_and_types.types[i].data[j]);
246  }
247  }
248 
249  return topics_and_types;
250 }
251 
252 std::map<std::string, std::vector<std::string>>
254  const std::string & node_name,
255  const std::string & namespace_,
256  bool no_demangle) const
257 {
259  auto topic_names_and_types_finalizer = rcpputils::make_scope_exit(
260  [&topic_names_and_types]() {
261  if (rcl_names_and_types_fini(&topic_names_and_types) != RCL_RET_OK) {
262  RCLCPP_ERROR(
263  rclcpp::get_logger("rclcpp"), "could not destroy topic names and types");
264  }
265  });
268  node_base_->get_rcl_node_handle(),
269  &allocator,
270  no_demangle,
271  node_name.c_str(),
272  namespace_.c_str(),
273  &topic_names_and_types);
274  if (ret != RCL_RET_OK) {
275  throw_from_rcl_error(ret, "failed to get topic names and types by node");
276  }
277 
278  std::map<std::string, std::vector<std::string>> topics_and_types;
279  for (size_t i = 0; i < topic_names_and_types.names.size; ++i) {
280  std::string topic_name = topic_names_and_types.names.data[i];
281  for (size_t j = 0; j < topic_names_and_types.types[i].size; ++j) {
282  topics_and_types[topic_name].emplace_back(topic_names_and_types.types[i].data[j]);
283  }
284  }
285 
286  return topics_and_types;
287 }
288 
289 std::vector<std::string>
291 {
292  std::vector<std::string> nodes;
293  auto names_and_namespaces = get_node_names_and_namespaces();
294 
295  std::transform(
296  names_and_namespaces.begin(),
297  names_and_namespaces.end(),
298  std::back_inserter(nodes),
299  [](std::pair<std::string, std::string> nns) {
300  std::string return_string;
301  if (nns.second.back() == '/') {
302  return_string = nns.second + nns.first;
303  } else {
304  return_string = nns.second + '/' + nns.first;
305  }
306  // Quick check to make sure that we start with a slash
307  // Since fully-qualified strings need to
308  if (return_string.front() != '/') {
309  return_string = "/" + return_string;
310  }
311  return return_string;
312  }
313  );
314  return nodes;
315 }
316 
317 std::vector<std::tuple<std::string, std::string, std::string>>
319 {
320  rcutils_string_array_t node_names_c =
321  rcutils_get_zero_initialized_string_array();
322  rcutils_string_array_t node_namespaces_c =
323  rcutils_get_zero_initialized_string_array();
324  rcutils_string_array_t node_enclaves_c =
325  rcutils_get_zero_initialized_string_array();
326 
327  auto allocator = rcl_get_default_allocator();
329  node_base_->get_rcl_node_handle(),
330  allocator,
331  &node_names_c,
332  &node_namespaces_c,
333  &node_enclaves_c);
334  if (ret != RCL_RET_OK) {
335  auto error_msg =
336  std::string("failed to get node names with enclaves: ") + rcl_get_error_string().str;
337  rcl_reset_error();
338  if (rcutils_string_array_fini(&node_names_c) != RCUTILS_RET_OK) {
339  error_msg += std::string(", failed also to cleanup node names, leaking memory: ") +
340  rcl_get_error_string().str;
341  rcl_reset_error();
342  }
343  if (rcutils_string_array_fini(&node_namespaces_c) != RCUTILS_RET_OK) {
344  error_msg += std::string(", failed also to cleanup node namespaces, leaking memory: ") +
345  rcl_get_error_string().str;
346  rcl_reset_error();
347  }
348  if (rcutils_string_array_fini(&node_enclaves_c) != RCUTILS_RET_OK) {
349  error_msg += std::string(", failed also to cleanup node enclaves, leaking memory: ") +
350  rcl_get_error_string().str;
351  rcl_reset_error();
352  }
353  throw std::runtime_error(error_msg);
354  }
355 
356  std::vector<std::tuple<std::string, std::string, std::string>> node_tuples;
357  for (size_t i = 0; i < node_names_c.size; ++i) {
358  if (node_names_c.data[i] && node_namespaces_c.data[i] && node_enclaves_c.data[i]) {
359  node_tuples.emplace_back(
360  std::make_tuple(node_names_c.data[i], node_namespaces_c.data[i], node_enclaves_c.data[i]));
361  }
362  }
363 
364  std::string error("failed to finalize array");
365  rcl_ret_t ret_names = rcutils_string_array_fini(&node_names_c);
366  if (ret_names != RCUTILS_RET_OK) {
367  error += std::string(", could not destroy node names, leaking memory: ") +
368  rcl_get_error_string().str;
369  rcl_reset_error();
370  }
371  rcl_ret_t ret_ns = rcutils_string_array_fini(&node_namespaces_c);
372  if (ret_ns != RCUTILS_RET_OK) {
373  error += std::string(", could not destroy node namespaces, leaking memory: ") +
374  rcl_get_error_string().str;
375  rcl_reset_error();
376  }
377 
378  rcl_ret_t ret_ecv = rcutils_string_array_fini(&node_enclaves_c);
379  if (ret_ecv != RCUTILS_RET_OK) {
380  error += std::string(", could not destroy node enclaves, leaking memory: ") +
381  rcl_get_error_string().str;
382  rcl_reset_error();
383  }
384 
385  if (ret_names != RCUTILS_RET_OK || ret_ns != RCUTILS_RET_OK || ret_ecv != RCUTILS_RET_OK) {
386  throw std::runtime_error(error);
387  }
388 
389  return node_tuples;
390 }
391 
392 std::vector<std::pair<std::string, std::string>>
394 {
395  rcutils_string_array_t node_names_c =
396  rcutils_get_zero_initialized_string_array();
397  rcutils_string_array_t node_namespaces_c =
398  rcutils_get_zero_initialized_string_array();
399 
400  auto allocator = rcl_get_default_allocator();
401  auto ret = rcl_get_node_names(
402  node_base_->get_rcl_node_handle(),
403  allocator,
404  &node_names_c,
405  &node_namespaces_c);
406  if (ret != RCL_RET_OK) {
407  auto error_msg = std::string("failed to get node names: ") + rcl_get_error_string().str;
408  rcl_reset_error();
409  if (rcutils_string_array_fini(&node_names_c) != RCUTILS_RET_OK) {
410  error_msg += std::string(", failed also to cleanup node names, leaking memory: ") +
411  rcl_get_error_string().str;
412  rcl_reset_error();
413  }
414  if (rcutils_string_array_fini(&node_namespaces_c) != RCUTILS_RET_OK) {
415  error_msg += std::string(", failed also to cleanup node namespaces, leaking memory: ") +
416  rcl_get_error_string().str;
417  rcl_reset_error();
418  }
419  RCUTILS_LOG_ERROR_NAMED("rclcpp", "%s", error_msg.c_str());
420  throw std::runtime_error(error_msg);
421  }
422 
423  std::vector<std::pair<std::string, std::string>> node_names;
424  node_names.reserve(node_names_c.size);
425  for (size_t i = 0; i < node_names_c.size; ++i) {
426  if (node_names_c.data[i] && node_namespaces_c.data[i]) {
427  node_names.emplace_back(node_names_c.data[i], node_namespaces_c.data[i]);
428  }
429  }
430 
431  std::string error;
432  rcl_ret_t ret_names = rcutils_string_array_fini(&node_names_c);
433  if (ret_names != RCUTILS_RET_OK) {
434  error = std::string("could not destroy node names: ") + rcl_get_error_string().str;
435  }
436  rcl_ret_t ret_ns = rcutils_string_array_fini(&node_namespaces_c);
437  if (ret_ns != RCUTILS_RET_OK) {
438  error += std::string(", could not destroy node namespaces: ") + rcl_get_error_string().str;
439  }
440 
441  if (ret_names != RCUTILS_RET_OK || ret_ns != RCUTILS_RET_OK) {
442  RCUTILS_LOG_ERROR_NAMED("rclcpp", "%s", error.c_str());
443  throw std::runtime_error(error);
444  }
445 
446  return node_names;
447 }
448 
449 size_t
450 NodeGraph::count_publishers(const std::string & topic_name) const
451 {
452  auto rcl_node_handle = node_base_->get_rcl_node_handle();
453 
455  topic_name,
456  rcl_node_get_name(rcl_node_handle),
457  rcl_node_get_namespace(rcl_node_handle),
458  false); // false = not a service
459 
460  size_t count;
461  auto ret = rcl_count_publishers(rcl_node_handle, fqdn.c_str(), &count);
462  if (ret != RMW_RET_OK) {
463  // *INDENT-OFF*
464  throw std::runtime_error(
465  std::string("could not count publishers: ") + rmw_get_error_string().str);
466  // *INDENT-ON*
467  }
468  return count;
469 }
470 
471 size_t
472 NodeGraph::count_subscribers(const std::string & topic_name) const
473 {
474  auto rcl_node_handle = node_base_->get_rcl_node_handle();
475 
477  topic_name,
478  rcl_node_get_name(rcl_node_handle),
479  rcl_node_get_namespace(rcl_node_handle),
480  false); // false = not a service
481 
482  size_t count;
483  auto ret = rcl_count_subscribers(rcl_node_handle, fqdn.c_str(), &count);
484  if (ret != RMW_RET_OK) {
485  // *INDENT-OFF*
486  throw std::runtime_error(
487  std::string("could not count subscribers: ") + rmw_get_error_string().str);
488  // *INDENT-ON*
489  }
490  return count;
491 }
492 
493 size_t
494 NodeGraph::count_clients(const std::string & service_name) const
495 {
496  auto rcl_node_handle = node_base_->get_rcl_node_handle();
497 
499  service_name,
500  rcl_node_get_name(rcl_node_handle),
501  rcl_node_get_namespace(rcl_node_handle),
502  true);
503 
504  size_t count;
505  auto ret = rcl_count_clients(rcl_node_handle, fqdn.c_str(), &count);
506  if (ret != RMW_RET_OK) {
507  // *INDENT-OFF*
508  throw std::runtime_error(
509  std::string("could not count clients: ") + rmw_get_error_string().str);
510  // *INDENT-ON*
511  }
512  return count;
513 }
514 
515 size_t
516 NodeGraph::count_services(const std::string & service_name) const
517 {
518  auto rcl_node_handle = node_base_->get_rcl_node_handle();
519 
521  service_name,
522  rcl_node_get_name(rcl_node_handle),
523  rcl_node_get_namespace(rcl_node_handle),
524  true);
525 
526  size_t count;
527  auto ret = rcl_count_services(rcl_node_handle, fqdn.c_str(), &count);
528  if (ret != RMW_RET_OK) {
529  // *INDENT-OFF*
530  throw std::runtime_error(
531  std::string("could not count services: ") + rmw_get_error_string().str);
532  // *INDENT-ON*
533  }
534  return count;
535 }
536 
537 const rcl_guard_condition_t *
539 {
541 }
542 
543 void
545 {
546  {
547  std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
548  bool bad_ptr_encountered = false;
549  for (auto & event_wptr : graph_events_) {
550  auto event_ptr = event_wptr.lock();
551  if (event_ptr) {
552  event_ptr->set();
553  } else {
554  bad_ptr_encountered = true;
555  }
556  }
557  if (bad_ptr_encountered) {
558  // remove invalid pointers with the erase-remove idiom
559  graph_events_.erase(
560  std::remove_if(
561  graph_events_.begin(),
562  graph_events_.end(),
563  [](const rclcpp::Event::WeakPtr & wptr) {
564  return wptr.expired();
565  }),
566  graph_events_.end());
567  // update graph_users_count_
568  graph_users_count_.store(graph_events_.size());
569  }
570  }
571  graph_cv_.notify_all();
572  try {
573  node_base_->trigger_notify_guard_condition();
574  } catch (const rclcpp::exceptions::RCLError & ex) {
575  throw std::runtime_error(
576  std::string("failed to notify wait set on graph change: ") + ex.what());
577  }
578 }
579 
580 void
582 {
583  // notify here anything that will not be woken up by ctrl-c or rclcpp::shutdown().
584  graph_cv_.notify_all();
585 }
586 
587 rclcpp::Event::SharedPtr
589 {
590  auto event = rclcpp::Event::make_shared();
591  {
592  std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
593  graph_events_.push_back(event);
594  graph_users_count_++;
595  }
596  // on first call, add node to graph_listener_
597  if (should_add_to_graph_listener_.exchange(false)) {
598  node_base_->get_context()->get_graph_listener()->add_node(this);
599  node_base_->get_context()->get_graph_listener()->start_if_not_started();
600  }
601  return event;
602 }
603 
604 void
606  rclcpp::Event::SharedPtr event,
607  std::chrono::nanoseconds timeout)
608 {
611  if (!event) {
612  throw InvalidEventError();
613  }
614  {
615  std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
616  bool event_in_graph_events = false;
617  for (const auto & event_wptr : graph_events_) {
618  if (event == event_wptr.lock()) {
619  event_in_graph_events = true;
620  break;
621  }
622  }
623  if (!event_in_graph_events) {
624  throw EventNotRegisteredError();
625  }
626  }
627  auto pred = [&event, context = node_base_->get_context()]() {
628  return event->check() || !rclcpp::ok(context);
629  };
630  std::unique_lock<std::mutex> graph_lock(graph_mutex_);
631  if (!pred()) {
632  graph_cv_.wait_for(graph_lock, timeout, pred);
633  }
634 }
635 
636 size_t
638 {
639  return graph_users_count_.load();
640 }
641 
642 static
643 std::vector<rclcpp::TopicEndpointInfo>
644 convert_to_topic_info_list(const rcl_topic_endpoint_info_array_t & info_array)
645 {
646  std::vector<rclcpp::TopicEndpointInfo> topic_info_list;
647  for (size_t i = 0; i < info_array.size; ++i) {
648  topic_info_list.push_back(rclcpp::TopicEndpointInfo(info_array.info_array[i]));
649  }
650  return topic_info_list;
651 }
652 
653 template<const char * EndpointType, typename FunctionT>
654 static std::vector<rclcpp::TopicEndpointInfo>
655 get_info_by_topic(
657  const std::string & topic_name,
658  bool no_mangle,
659  FunctionT rcl_get_info_by_topic)
660 {
661  std::string fqdn;
662  auto rcl_node_handle = node_base->get_rcl_node_handle();
663 
664  if (no_mangle) {
665  fqdn = topic_name;
666  } else {
668  topic_name,
669  rcl_node_get_name(rcl_node_handle),
670  rcl_node_get_namespace(rcl_node_handle),
671  false); // false = not a service
672 
673  // Get the node options
674  const rcl_node_options_t * node_options = rcl_node_get_options(rcl_node_handle);
675  if (nullptr == node_options) {
676  throw std::runtime_error("Need valid node options in get_info_by_topic()");
677  }
678  const rcl_arguments_t * global_args = nullptr;
679  if (node_options->use_global_arguments) {
680  global_args = &(rcl_node_handle->context->global_arguments);
681  }
682 
683  char * remapped_topic_name = nullptr;
685  &(node_options->arguments),
686  global_args,
687  fqdn.c_str(),
688  rcl_node_get_name(rcl_node_handle),
689  rcl_node_get_namespace(rcl_node_handle),
690  node_options->allocator,
691  &remapped_topic_name);
692  if (RCL_RET_OK != ret) {
693  throw_from_rcl_error(ret, std::string("Failed to remap topic name ") + fqdn);
694  } else if (nullptr != remapped_topic_name) {
695  fqdn = remapped_topic_name;
696  node_options->allocator.deallocate(remapped_topic_name, node_options->allocator.state);
697  }
698  }
699 
700  rcutils_allocator_t allocator = rcutils_get_default_allocator();
702  rcl_ret_t ret =
703  rcl_get_info_by_topic(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
704  if (RCL_RET_OK != ret) {
705  auto error_msg =
706  std::string("Failed to get information by topic for ") + EndpointType + std::string(":");
707  if (RCL_RET_UNSUPPORTED == ret) {
708  error_msg += std::string("function not supported by RMW_IMPLEMENTATION");
709  } else {
710  error_msg += rcl_get_error_string().str;
711  }
712  rcl_reset_error();
713  if (RCL_RET_OK != rcl_topic_endpoint_info_array_fini(&info_array, &allocator)) {
714  error_msg += std::string(", failed also to cleanup topic info array, leaking memory: ") +
715  rcl_get_error_string().str;
716  rcl_reset_error();
717  }
718  throw_from_rcl_error(ret, error_msg);
719  }
720 
721  std::vector<rclcpp::TopicEndpointInfo> topic_info_list = convert_to_topic_info_list(info_array);
722  ret = rcl_topic_endpoint_info_array_fini(&info_array, &allocator);
723  if (RCL_RET_OK != ret) {
724  throw_from_rcl_error(ret, "rcl_topic_info_array_fini failed.");
725  }
726 
727  return topic_info_list;
728 }
729 
730 static constexpr char kPublisherEndpointTypeName[] = "publishers";
731 std::vector<rclcpp::TopicEndpointInfo>
733  const std::string & topic_name,
734  bool no_mangle) const
735 {
736  return get_info_by_topic<kPublisherEndpointTypeName>(
737  node_base_,
738  topic_name,
739  no_mangle,
741 }
742 
743 static constexpr char kSubscriptionEndpointTypeName[] = "subscriptions";
744 std::vector<rclcpp::TopicEndpointInfo>
746  const std::string & topic_name,
747  bool no_mangle) const
748 {
749  return get_info_by_topic<kSubscriptionEndpointTypeName>(
750  node_base_,
751  topic_name,
752  no_mangle,
754 }
755 
756 std::string &
758 {
759  return node_name_;
760 }
761 
762 const std::string &
764 {
765  return node_name_;
766 }
767 
768 std::string &
770 {
771  return node_namespace_;
772 }
773 
774 const std::string &
776 {
777  return node_namespace_;
778 }
779 
780 std::string &
782 {
783  return topic_type_;
784 }
785 
786 const std::string &
788 {
789  return topic_type_;
790 }
791 
792 rclcpp::EndpointType &
794 {
795  return endpoint_type_;
796 }
797 
798 const rclcpp::EndpointType &
800 {
801  return endpoint_type_;
802 }
803 
804 std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
806 {
807  return endpoint_gid_;
808 }
809 
810 const std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
812 {
813  return endpoint_gid_;
814 }
815 
816 rclcpp::QoS &
818 {
819  return qos_profile_;
820 }
821 
822 const rclcpp::QoS &
824 {
825  return qos_profile_;
826 }
827 
828 rosidl_type_hash_t &
830 {
831  return topic_type_hash_;
832 }
833 
834 const rosidl_type_hash_t &
836 {
837  return topic_type_hash_;
838 }
#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 std::string & node_name()
Get a mutable reference to the node name.
Definition: node_graph.cpp:757
RCLCPP_PUBLIC std::string & node_namespace()
Get a mutable reference to the node namespace.
Definition: node_graph.cpp:769
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:829
RCLCPP_PUBLIC std::string & topic_type()
Get a mutable reference to the topic type string.
Definition: node_graph.cpp:781
RCLCPP_PUBLIC rclcpp::QoS & qos_profile()
Get a mutable reference to the QoS profile of the topic endpoint.
Definition: node_graph.cpp:817
RCLCPP_PUBLIC rclcpp::EndpointType & endpoint_type()
Get a mutable reference to the topic endpoint type.
Definition: node_graph.cpp:793
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:805
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:51
RCLCPP_PUBLIC std::vector< std::string > get_node_names() const override
Return a vector of existing node names (string).
Definition: node_graph.cpp:290
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:97
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:216
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:732
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:393
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:516
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:253
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:472
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:181
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:745
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:637
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:55
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:605
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:139
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:588
RCLCPP_PUBLIC void notify_shutdown() override
Notify any and all blocking node actions that shutdown has occurred.
Definition: node_graph.cpp:581
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:318
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:450
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:494
RCLCPP_PUBLIC void notify_graph_change() override
Notify threads waiting on graph changes.
Definition: node_graph.cpp:544
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:538
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:479
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:738
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:306
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:375
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:267
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:200
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:721
rmw_topic_endpoint_info_array_t rcl_topic_endpoint_info_array_t
An array of topic endpoint information.
Definition: graph.h:48
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:160
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:118
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:441
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:460
rmw_names_and_types_t rcl_names_and_types_t
A structure that contains topic names and types.
Definition: graph.h:40
#define rcl_topic_endpoint_info_array_fini
Finalize a topic_endpoint_info_array_t structure.
Definition: graph.h:58
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:77
#define rcl_get_zero_initialized_names_and_types
Return a zero-initialized rcl_names_and_types_t structure.
Definition: graph.h:51
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:240
#define rcl_get_zero_initialized_topic_endpoint_info_array
Return a zero-initialized rcl_topic_endpoint_info_t structure.
Definition: graph.h:54
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:316
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:422
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(rclcpp::Context::SharedPtr context=nullptr)
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:435
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:408
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:417
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:476
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