ROS 2 rclcpp + rcl - jazzy  jazzy
ROS 2 C++ Client Library with ROS Client Library
discovery_options.c
1 // Copyright 2022 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 "rcl/discovery_options.h"
16 
17 #include <stdlib.h>
18 #include <string.h>
19 
20 #include "rcutils/allocator.h"
21 #include "rcutils/env.h"
22 #include "rcutils/logging_macros.h"
23 #include "rcutils/snprintf.h"
24 #include "rcutils/split.h"
25 #include "rcutils/types/string_array.h"
26 
27 #include "rcl/error_handling.h"
28 #include "rcl/types.h"
29 
30 #include "rmw/error_handling.h"
31 
32 #include "./common.h"
33 
34 static const char * const RCL_STATIC_PEERS_ENV_VAR = "ROS_STATIC_PEERS";
35 static const char * const RCL_AUTOMATIC_DISCOVERY_RANGE_ENV_VAR = "ROS_AUTOMATIC_DISCOVERY_RANGE";
36 
37 #define GET_RMW_DISCOVERY_RANGE(x) \
38  _GET_DEFAULT_DISCOVERY_RANGE(x)
39 #define _GET_DEFAULT_DISCOVERY_RANGE(x) \
40  RMW_AUTOMATIC_DISCOVERY_RANGE_ ## x
41 
43 rcl_get_automatic_discovery_range(rmw_discovery_options_t * discovery_options)
44 {
45  const char * ros_automatic_discovery_range_env_val = NULL;
46  const char * get_env_error_str = NULL;
47 
48  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
49  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
50  RCL_CHECK_ARGUMENT_FOR_NULL(discovery_options, RCL_RET_INVALID_ARGUMENT);
51 
52  get_env_error_str = rcutils_get_env(
53  RCL_AUTOMATIC_DISCOVERY_RANGE_ENV_VAR,
54  &ros_automatic_discovery_range_env_val);
55  if (NULL != get_env_error_str) {
56  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
57  "Error getting env var '%s': %s", RCL_AUTOMATIC_DISCOVERY_RANGE_ENV_VAR,
58  get_env_error_str);
59  return RCL_RET_ERROR;
60  }
61  if (strcmp(ros_automatic_discovery_range_env_val, "") == 0) {
62 #ifdef RCL_DEFAULT_DISCOVERY_RANGE
63  discovery_options->automatic_discovery_range =
64  GET_RMW_DISCOVERY_RANGE(RCL_DEFAULT_DISCOVERY_RANGE);
65 #else
66  discovery_options->automatic_discovery_range = RMW_AUTOMATIC_DISCOVERY_RANGE_SUBNET;
67 #endif
68  } else if (strcmp(ros_automatic_discovery_range_env_val, "OFF") == 0) {
69  discovery_options->automatic_discovery_range = RMW_AUTOMATIC_DISCOVERY_RANGE_OFF;
70  } else if (strcmp(ros_automatic_discovery_range_env_val, "LOCALHOST") == 0) {
71  discovery_options->automatic_discovery_range = RMW_AUTOMATIC_DISCOVERY_RANGE_LOCALHOST;
72  } else if (strcmp(ros_automatic_discovery_range_env_val, "SUBNET") == 0) {
73  discovery_options->automatic_discovery_range = RMW_AUTOMATIC_DISCOVERY_RANGE_SUBNET;
74  } else if (strcmp(ros_automatic_discovery_range_env_val, "SYSTEM_DEFAULT") == 0) {
75  discovery_options->automatic_discovery_range = RMW_AUTOMATIC_DISCOVERY_RANGE_SYSTEM_DEFAULT;
76  } else {
77  RCUTILS_LOG_WARN_NAMED(
78  ROS_PACKAGE_NAME,
79  "Invalid value '%s' specified for '%s', assuming localhost only",
80  ros_automatic_discovery_range_env_val,
81  RCL_AUTOMATIC_DISCOVERY_RANGE_ENV_VAR);
82 
83  discovery_options->automatic_discovery_range = RMW_AUTOMATIC_DISCOVERY_RANGE_LOCALHOST;
84  }
85 
86  return RCL_RET_OK;
87 }
88 
89 RCL_PUBLIC
90 const char *
91 rcl_automatic_discovery_range_to_string(rmw_automatic_discovery_range_t automatic_discovery_range)
92 {
93  switch (automatic_discovery_range) {
94  case RMW_AUTOMATIC_DISCOVERY_RANGE_NOT_SET:
95  return "RMW_AUTOMATIC_DISCOVERY_RANGE_NOT_SET";
96  case RMW_AUTOMATIC_DISCOVERY_RANGE_OFF:
97  return "RMW_AUTOMATIC_DISCOVERY_RANGE_OFF";
98  case RMW_AUTOMATIC_DISCOVERY_RANGE_LOCALHOST:
99  return "RMW_AUTOMATIC_DISCOVERY_RANGE_LOCALHOST";
100  case RMW_AUTOMATIC_DISCOVERY_RANGE_SUBNET:
101  return "RMW_AUTOMATIC_DISCOVERY_RANGE_SUBNET";
102  case RMW_AUTOMATIC_DISCOVERY_RANGE_SYSTEM_DEFAULT:
103  return "RMW_AUTOMATIC_DISCOVERY_RANGE_SYSTEM_DEFAULT";
104  default:
105  return NULL;
106  }
107 }
108 
109 rcl_ret_t
111  rmw_discovery_options_t * discovery_options,
112  rcutils_allocator_t * allocator)
113 {
114  const char * ros_peers_env_val = NULL;
115  const char * get_env_error_str = NULL;
116 
117  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
118  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
119  RCL_CHECK_ARGUMENT_FOR_NULL(discovery_options, RCL_RET_INVALID_ARGUMENT);
120  RCL_CHECK_ARGUMENT_FOR_NULL(allocator, RCL_RET_INVALID_ARGUMENT);
121 
122  get_env_error_str = rcutils_get_env(RCL_STATIC_PEERS_ENV_VAR, &ros_peers_env_val);
123  if (NULL != get_env_error_str) {
124  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
125  "Error getting environment variable '%s': %s",
126  RCL_STATIC_PEERS_ENV_VAR, get_env_error_str);
127  return RCL_RET_ERROR;
128  }
129 
130  // The value of the env var should be at least "", even when not set.
131  if (NULL == ros_peers_env_val) {
132  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
133  "Environment variable value unexpectedly NULL when checking '%s'",
134  RCL_STATIC_PEERS_ENV_VAR);
135  return RCL_RET_ERROR;
136  }
137 
138  rcutils_string_array_t array = rcutils_get_zero_initialized_string_array();
139  rcutils_ret_t split_ret = rcutils_split(ros_peers_env_val, ';', *allocator, &array);
140  if (RCUTILS_RET_OK != split_ret) {
141  RCL_SET_ERROR_MSG(rcutils_get_error_string().str);
142  return RCL_RET_ERROR;
143  }
144 
145  rmw_ret_t rmw_ret = rmw_discovery_options_init(discovery_options, array.size, allocator);
146  if (RMW_RET_OK != rmw_ret) {
147  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
148  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
149  }
150 
151  for (size_t i = 0; i < array.size; ++i) {
152  if (strlen(array.data[i]) > (RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH - 1)) {
153  RCUTILS_LOG_WARN_NAMED(
154  ROS_PACKAGE_NAME,
155  "Static peer %s specified to '%s' is too long (maximum of %d); skipping",
156  array.data[i], RCL_STATIC_PEERS_ENV_VAR,
157  RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH - 1);
158  continue;
159  }
160 #ifdef _WIN32
161  strncpy_s(
162  discovery_options->static_peers[i].peer_address,
163  RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH,
164  array.data[i],
165  RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH);
166 #else
167  strncpy(
168  discovery_options->static_peers[i].peer_address,
169  array.data[i],
170  RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH);
171  discovery_options->static_peers[i].peer_address[
172  RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH - 1] = '\0';
173 #endif
174  }
175 
176  if (RCUTILS_RET_OK != rcutils_string_array_fini(&array)) {
177  RCL_SET_ERROR_MSG(rcutils_get_error_string().str);
178  return RCL_RET_ERROR;
179  }
180 
181  return RCL_RET_OK;
182 }
RCL_PUBLIC rcl_ret_t rcl_get_discovery_static_peers(rmw_discovery_options_t *discovery_options, rcutils_allocator_t *allocator)
Determine how the user wishes to discover other ROS nodes via statically-configured peers.
RCL_PUBLIC const char * rcl_automatic_discovery_range_to_string(rmw_automatic_discovery_range_t automatic_discovery_range)
Convert the automatic discovery range value to a string for easy printing.
RCL_PUBLIC rcl_ret_t rcl_get_automatic_discovery_range(rmw_discovery_options_t *discovery_options)
Determine how the user wishes to discover other ROS nodes automatically.
#define RCL_RET_OK
Success return code.
Definition: types.h:27
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:35
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:29
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24