ROS 2 rclcpp + rcl - rolling  rolling-e7363f10
ROS 2 C++ Client Library with ROS Client Library
rmw_implementation_identifier_check.c
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 #ifdef __cplusplus
16 extern "C"
17 {
18 #endif
19 
20 #include <stddef.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "rcl/allocator.h"
25 #include "rcl/error_handling.h"
26 #include "rcutils/env.h"
27 #include "rcutils/error_handling.h"
28 #include "rcutils/logging_macros.h"
29 #include "rcutils/strdup.h"
30 #include "rmw/rmw.h"
31 
32 #include "rcl/types.h"
33 
35 
36 // *INDENT-OFF*
37 
38 // Extracted this portable method of doing a "shared library constructor" from SO:
39 // http://stackoverflow.com/a/2390626/671658
40 // Initializer/finalizer sample for MSVC and GCC/Clang.
41 // 2010-2016 Joe Lowe. Released into the public domain.
42 #if defined(_MSC_VER)
43  #pragma section(".CRT$XCU", read)
44  #define INITIALIZER2_(f, p) \
45  static void f(void); \
46  __declspec(allocate(".CRT$XCU"))void(*f ## _)(void) = f; \
47  __pragma(comment(linker, "/include:" p #f "_")) \
48  static void f(void)
49  #ifdef _WIN64
50  #define INITIALIZER(f) INITIALIZER2_(f, "")
51  #else
52  #define INITIALIZER(f) INITIALIZER2_(f, "_")
53  #endif
54 #else
55  #define INITIALIZER(f) \
56  static void f(void) __attribute__((constructor)); \
57  static void f(void)
58 #endif
59 
60 // *INDENT-ON*
61 
63 {
64  // If the environment variable RMW_IMPLEMENTATION is set, or
65  // the environment variable RCL_ASSERT_RMW_ID_MATCHES is set,
66  // check that the result of `rmw_get_implementation_identifier` matches.
67  rcl_ret_t ret = RCL_RET_OK;
69  char * expected_rmw_impl = NULL;
70  const char * expected_rmw_impl_env = NULL;
71  const char * get_env_error_str = rcutils_get_env(
73  &expected_rmw_impl_env);
74  if (NULL != get_env_error_str) {
75  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
76  "Error getting env var '" RCUTILS_STRINGIFY(RMW_IMPLEMENTATION_ENV_VAR_NAME) "': %s\n",
77  get_env_error_str);
78  return RCL_RET_ERROR;
79  }
80  if (strlen(expected_rmw_impl_env) > 0) {
81  // Copy the environment variable so it doesn't get over-written by the next getenv call.
82  expected_rmw_impl = rcutils_strdup(expected_rmw_impl_env, allocator);
83  if (!expected_rmw_impl) {
84  RCL_SET_ERROR_MSG("allocation failed");
85  return RCL_RET_BAD_ALLOC;
86  }
87  }
88 
89  char * asserted_rmw_impl = NULL;
90  const char * asserted_rmw_impl_env = NULL;
91  get_env_error_str = rcutils_get_env(
92  RCL_ASSERT_RMW_ID_MATCHES_ENV_VAR_NAME, &asserted_rmw_impl_env);
93  if (NULL != get_env_error_str) {
94  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
95  "Error getting env var '"
96  RCUTILS_STRINGIFY(RCL_ASSERT_RMW_ID_MATCHES_ENV_VAR_NAME) "': %s\n",
97  get_env_error_str);
98  ret = RCL_RET_ERROR;
99  goto cleanup;
100  }
101  if (strlen(asserted_rmw_impl_env) > 0) {
102  // Copy the environment variable so it doesn't get over-written by the next getenv call.
103  asserted_rmw_impl = rcutils_strdup(asserted_rmw_impl_env, allocator);
104  if (!asserted_rmw_impl) {
105  RCL_SET_ERROR_MSG("allocation failed");
106  ret = RCL_RET_BAD_ALLOC;
107  goto cleanup;
108  }
109  }
110 
111  // If both environment variables are set, and they do not match, print an error and exit.
112  if (expected_rmw_impl && asserted_rmw_impl && strcmp(expected_rmw_impl, asserted_rmw_impl) != 0) {
113  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
114  "Values of RMW_IMPLEMENTATION ('%s') and RCL_ASSERT_RMW_ID_MATCHES ('%s') environment "
115  "variables do not match, exiting with %d.",
116  expected_rmw_impl, asserted_rmw_impl, RCL_RET_ERROR
117  );
118  ret = RCL_RET_ERROR;
119  goto cleanup;
120  }
121 
122  // Collapse the expected_rmw_impl and asserted_rmw_impl variables so only expected_rmw_impl needs
123  // to be used from now on.
124  if (expected_rmw_impl && asserted_rmw_impl) {
125  // The strings at this point must be equal.
126  // No need for asserted_rmw_impl anymore, free the memory.
127  allocator.deallocate(asserted_rmw_impl, allocator.state);
128  asserted_rmw_impl = NULL;
129  } else {
130  // One or none are set.
131  // If asserted_rmw_impl has contents, move it over to expected_rmw_impl.
132  if (asserted_rmw_impl) {
133  expected_rmw_impl = asserted_rmw_impl;
134  asserted_rmw_impl = NULL;
135  }
136  }
137 
138  // If either environment variable is set, and it does not match, print an error and exit.
139  if (expected_rmw_impl) {
140  const char * actual_rmw_impl_id = rmw_get_implementation_identifier();
141  const rcutils_error_string_t rmw_error_msg = rcl_get_error_string();
142  rcl_reset_error();
143  if (!actual_rmw_impl_id) {
144  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
145  "Error getting RMW implementation identifier / RMW implementation not installed "
146  "(expected identifier of '%s'), with error message '%s', exiting with %d.",
147  expected_rmw_impl,
148  rmw_error_msg.str,
150  );
151  ret = RCL_RET_ERROR;
152  goto cleanup;
153  }
154  if (strcmp(actual_rmw_impl_id, expected_rmw_impl) != 0) {
155  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
156  "Expected RMW implementation identifier of '%s' but instead found '%s', exiting with %d.",
157  expected_rmw_impl,
158  actual_rmw_impl_id,
160  );
162  goto cleanup;
163  }
164  }
165  ret = RCL_RET_OK;
166 // fallthrough
167 cleanup:
168  allocator.deallocate(expected_rmw_impl, allocator.state);
169  allocator.deallocate(asserted_rmw_impl, allocator.state);
170  return ret;
171 }
172 
173 INITIALIZER(initialize) {
175  if (ret != RCL_RET_OK) {
176  RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "%s\n", rcl_get_error_string().str);
177  exit(ret);
178  }
179 }
180 
181 #ifdef __cplusplus
182 }
183 #endif
#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
#define RMW_IMPLEMENTATION_ENV_VAR_NAME
The environment variable name to control which RMW implementation is used.
#define RCL_ASSERT_RMW_ID_MATCHES_ENV_VAR_NAME
RCL_PUBLIC rcl_ret_t rcl_rmw_implementation_identifier_check(void)
Check whether the RMW implementation in use matches what the user requested.
#define RCL_RET_OK
Success return code.
Definition: types.h:28
#define RCL_RET_BAD_ALLOC
Failed to allocate memory return code.
Definition: types.h:34
#define RCL_RET_MISMATCHED_RMW_ID
Mismatched rmw identifier return code.
Definition: types.h:46
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:30
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:25