ROS 2 rclcpp + rcl - rolling  rolling-a919a6e5
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 const char *
90 rcl_automatic_discovery_range_to_string(rmw_automatic_discovery_range_t automatic_discovery_range)
91 {
92  switch (automatic_discovery_range) {
93  case RMW_AUTOMATIC_DISCOVERY_RANGE_NOT_SET:
94  return "RMW_AUTOMATIC_DISCOVERY_RANGE_NOT_SET";
95  case RMW_AUTOMATIC_DISCOVERY_RANGE_OFF:
96  return "RMW_AUTOMATIC_DISCOVERY_RANGE_OFF";
97  case RMW_AUTOMATIC_DISCOVERY_RANGE_LOCALHOST:
98  return "RMW_AUTOMATIC_DISCOVERY_RANGE_LOCALHOST";
99  case RMW_AUTOMATIC_DISCOVERY_RANGE_SUBNET:
100  return "RMW_AUTOMATIC_DISCOVERY_RANGE_SUBNET";
101  case RMW_AUTOMATIC_DISCOVERY_RANGE_SYSTEM_DEFAULT:
102  return "RMW_AUTOMATIC_DISCOVERY_RANGE_SYSTEM_DEFAULT";
103  default:
104  return NULL;
105  }
106 }
107 
108 rcl_ret_t
110  rmw_discovery_options_t * discovery_options,
111  rcutils_allocator_t * allocator)
112 {
113  const char * ros_peers_env_val = NULL;
114  const char * get_env_error_str = NULL;
115 
116  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
117  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
118  RCL_CHECK_ARGUMENT_FOR_NULL(discovery_options, RCL_RET_INVALID_ARGUMENT);
119  RCL_CHECK_ARGUMENT_FOR_NULL(allocator, RCL_RET_INVALID_ARGUMENT);
120 
121  get_env_error_str = rcutils_get_env(RCL_STATIC_PEERS_ENV_VAR, &ros_peers_env_val);
122  if (NULL != get_env_error_str) {
123  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
124  "Error getting environment variable '%s': %s",
125  RCL_STATIC_PEERS_ENV_VAR, get_env_error_str);
126  return RCL_RET_ERROR;
127  }
128 
129  // The value of the env var should be at least "", even when not set.
130  if (NULL == ros_peers_env_val) {
131  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
132  "Environment variable value unexpectedly NULL when checking '%s'",
133  RCL_STATIC_PEERS_ENV_VAR);
134  return RCL_RET_ERROR;
135  }
136 
137  rcutils_string_array_t array = rcutils_get_zero_initialized_string_array();
138  rcutils_ret_t split_ret = rcutils_split(ros_peers_env_val, ';', *allocator, &array);
139  if (RCUTILS_RET_OK != split_ret) {
140  RCL_SET_ERROR_MSG(rcutils_get_error_string().str);
141  return RCL_RET_ERROR;
142  }
143 
144  rmw_ret_t rmw_ret = rmw_discovery_options_init(discovery_options, array.size, allocator);
145  if (RMW_RET_OK != rmw_ret) {
146  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
147  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
148  }
149 
150  for (size_t i = 0; i < array.size; ++i) {
151  if (strlen(array.data[i]) > (RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH - 1)) {
152  RCUTILS_LOG_WARN_NAMED(
153  ROS_PACKAGE_NAME,
154  "Static peer %s specified to '%s' is too long (maximum of %d); skipping",
155  array.data[i], RCL_STATIC_PEERS_ENV_VAR,
156  RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH - 1);
157  continue;
158  }
159 #ifdef _WIN32
160  strncpy_s(
161  discovery_options->static_peers[i].peer_address,
162  RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH,
163  array.data[i],
164  RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH);
165 #else
166  strncpy(
167  discovery_options->static_peers[i].peer_address,
168  array.data[i],
169  RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH);
170  discovery_options->static_peers[i].peer_address[
171  RMW_DISCOVERY_OPTIONS_STATIC_PEERS_MAX_LENGTH - 1] = '\0';
172 #endif
173  }
174 
175  if (RCUTILS_RET_OK != rcutils_string_array_fini(&array)) {
176  RCL_SET_ERROR_MSG(rcutils_get_error_string().str);
177  return RCL_RET_ERROR;
178  }
179 
180  return RCL_RET_OK;
181 }
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