ROS 2 rclcpp + rcl - humble  humble
ROS 2 C++ Client Library with ROS Client Library
graph.c
1 // Copyright 2016-2017 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 #ifdef __cplusplus
16 extern "C"
17 {
18 #endif
19 
20 #include "rcl/graph.h"
21 
22 #include "rcl/error_handling.h"
23 #include "rcl/guard_condition.h"
24 #include "rcl/wait.h"
25 #include "rcutils/allocator.h"
26 #include "rcutils/error_handling.h"
27 #include "rcutils/macros.h"
28 #include "rcutils/time.h"
29 #include "rcutils/types.h"
30 #include "rmw/error_handling.h"
31 #include "rmw/get_node_info_and_types.h"
32 #include "rmw/get_service_names_and_types.h"
33 #include "rmw/get_topic_endpoint_info.h"
34 #include "rmw/get_topic_names_and_types.h"
35 #include "rmw/names_and_types.h"
36 #include "rmw/rmw.h"
37 #include "rmw/topic_endpoint_info_array.h"
38 #include "rmw/validate_namespace.h"
39 #include "rmw/validate_node_name.h"
40 
41 #include "./common.h"
42 
44 __validate_node_name_and_namespace(
45  const char * node_name,
46  const char * node_namespace)
47 {
48  int validation_result = 0;
49  rmw_ret_t rmw_ret = rmw_validate_namespace(node_namespace, &validation_result, NULL);
50 
51  if (RMW_RET_OK != rmw_ret) {
52  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
53  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
54  }
55  if (validation_result != RMW_NAMESPACE_VALID) {
56  const char * msg = rmw_namespace_validation_result_string(validation_result);
57  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING("%s, result: %d", msg, validation_result);
59  }
60 
61  validation_result = 0;
62  rmw_ret = rmw_validate_node_name(node_name, &validation_result, NULL);
63  if (RMW_RET_OK != rmw_ret) {
64  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
65  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
66  }
67  if (RMW_NODE_NAME_VALID != validation_result) {
68  const char * msg = rmw_node_name_validation_result_string(validation_result);
69  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING("%s, result: %d", msg, validation_result);
71  }
72 
73  return RCL_RET_OK;
74 }
75 
78  const rcl_node_t * node,
79  rcl_allocator_t * allocator,
80  bool no_demangle,
81  const char * node_name,
82  const char * node_namespace,
83  rcl_names_and_types_t * topic_names_and_types)
84 {
85  if (!rcl_node_is_valid(node)) {
86  return RCL_RET_NODE_INVALID;
87  }
88  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
89  RCL_CHECK_ARGUMENT_FOR_NULL(node_name, RCL_RET_INVALID_ARGUMENT);
90  RCL_CHECK_ARGUMENT_FOR_NULL(node_namespace, RCL_RET_INVALID_ARGUMENT);
91  RCL_CHECK_ARGUMENT_FOR_NULL(topic_names_and_types, RCL_RET_INVALID_ARGUMENT);
92 
93  const char * valid_namespace = "/";
94  if (strlen(node_namespace) > 0) {
95  valid_namespace = node_namespace;
96  }
97  rmw_ret_t rmw_ret = rmw_names_and_types_check_zero(topic_names_and_types);
98  if (RMW_RET_OK != rmw_ret) {
99  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
100  }
101  rcl_ret_t rcl_ret = __validate_node_name_and_namespace(node_name, valid_namespace);
102  if (RCL_RET_OK != rcl_ret) {
103  return rcl_ret;
104  }
105  rcutils_allocator_t rcutils_allocator = *allocator;
106  rmw_ret = rmw_get_publisher_names_and_types_by_node(
108  &rcutils_allocator,
109  node_name,
110  valid_namespace,
111  no_demangle,
112  topic_names_and_types
113  );
114  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
115 }
116 
117 rcl_ret_t
119  const rcl_node_t * node,
120  rcl_allocator_t * allocator,
121  bool no_demangle,
122  const char * node_name,
123  const char * node_namespace,
124  rcl_names_and_types_t * topic_names_and_types)
125 {
126  if (!rcl_node_is_valid(node)) {
127  return RCL_RET_NODE_INVALID;
128  }
129  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
130  RCL_CHECK_ARGUMENT_FOR_NULL(node_name, RCL_RET_INVALID_ARGUMENT);
131  RCL_CHECK_ARGUMENT_FOR_NULL(node_namespace, RCL_RET_INVALID_ARGUMENT);
132  RCL_CHECK_ARGUMENT_FOR_NULL(topic_names_and_types, RCL_RET_INVALID_ARGUMENT);
133 
134  const char * valid_namespace = "/";
135  if (strlen(node_namespace) > 0) {
136  valid_namespace = node_namespace;
137  }
138  rmw_ret_t rmw_ret;
139  rmw_ret = rmw_names_and_types_check_zero(topic_names_and_types);
140  if (rmw_ret != RMW_RET_OK) {
141  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
142  }
143  rcutils_allocator_t rcutils_allocator = *allocator;
144  rcl_ret_t rcl_ret = __validate_node_name_and_namespace(node_name, valid_namespace);
145  if (RCL_RET_OK != rcl_ret) {
146  return rcl_ret;
147  }
148  rmw_ret = rmw_get_subscriber_names_and_types_by_node(
150  &rcutils_allocator,
151  node_name,
152  valid_namespace,
153  no_demangle,
154  topic_names_and_types
155  );
156  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
157 }
158 
159 rcl_ret_t
161  const rcl_node_t * node,
162  rcl_allocator_t * allocator,
163  const char * node_name,
164  const char * node_namespace,
165  rcl_names_and_types_t * service_names_and_types)
166 {
167  if (!rcl_node_is_valid(node)) {
168  return RCL_RET_NODE_INVALID;
169  }
170  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
171  RCL_CHECK_ARGUMENT_FOR_NULL(node_name, RCL_RET_INVALID_ARGUMENT);
172  RCL_CHECK_ARGUMENT_FOR_NULL(node_namespace, RCL_RET_INVALID_ARGUMENT);
173  RCL_CHECK_ARGUMENT_FOR_NULL(service_names_and_types, RCL_RET_INVALID_ARGUMENT);
174 
175  const char * valid_namespace = "/";
176  if (strlen(node_namespace) > 0) {
177  valid_namespace = node_namespace;
178  }
179  rmw_ret_t rmw_ret;
180  rmw_ret = rmw_names_and_types_check_zero(service_names_and_types);
181  if (rmw_ret != RMW_RET_OK) {
182  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
183  }
184  rcl_ret_t rcl_ret = __validate_node_name_and_namespace(node_name, valid_namespace);
185  if (RCL_RET_OK != rcl_ret) {
186  return rcl_ret;
187  }
188  rcutils_allocator_t rcutils_allocator = *allocator;
189  rmw_ret = rmw_get_service_names_and_types_by_node(
191  &rcutils_allocator,
192  node_name,
193  valid_namespace,
194  service_names_and_types
195  );
196  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
197 }
198 
199 rcl_ret_t
201  const rcl_node_t * node,
202  rcl_allocator_t * allocator,
203  const char * node_name,
204  const char * node_namespace,
205  rcl_names_and_types_t * service_names_and_types)
206 {
207  if (!rcl_node_is_valid(node)) {
208  return RCL_RET_NODE_INVALID;
209  }
210  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
211  RCL_CHECK_ARGUMENT_FOR_NULL(node_name, RCL_RET_INVALID_ARGUMENT);
212  RCL_CHECK_ARGUMENT_FOR_NULL(node_namespace, RCL_RET_INVALID_ARGUMENT);
213  RCL_CHECK_ARGUMENT_FOR_NULL(service_names_and_types, RCL_RET_INVALID_ARGUMENT);
214 
215  const char * valid_namespace = "/";
216  if (strlen(node_namespace) > 0) {
217  valid_namespace = node_namespace;
218  }
219  rmw_ret_t rmw_ret;
220  rmw_ret = rmw_names_and_types_check_zero(service_names_and_types);
221  if (rmw_ret != RMW_RET_OK) {
222  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
223  }
224  rcl_ret_t rcl_ret = __validate_node_name_and_namespace(node_name, valid_namespace);
225  if (RCL_RET_OK != rcl_ret) {
226  return rcl_ret;
227  }
228  rcutils_allocator_t rcutils_allocator = *allocator;
229  rmw_ret = rmw_get_client_names_and_types_by_node(
231  &rcutils_allocator,
232  node_name,
233  valid_namespace,
234  service_names_and_types
235  );
236  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
237 }
238 
239 rcl_ret_t
241  const rcl_node_t * node,
242  rcl_allocator_t * allocator,
243  bool no_demangle,
244  rcl_names_and_types_t * topic_names_and_types)
245 {
246  if (!rcl_node_is_valid(node)) {
247  return RCL_RET_NODE_INVALID; // error already set
248  }
249  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
250  RCL_CHECK_ARGUMENT_FOR_NULL(topic_names_and_types, RCL_RET_INVALID_ARGUMENT);
251  rmw_ret_t rmw_ret;
252  rmw_ret = rmw_names_and_types_check_zero(topic_names_and_types);
253  if (rmw_ret != RMW_RET_OK) {
254  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
255  }
256  rcutils_allocator_t rcutils_allocator = *allocator;
257  rmw_ret = rmw_get_topic_names_and_types(
259  &rcutils_allocator,
260  no_demangle,
261  topic_names_and_types
262  );
263  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
264 }
265 
266 rcl_ret_t
268  const rcl_node_t * node,
269  rcl_allocator_t * allocator,
270  rcl_names_and_types_t * service_names_and_types)
271 {
272  if (!rcl_node_is_valid(node)) {
273  return RCL_RET_NODE_INVALID; // error already set
274  }
275  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
276  RCL_CHECK_ARGUMENT_FOR_NULL(service_names_and_types, RCL_RET_INVALID_ARGUMENT);
277  rmw_ret_t rmw_ret;
278  rmw_ret = rmw_names_and_types_check_zero(service_names_and_types);
279  if (rmw_ret != RMW_RET_OK) {
280  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
281  }
282  rcutils_allocator_t rcutils_allocator = *allocator;
283  rmw_ret = rmw_get_service_names_and_types(
285  &rcutils_allocator,
286  service_names_and_types
287  );
288  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
289 }
290 
291 rcl_ret_t
293  rcl_names_and_types_t * names_and_types,
294  size_t size,
295  rcl_allocator_t * allocator)
296 {
297  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
298 
299  RCL_CHECK_ARGUMENT_FOR_NULL(names_and_types, RCL_RET_INVALID_ARGUMENT);
301  rmw_ret_t rmw_ret = rmw_names_and_types_init(names_and_types, size, allocator);
302  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
303 }
304 
305 rcl_ret_t
307 {
308  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
309 
310  RCL_CHECK_ARGUMENT_FOR_NULL(topic_names_and_types, RCL_RET_INVALID_ARGUMENT);
311  rmw_ret_t rmw_ret = rmw_names_and_types_fini(topic_names_and_types);
312  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
313 }
314 
315 rcl_ret_t
317  const rcl_node_t * node,
318  rcl_allocator_t allocator,
319  rcutils_string_array_t * node_names,
320  rcutils_string_array_t * node_namespaces)
321 {
322  if (!rcl_node_is_valid(node)) {
323  return RCL_RET_NODE_INVALID; // error already set
324  }
325  RCL_CHECK_ARGUMENT_FOR_NULL(node_names, RCL_RET_INVALID_ARGUMENT);
326  if (node_names->size != 0) {
327  RCL_SET_ERROR_MSG("node_names size is not zero");
329  }
330  if (node_names->data) {
331  RCL_SET_ERROR_MSG("node_names is not null");
333  }
334  RCL_CHECK_ARGUMENT_FOR_NULL(node_namespaces, RCL_RET_INVALID_ARGUMENT);
335  if (node_namespaces->size != 0) {
336  RCL_SET_ERROR_MSG("node_namespaces size is not zero");
338  }
339  if (node_namespaces->data) {
340  RCL_SET_ERROR_MSG("node_namespaces is not null");
342  }
343  (void)allocator; // to be used in rmw_get_node_names in the future
344  rmw_ret_t rmw_ret = rmw_get_node_names(
346  node_names,
347  node_namespaces);
348 
349  if (RMW_RET_OK != rmw_ret) {
350  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
351  }
352 
353  // Check that none of the node names are NULL or empty
354  for (size_t i = 0u; i < node_names->size; ++i) {
355  if (!node_names->data[i]) {
356  RCL_SET_ERROR_MSG("NULL node name returned by the RMW layer");
358  }
359  if (!strcmp(node_names->data[i], "")) {
360  RCL_SET_ERROR_MSG("empty node name returned by the RMW layer");
362  }
363  }
364  // Check that none of the node namespaces are NULL
365  for (size_t i = 0u; i < node_namespaces->size; ++i) {
366  if (!node_namespaces->data[i]) {
367  RCL_SET_ERROR_MSG("NULL node namespace returned by the RMW layer");
369  }
370  }
371  return RCL_RET_OK;
372 }
373 
374 rcl_ret_t
376  const rcl_node_t * node,
377  rcl_allocator_t allocator,
378  rcutils_string_array_t * node_names,
379  rcutils_string_array_t * node_namespaces,
380  rcutils_string_array_t * enclaves)
381 {
382  if (!rcl_node_is_valid(node)) {
383  return RCL_RET_NODE_INVALID; // error already set
384  }
385  RCL_CHECK_ARGUMENT_FOR_NULL(node_names, RCL_RET_INVALID_ARGUMENT);
386  if (node_names->size != 0) {
387  RCL_SET_ERROR_MSG("node_names size is not zero");
389  }
390  if (node_names->data) {
391  RCL_SET_ERROR_MSG("node_names is not null");
393  }
394  RCL_CHECK_ARGUMENT_FOR_NULL(node_namespaces, RCL_RET_INVALID_ARGUMENT);
395  if (node_namespaces->size != 0) {
396  RCL_SET_ERROR_MSG("node_namespaces size is not zero");
398  }
399  if (node_namespaces->data) {
400  RCL_SET_ERROR_MSG("node_namespaces is not null");
402  }
403  RCL_CHECK_ARGUMENT_FOR_NULL(enclaves, RCL_RET_INVALID_ARGUMENT);
404  if (enclaves->size != 0) {
405  RCL_SET_ERROR_MSG("enclaves size is not zero");
407  }
408  if (enclaves->data) {
409  RCL_SET_ERROR_MSG("enclaves is not null");
411  }
412  (void)allocator; // to be used in rmw_get_node_names in the future
413  rmw_ret_t rmw_ret = rmw_get_node_names_with_enclaves(
415  node_names,
416  node_namespaces,
417  enclaves);
418  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
419 }
420 
421 rcl_ret_t
423  const rcl_node_t * node,
424  const char * topic_name,
425  size_t * count)
426 {
427  if (!rcl_node_is_valid(node)) {
428  return RCL_RET_NODE_INVALID; // error already set
429  }
430  const rcl_node_options_t * node_options = rcl_node_get_options(node);
431  if (!node_options) {
432  return RCL_RET_NODE_INVALID; // shouldn't happen, but error is already set if so
433  }
434  RCL_CHECK_ARGUMENT_FOR_NULL(topic_name, RCL_RET_INVALID_ARGUMENT);
435  RCL_CHECK_ARGUMENT_FOR_NULL(count, RCL_RET_INVALID_ARGUMENT);
436  rmw_ret_t rmw_ret = rmw_count_publishers(rcl_node_get_rmw_handle(node), topic_name, count);
437  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
438 }
439 
440 rcl_ret_t
442  const rcl_node_t * node,
443  const char * topic_name,
444  size_t * count)
445 {
446  if (!rcl_node_is_valid(node)) {
447  return RCL_RET_NODE_INVALID; // error already set
448  }
449  const rcl_node_options_t * node_options = rcl_node_get_options(node);
450  if (!node_options) {
451  return RCL_RET_NODE_INVALID; // shouldn't happen, but error is already set if so
452  }
453  RCL_CHECK_ARGUMENT_FOR_NULL(topic_name, RCL_RET_INVALID_ARGUMENT);
454  RCL_CHECK_ARGUMENT_FOR_NULL(count, RCL_RET_INVALID_ARGUMENT);
455  rmw_ret_t rmw_ret = rmw_count_subscribers(rcl_node_get_rmw_handle(node), topic_name, count);
456  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
457 }
458 
459 typedef rcl_ret_t (* count_entities_func_t)(
460  const rcl_node_t * node,
461  const char * topic_name,
462  size_t * count);
463 
464 rcl_ret_t
465 _rcl_wait_for_entities(
466  const rcl_node_t * node,
467  rcl_allocator_t * allocator,
468  const char * topic_name,
469  const size_t expected_count,
470  rcutils_duration_value_t timeout,
471  bool * success,
472  count_entities_func_t count_entities_func)
473 {
474  if (!rcl_node_is_valid(node)) {
475  return RCL_RET_NODE_INVALID;
476  }
477  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
478  RCL_CHECK_ARGUMENT_FOR_NULL(topic_name, RCL_RET_INVALID_ARGUMENT);
479  RCL_CHECK_ARGUMENT_FOR_NULL(success, RCL_RET_INVALID_ARGUMENT);
480 
481  rcl_ret_t ret = RCL_RET_OK;
482  *success = false;
483 
484  // We can avoid waiting if there are already the expected number of entities
485  size_t count = 0u;
486  ret = count_entities_func(node, topic_name, &count);
487  if (ret != RCL_RET_OK) {
488  // Error message already set
489  return ret;
490  }
491  if (expected_count <= count) {
492  *success = true;
493  return RCL_RET_OK;
494  }
495 
496  // Create a wait set and add the node graph guard condition to it
498  ret = rcl_wait_set_init(
499  &wait_set, 0, 1, 0, 0, 0, 0, node->context, *allocator);
500  if (ret != RCL_RET_OK) {
501  // Error message already set
502  return ret;
503  }
504 
505  const rcl_guard_condition_t * guard_condition = rcl_node_get_graph_guard_condition(node);
506  if (!guard_condition) {
507  // Error message already set
508  ret = RCL_RET_ERROR;
509  goto cleanup;
510  }
511 
512  // Add it to the wait set
513  ret = rcl_wait_set_add_guard_condition(&wait_set, guard_condition, NULL);
514  if (ret != RCL_RET_OK) {
515  // Error message already set
516  goto cleanup;
517  }
518 
519  // Get current time
520  // We use system time to be consistent with the clock used by rcl_wait()
521  rcutils_time_point_value_t start;
522  rcutils_ret_t time_ret = rcutils_system_time_now(&start);
523  if (time_ret != RCUTILS_RET_OK) {
524  rcutils_error_string_t error = rcutils_get_error_string();
525  rcutils_reset_error();
526  RCL_SET_ERROR_MSG(error.str);
527  ret = RCL_RET_ERROR;
528  goto cleanup;
529  }
530 
531  // Wait for expected count or timeout
532  rcl_ret_t wait_ret;
533  while (true) {
534  // Use separate 'wait_ret' code to avoid returning spurious TIMEOUT value
535  wait_ret = rcl_wait(&wait_set, timeout);
536  if (wait_ret != RCL_RET_OK && wait_ret != RCL_RET_TIMEOUT) {
537  // Error message already set
538  ret = wait_ret;
539  break;
540  }
541 
542  // Check count
543  ret = count_entities_func(node, topic_name, &count);
544  if (ret != RCL_RET_OK) {
545  // Error already set
546  break;
547  }
548  if (expected_count <= count) {
549  *success = true;
550  break;
551  }
552 
553  // If we're not waiting indefinitely, compute time remaining
554  if (timeout >= 0) {
555  rcutils_time_point_value_t now;
556  time_ret = rcutils_system_time_now(&now);
557  if (time_ret != RCUTILS_RET_OK) {
558  rcutils_error_string_t error = rcutils_get_error_string();
559  rcutils_reset_error();
560  RCL_SET_ERROR_MSG(error.str);
561  ret = RCL_RET_ERROR;
562  break;
563  }
564  timeout = timeout - (now - start);
565  if (timeout <= 0) {
566  ret = RCL_RET_TIMEOUT;
567  break;
568  }
569  }
570 
571  // Clear wait set for next iteration
572  ret = rcl_wait_set_clear(&wait_set);
573  if (ret != RCL_RET_OK) {
574  // Error message already set
575  break;
576  }
577  }
578 
579  rcl_ret_t cleanup_ret;
580 cleanup:
581  // Cleanup
582  cleanup_ret = rcl_wait_set_fini(&wait_set);
583  if (cleanup_ret != RCL_RET_OK) {
584  // If we got two unexpected errors, return the earlier error
585  if (ret != RCL_RET_OK && ret != RCL_RET_TIMEOUT) {
586  // Error message already set
587  ret = cleanup_ret;
588  }
589  }
590 
591  return ret;
592 }
593 
594 rcl_ret_t
596  const rcl_node_t * node,
597  rcl_allocator_t * allocator,
598  const char * topic_name,
599  const size_t expected_count,
600  rcutils_duration_value_t timeout,
601  bool * success)
602 {
603  return _rcl_wait_for_entities(
604  node,
605  allocator,
606  topic_name,
607  expected_count,
608  timeout,
609  success,
611 }
612 
613 rcl_ret_t
615  const rcl_node_t * node,
616  rcl_allocator_t * allocator,
617  const char * topic_name,
618  const size_t expected_count,
619  rcutils_duration_value_t timeout,
620  bool * success)
621 {
622  return _rcl_wait_for_entities(
623  node,
624  allocator,
625  topic_name,
626  expected_count,
627  timeout,
628  success,
630 }
631 
632 typedef rmw_ret_t (* get_topic_endpoint_info_func_t)(
633  const rmw_node_t * node,
634  rcutils_allocator_t * allocator,
635  const char * topic_name,
636  bool no_mangle,
637  rmw_topic_endpoint_info_array_t * info_array);
638 
639 rcl_ret_t
640 __rcl_get_info_by_topic(
641  const rcl_node_t * node,
642  rcutils_allocator_t * allocator,
643  const char * topic_name,
644  bool no_mangle,
645  rmw_topic_endpoint_info_array_t * info_array,
646  get_topic_endpoint_info_func_t get_topic_endpoint_info)
647 {
648  if (!rcl_node_is_valid(node)) {
649  return RCL_RET_NODE_INVALID; // error already set.
650  }
651  const rcl_node_options_t * node_options = rcl_node_get_options(node);
652  if (!node_options) {
653  return RCL_RET_NODE_INVALID; // shouldn't happen, but error is already set if so
654  }
655  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
656  RCL_CHECK_ARGUMENT_FOR_NULL(topic_name, RCL_RET_INVALID_ARGUMENT);
657  rmw_error_string_t error_string;
658  rmw_ret_t rmw_ret = rmw_topic_endpoint_info_array_check_zero(info_array);
659  if (rmw_ret != RMW_RET_OK) {
660  error_string = rmw_get_error_string();
661  rmw_reset_error();
662  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
663  "rmw_topic_endpoint_info_array_t must be zero initialized: %s,\n"
664  "Use rmw_get_zero_initialized_topic_endpoint_info_array",
665  error_string.str);
666  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
667  }
668  rmw_ret = get_topic_endpoint_info(
670  allocator,
671  topic_name,
672  no_mangle,
673  info_array);
674  if (rmw_ret != RMW_RET_OK) {
675  error_string = rmw_get_error_string();
676  rmw_reset_error();
677  RCL_SET_ERROR_MSG(error_string.str);
678  }
679  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
680 }
681 
682 rcl_ret_t
684  const rcl_node_t * node,
685  rcutils_allocator_t * allocator,
686  const char * topic_name,
687  bool no_mangle,
688  rmw_topic_endpoint_info_array_t * publishers_info)
689 {
690  return __rcl_get_info_by_topic(
691  node,
692  allocator,
693  topic_name,
694  no_mangle,
695  publishers_info,
696  rmw_get_publishers_info_by_topic);
697 }
698 
699 rcl_ret_t
701  const rcl_node_t * node,
702  rcutils_allocator_t * allocator,
703  const char * topic_name,
704  bool no_mangle,
705  rmw_topic_endpoint_info_array_t * subscriptions_info)
706 {
707  return __rcl_get_info_by_topic(
708  node,
709  allocator,
710  topic_name,
711  no_mangle,
712  subscriptions_info,
713  rmw_get_subscriptions_info_by_topic);
714 }
715 
716 rcl_ret_t
718  const rcl_node_t * node,
719  const rcl_client_t * client,
720  bool * is_available)
721 {
722  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
723  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_NODE_INVALID);
724 
725  if (!rcl_node_is_valid(node)) {
726  return RCL_RET_NODE_INVALID; // error already set
727  }
728  const rcl_node_options_t * node_options = rcl_node_get_options(node);
729  if (!node_options) {
730  return RCL_RET_NODE_INVALID; // shouldn't happen, but error is already set if so
731  }
732  RCL_CHECK_ARGUMENT_FOR_NULL(client, RCL_RET_INVALID_ARGUMENT);
733  RCL_CHECK_ARGUMENT_FOR_NULL(is_available, RCL_RET_INVALID_ARGUMENT);
734  rmw_ret_t rmw_ret = rmw_service_server_is_available(
737  is_available
738  );
739  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
740 }
741 
742 #ifdef __cplusplus
743 }
744 #endif
#define RCL_CHECK_ALLOCATOR(allocator, fail_statement)
Check that the given allocator is initialized.
Definition: allocator.h:49
#define RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, msg, fail_statement)
Check that the given allocator is initialized, or fail with a message.
Definition: allocator.h:56
rcutils_allocator_t rcl_allocator_t
Encapsulation of an allocator.
Definition: allocator.h:31
RCL_PUBLIC RCL_WARN_UNUSED rmw_client_t * rcl_client_get_rmw_handle(const rcl_client_t *client)
Return the rmw client handle.
Definition: client.c:230
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:700
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 available nodes in the ROS graph, including their enclave names.
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_service_server_is_available(const rcl_node_t *node, const rcl_client_t *client, bool *is_available)
Check if a service server is available for the given service client.
Definition: graph.c:717
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:683
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_names_and_types_init(rcl_names_and_types_t *names_and_types, size_t size, rcl_allocator_t *allocator)
Initialize a rcl_names_and_types_t object.
Definition: graph.c:292
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_wait_for_publishers(const rcl_node_t *node, rcl_allocator_t *allocator, const char *topic_name, const size_t count, rcutils_duration_value_t timeout, bool *success)
Wait for there to be a specified number of publishers on a given topic.
Definition: graph.c:595
rmw_names_and_types_t rcl_names_and_types_t
A structure that contains topic names and types.
Definition: graph.h:40
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
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_for_subscribers(const rcl_node_t *node, rcl_allocator_t *allocator, const char *topic_name, const size_t count, rcutils_duration_value_t timeout, bool *success)
Wait for there to be a specified number of subscribers on a given topic.
Definition: graph.c:614
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
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 available nodes 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
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:462
RCL_PUBLIC bool rcl_node_is_valid(const rcl_node_t *node)
Return true if the node is valid, else false.
Definition: node.c:421
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:503
RCL_PUBLIC RCL_WARN_UNUSED rmw_node_t * rcl_node_get_rmw_handle(const rcl_node_t *node)
Return the rmw node handle.
Definition: node.c:485
Structure which encapsulates a ROS Client.
Definition: client.h:37
Handle for a rcl guard condition.
Structure which encapsulates the options for creating a rcl_node_t.
Definition: node_options.h:35
Structure which encapsulates a ROS Node.
Definition: node.h:42
rcl_context_t * context
Context associated with this node.
Definition: node.h:44
Container for subscription's, guard condition's, etc to be waited on.
Definition: wait.h:42
#define RCL_RET_NODE_INVALID_NAMESPACE
Invalid node namespace return code.
Definition: types.h:60
#define RCL_RET_OK
Success return code.
Definition: types.h:26
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:34
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:28
#define RCL_RET_NODE_INVALID
Invalid rcl_node_t given return code.
Definition: types.h:56
#define RCL_RET_TIMEOUT
Timeout occurred return code.
Definition: types.h:30
#define RCL_RET_NODE_INVALID_NAME
Invalid node name return code.
Definition: types.h:58
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:23
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_init(rcl_wait_set_t *wait_set, size_t number_of_subscriptions, size_t number_of_guard_conditions, size_t number_of_timers, size_t number_of_clients, size_t number_of_services, size_t number_of_events, rcl_context_t *context, rcl_allocator_t allocator)
Initialize a rcl wait set with space for items to be waited on.
Definition: wait.c:103
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_clear(rcl_wait_set_t *wait_set)
Remove (sets to NULL) all entities in the wait set.
Definition: wait.c:334
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_fini(rcl_wait_set_t *wait_set)
Finalize a rcl wait set.
Definition: wait.c:189
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait(rcl_wait_set_t *wait_set, int64_t timeout)
Block until the wait set is ready or until the timeout has been exceeded.
Definition: wait.c:522
RCL_PUBLIC RCL_WARN_UNUSED rcl_wait_set_t rcl_get_zero_initialized_wait_set(void)
Return a rcl_wait_set_t struct with members set to NULL.
Definition: wait.c:64
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_guard_condition(rcl_wait_set_t *wait_set, const rcl_guard_condition_t *guard_condition, size_t *index)
Store a pointer to the guard condition in the next empty spot in the set.
Definition: wait.c:454