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 : CHIP_ERROR(ChipError::Range::kPOSIX, aError, location));
62 : }
63 : #elif CHIP_CONFIG_ERROR_SOURCE
64 22034 : DLL_EXPORT CHIP_ERROR MapErrorPOSIX(int aError, const char * file, unsigned int line)
65 : {
66 22034 : return (aError == 0 ? CHIP_NO_ERROR : CHIP_ERROR(ChipError::Range::kPOSIX, aError, file, line));
67 : }
68 : #else
69 : DLL_EXPORT CHIP_ERROR MapErrorPOSIX(int aError)
70 : {
71 : return (aError == 0 ? CHIP_NO_ERROR : CHIP_ERROR(ChipError::Range::kPOSIX, aError));
72 : }
73 : #endif
74 : } // namespace Internal
75 :
76 : /**
77 : * This implements a function to return an NULL-terminated OS-specific descriptive C string, associated with the specified, mapped
78 : * OS error.
79 : *
80 : * @param[in] aError The mapped OS-specific error to describe.
81 : *
82 : * @return A NULL-terminated, OS-specific descriptive C string describing the error.
83 : */
84 12 : DLL_EXPORT const char * DescribeErrorPOSIX(CHIP_ERROR aError)
85 : {
86 12 : const int lError = static_cast<int>(aError.GetValue());
87 : #if CHIP_SYSTEM_CONFIG_THREAD_LOCAL_STORAGE
88 : static thread_local char errBuf[128];
89 : #else
90 : static char errBuf[128];
91 : #endif // CHIP_SYSTEM_CONFIG_THREAD_LOCAL_STORAGE
92 :
93 : // Use thread-safe strerror_r when available
94 : #if defined(__GLIBC__) && defined(_GNU_SOURCE)
95 : // GNU version returns char*
96 12 : const char * s = strerror_r(lError, errBuf, sizeof(errBuf));
97 12 : if (s != nullptr)
98 : {
99 12 : return s; // errBuf or suitable glibc buffer
100 : }
101 : #elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)
102 : // POSIX version returns int (0 on success)
103 : if (strerror_r(lError, errBuf, sizeof(errBuf)) == 0)
104 : {
105 : return errBuf;
106 : }
107 : #else
108 : // Fallback for platforms without strerror_r
109 : const char * s = strerror(lError);
110 : if (s != nullptr)
111 : {
112 : chip::Platform::CopyString(errBuf, sizeof(errBuf), s);
113 : return errBuf;
114 : }
115 : #endif
116 :
117 0 : return "Unknown POSIX error";
118 : }
119 :
120 : /**
121 : * Register a text error formatter for POSIX errors.
122 : */
123 137 : void RegisterPOSIXErrorFormatter()
124 : {
125 : static ErrorFormatter sPOSIXErrorFormatter = { FormatPOSIXError, nullptr };
126 : static bool sRegistered = false;
127 137 : if (sRegistered)
128 : {
129 62 : return;
130 : }
131 75 : RegisterErrorFormatter(&sPOSIXErrorFormatter);
132 75 : sRegistered = true;
133 : }
134 :
135 : /**
136 : * Given a POSIX error, returns a human-readable NULL-terminated C string
137 : * describing the error.
138 : *
139 : * @param[in] buf Buffer into which the error string will be placed.
140 : * @param[in] bufSize Size of the supplied buffer in bytes.
141 : * @param[in] err The error to be described.
142 : *
143 : * @return true If a description string was written into the supplied buffer.
144 : * @return false If the supplied error was not a POSIX error.
145 : *
146 : */
147 63 : bool FormatPOSIXError(char * buf, uint16_t bufSize, CHIP_ERROR err)
148 : {
149 63 : if (err.IsRange(ChipError::Range::kPOSIX))
150 : {
151 : const char * desc =
152 : #if CHIP_CONFIG_SHORT_ERROR_STR
153 : nullptr;
154 : #else
155 11 : DescribeErrorPOSIX(err);
156 : #endif
157 11 : FormatError(buf, bufSize, "OS", err, desc);
158 11 : return true;
159 : }
160 :
161 52 : return false;
162 : }
163 :
164 : /**
165 : * This implements a mapping function for CHIP System Layer errors that allows mapping integers in the number space of the
166 : * Zephyr OS user API stack errors into the POSIX range.
167 : *
168 : * @param[in] aError The native Zephyr API error to map.
169 : *
170 : * @return The mapped POSIX error.
171 : */
172 0 : DLL_EXPORT CHIP_ERROR MapErrorZephyr(int aError)
173 : {
174 0 : return Internal::MapErrorPOSIX(-aError CHIP_ERROR_SOURCE_LOCATION_NULL);
175 : }
176 :
177 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
178 :
179 : /**
180 : * This implements a mapping function for CHIP System Layer errors that allows mapping underlying LwIP network stack errors into a
181 : * platform- or system-specific range.
182 : *
183 : * @param[in] aError The LwIP error to map.
184 : *
185 : * @return The mapped LwIP network or OS error.
186 : *
187 : */
188 : DLL_EXPORT CHIP_ERROR MapErrorLwIP(err_t aError)
189 : {
190 : static_assert(ChipError::CanEncapsulate(ChipError::Range::kLwIP, err_t{}), "Can't represent all LWIP errors");
191 : return (aError == ERR_OK ? CHIP_NO_ERROR : CHIP_ERROR(ChipError::Range::kLwIP, static_cast<int>(-aError)));
192 : }
193 :
194 : /**
195 : * This implements a function to return an NULL-terminated LwIP-specific descriptive C string, associated with the specified,
196 : * mapped LwIP error.
197 : *
198 : * @param[in] aError The mapped LwIP-specific error to describe.
199 : *
200 : * @return A NULL-terminated, LwIP-specific descriptive C string describing the error.
201 : *
202 : */
203 : DLL_EXPORT const char * DescribeErrorLwIP(CHIP_ERROR aError)
204 : {
205 : if (!aError.IsRange(ChipError::Range::kLwIP))
206 : {
207 : return nullptr;
208 : }
209 :
210 : const err_t lError = static_cast<err_t>(-static_cast<err_t>(aError.GetValue()));
211 :
212 : // If we are not compiling with LWIP_DEBUG asserted, the unmapped
213 : // local value may go unused.
214 :
215 : (void) lError;
216 :
217 : return lwip_strerr(lError);
218 : }
219 :
220 : /**
221 : * Register a text error formatter for LwIP errors.
222 : */
223 : void RegisterLwIPErrorFormatter()
224 : {
225 : static ErrorFormatter sLwIPErrorFormatter = { FormatLwIPError, nullptr };
226 :
227 : RegisterErrorFormatter(&sLwIPErrorFormatter);
228 : }
229 :
230 : /**
231 : * Given an LwIP error, returns a human-readable NULL-terminated C string
232 : * describing the error.
233 : *
234 : * @param[in] buf Buffer into which the error string will be placed.
235 : * @param[in] bufSize Size of the supplied buffer in bytes.
236 : * @param[in] err The error to be described.
237 : *
238 : * @return true If a description string was written into the supplied buffer.
239 : * @return false If the supplied error was not an LwIP error.
240 : *
241 : */
242 : bool FormatLwIPError(char * buf, uint16_t bufSize, CHIP_ERROR err)
243 : {
244 : if (err.IsRange(ChipError::Range::kLwIP))
245 : {
246 : const char * desc =
247 : #if CHIP_CONFIG_SHORT_ERROR_STR
248 : nullptr;
249 : #else
250 : DescribeErrorLwIP(err);
251 : #endif
252 : chip::FormatError(buf, bufSize, "LwIP", err, desc);
253 : return true;
254 : }
255 : return false;
256 : }
257 :
258 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
259 :
260 : } // namespace System
261 : } // namespace chip
|