Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : * Copyright (c) 2016-2017 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file contains free functions for mapping OS and LwIP
22 : * stack-specific errors into CHIP System Layer-specific errors
23 : * and for converting those mapped errors into descriptive
24 : * error strings.
25 : */
26 :
27 : // Include module header
28 : #include <system/SystemError.h>
29 :
30 : #include <lib/core/ErrorStr.h>
31 : #include <lib/support/CHIPMemString.h>
32 : #include <lib/support/DLLUtil.h>
33 :
34 : #include <lib/core/CHIPConfig.h>
35 :
36 : // Include local headers
37 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
38 : #include <lwip/err.h>
39 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
40 :
41 : #include <limits>
42 : #include <stddef.h>
43 : #include <string.h>
44 :
45 : namespace chip {
46 : namespace System {
47 :
48 : namespace Internal {
49 : /**
50 : * This implements a mapping function for CHIP System Layer errors that allows mapping integers in the number space of the
51 : * underlying POSIX network and OS stack errors into a platform- or system-specific range. Error codes beyond those currently
52 : * defined by POSIX or the ISO C/C++ standards are mapped similar to the standard ones.
53 : *
54 : * @param[in] aError The POSIX network or OS error to map.
55 : *
56 : * @return The mapped POSIX network or OS error.
57 : */
58 : #if CHIP_CONFIG_ERROR_SOURCE && CHIP_CONFIG_ERROR_STD_SOURCE_LOCATION
59 : DLL_EXPORT CHIP_ERROR MapErrorPOSIX(int aError, std::source_location location)
60 : {
61 : return (aError == 0 ? CHIP_NO_ERROR
62 : : CHIP_ERROR(ChipError::Range::kPOSIX, static_cast<ChipError::ValueType>(aError), location));
63 : }
64 : #elif CHIP_CONFIG_ERROR_SOURCE
65 21874 : DLL_EXPORT CHIP_ERROR MapErrorPOSIX(int aError, const char * file, unsigned int line)
66 : {
67 : return (aError == 0 ? CHIP_NO_ERROR
68 21874 : : CHIP_ERROR(ChipError::Range::kPOSIX, static_cast<ChipError::ValueType>(aError), file, line));
69 : }
70 : #else
71 : DLL_EXPORT CHIP_ERROR MapErrorPOSIX(int aError)
72 : {
73 : return (aError == 0 ? CHIP_NO_ERROR : CHIP_ERROR(ChipError::Range::kPOSIX, static_cast<ChipError::ValueType>(aError)));
74 : }
75 : #endif
76 : } // namespace Internal
77 :
78 : /**
79 : * This implements a function to return an NULL-terminated OS-specific descriptive C string, associated with the specified, mapped
80 : * OS error.
81 : *
82 : * @param[in] aError The mapped OS-specific error to describe.
83 : *
84 : * @return A NULL-terminated, OS-specific descriptive C string describing the error.
85 : */
86 17 : DLL_EXPORT const char * DescribeErrorPOSIX(CHIP_ERROR aError)
87 : {
88 17 : const int lError = static_cast<int>(aError.GetValue());
89 : #if CHIP_SYSTEM_CONFIG_THREAD_LOCAL_STORAGE
90 : static thread_local char errBuf[128];
91 : #else
92 : static char errBuf[128];
93 : #endif // CHIP_SYSTEM_CONFIG_THREAD_LOCAL_STORAGE
94 :
95 : // Use thread-safe strerror_r when available
96 : #if defined(_GNU_SOURCE) && !defined(__ANDROID__)
97 : // GNU version returns char*
98 17 : const char * s = strerror_r(lError, errBuf, sizeof(errBuf));
99 17 : if (s != nullptr)
100 : {
101 17 : if (s != errBuf)
102 : {
103 17 : chip::Platform::CopyString(errBuf, sizeof(errBuf), s);
104 : }
105 17 : return errBuf;
106 : }
107 : #elif defined(_POSIX_C_SOURCE)
108 : // POSIX version returns int (0 on success)
109 : if (strerror_r(lError, errBuf, sizeof(errBuf)) == 0)
110 : {
111 : return errBuf;
112 : }
113 : #else
114 : // Fallback for platforms without strerror_r
115 : const char * s = strerror(lError);
116 : if (s != nullptr)
117 : {
118 : chip::Platform::CopyString(errBuf, sizeof(errBuf), s);
119 : return errBuf;
120 : }
121 : #endif
122 :
123 0 : return "Unknown POSIX error";
124 : }
125 :
126 : /**
127 : * Register a text error formatter for POSIX errors.
128 : */
129 121 : void RegisterPOSIXErrorFormatter()
130 : {
131 : static ErrorFormatter sPOSIXErrorFormatter = { FormatPOSIXError, nullptr };
132 : static bool sRegistered = false;
133 121 : if (sRegistered)
134 : {
135 58 : return;
136 : }
137 63 : RegisterErrorFormatter(&sPOSIXErrorFormatter);
138 63 : sRegistered = true;
139 : }
140 :
141 : /**
142 : * Given a POSIX error, returns a human-readable NULL-terminated C string
143 : * describing the error.
144 : *
145 : * @param[in] buf Buffer into which the error string will be placed.
146 : * @param[in] bufSize Size of the supplied buffer in bytes.
147 : * @param[in] err The error to be described.
148 : *
149 : * @return true If a description string was written into the supplied buffer.
150 : * @return false If the supplied error was not a POSIX error.
151 : *
152 : */
153 71 : bool FormatPOSIXError(char * buf, uint16_t bufSize, CHIP_ERROR err)
154 : {
155 71 : if (err.IsRange(ChipError::Range::kPOSIX))
156 : {
157 : const char * desc =
158 : #if CHIP_CONFIG_SHORT_ERROR_STR
159 : nullptr;
160 : #else
161 16 : DescribeErrorPOSIX(err);
162 : #endif
163 16 : FormatError(buf, bufSize, "OS", err, desc);
164 16 : return true;
165 : }
166 :
167 55 : return false;
168 : }
169 :
170 : /**
171 : * This implements a mapping function for CHIP System Layer errors that allows mapping integers in the number space of the
172 : * Zephyr OS user API stack errors into the POSIX range.
173 : *
174 : * @param[in] aError The native Zephyr API error to map.
175 : *
176 : * @return The mapped POSIX error.
177 : */
178 0 : DLL_EXPORT CHIP_ERROR MapErrorZephyr(int aError)
179 : {
180 0 : return Internal::MapErrorPOSIX(-aError CHIP_ERROR_SOURCE_LOCATION_NULL);
181 : }
182 :
183 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
184 :
185 : /**
186 : * This implements a mapping function for CHIP System Layer errors that allows mapping underlying LwIP network stack errors into a
187 : * platform- or system-specific range.
188 : *
189 : * @param[in] aError The LwIP error to map.
190 : *
191 : * @return The mapped LwIP network or OS error.
192 : *
193 : */
194 : DLL_EXPORT CHIP_ERROR MapErrorLwIP(err_t aError)
195 : {
196 : static_assert(ChipError::CanEncapsulate(-std::numeric_limits<err_t>::min()), "Can't represent all LWIP errors");
197 : return (aError == ERR_OK ? CHIP_NO_ERROR : CHIP_ERROR(ChipError::Range::kLwIP, static_cast<unsigned int>(-aError)));
198 : }
199 :
200 : /**
201 : * This implements a function to return an NULL-terminated LwIP-specific descriptive C string, associated with the specified,
202 : * mapped LwIP error.
203 : *
204 : * @param[in] aError The mapped LwIP-specific error to describe.
205 : *
206 : * @return A NULL-terminated, LwIP-specific descriptive C string describing the error.
207 : *
208 : */
209 : DLL_EXPORT const char * DescribeErrorLwIP(CHIP_ERROR aError)
210 : {
211 : if (!aError.IsRange(ChipError::Range::kLwIP))
212 : {
213 : return nullptr;
214 : }
215 :
216 : const err_t lError = static_cast<err_t>(-static_cast<err_t>(aError.GetValue()));
217 :
218 : // If we are not compiling with LWIP_DEBUG asserted, the unmapped
219 : // local value may go unused.
220 :
221 : (void) lError;
222 :
223 : return lwip_strerr(lError);
224 : }
225 :
226 : /**
227 : * Register a text error formatter for LwIP errors.
228 : */
229 : void RegisterLwIPErrorFormatter()
230 : {
231 : static ErrorFormatter sLwIPErrorFormatter = { FormatLwIPError, nullptr };
232 :
233 : RegisterErrorFormatter(&sLwIPErrorFormatter);
234 : }
235 :
236 : /**
237 : * Given an LwIP error, returns a human-readable NULL-terminated C string
238 : * describing the error.
239 : *
240 : * @param[in] buf Buffer into which the error string will be placed.
241 : * @param[in] bufSize Size of the supplied buffer in bytes.
242 : * @param[in] err The error to be described.
243 : *
244 : * @return true If a description string was written into the supplied buffer.
245 : * @return false If the supplied error was not an LwIP error.
246 : *
247 : */
248 : bool FormatLwIPError(char * buf, uint16_t bufSize, CHIP_ERROR err)
249 : {
250 : if (err.IsRange(ChipError::Range::kLwIP))
251 : {
252 : const char * desc =
253 : #if CHIP_CONFIG_SHORT_ERROR_STR
254 : nullptr;
255 : #else
256 : DescribeErrorLwIP(err);
257 : #endif
258 : chip::FormatError(buf, bufSize, "LwIP", err, desc);
259 : return true;
260 : }
261 : return false;
262 : }
263 :
264 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
265 :
266 : } // namespace System
267 : } // namespace chip
|