Line data Source code
1 : /**
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2018 Google LLC.
5 : * Copyright (c) 2016-2017 Nest Labs, Inc.
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 : * @file
20 : * This file defines message helper functions in CHIP interaction model
21 : *
22 : */
23 :
24 : #include "MessageDefHelper.h"
25 :
26 : #include <algorithm>
27 : #include <app/AppConfig.h>
28 : #include <app/SpecificationDefinedRevisions.h>
29 : #include <app/util/basic-types.h>
30 : #include <lib/core/CHIPConfig.h>
31 : #include <lib/support/ScopedMemoryBuffer.h>
32 : #include <lib/support/logging/CHIPLogging.h>
33 :
34 : #include <cinttypes>
35 : #include <cstdarg>
36 : #include <cstdio>
37 :
38 : namespace chip {
39 : namespace app {
40 : #if CHIP_CONFIG_IM_PRETTY_PRINT && CHIP_DETAIL_LOGGING
41 : // this is used to run in signle thread for IM message debug purpose
42 : namespace {
43 : uint32_t gPrettyPrintingDepthLevel = 0;
44 : char gLineBuffer[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
45 : size_t gCurLineBufferSize = 0;
46 : } // namespace
47 :
48 526713 : void PrettyPrintIMBlankLine()
49 : {
50 526713 : if (gCurLineBufferSize)
51 : {
52 : // Don't need to explicitly NULL-terminate the string because
53 : // snprintf takes care of that.
54 514214 : ChipLogDetail(DataManagement, "%s", gLineBuffer);
55 514214 : gCurLineBufferSize = 0;
56 : }
57 :
58 1886711 : for (uint32_t i = 0; i < gPrettyPrintingDepthLevel; i++)
59 : {
60 1359998 : if (sizeof(gLineBuffer) > gCurLineBufferSize)
61 : {
62 1359998 : size_t sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
63 1359998 : size_t ret = (size_t) (snprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, "\t"));
64 1359998 : if (ret > 0)
65 : {
66 1359998 : gCurLineBufferSize += std::min(ret, sizeLeft);
67 : }
68 : }
69 : }
70 526713 : }
71 :
72 3511601 : void PrettyPrintIM(bool aIsNewLine, const char * aFmt, ...)
73 : {
74 : va_list args;
75 3511601 : va_start(args, aFmt);
76 :
77 3511601 : if (aIsNewLine)
78 : {
79 469054 : PrettyPrintIMBlankLine();
80 : }
81 :
82 3511601 : if (sizeof(gLineBuffer) > gCurLineBufferSize)
83 : {
84 1419416 : size_t sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
85 1419416 : size_t ret = (size_t) (vsnprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, aFmt, args));
86 1419416 : if (ret > 0)
87 : {
88 1419416 : gCurLineBufferSize += std::min(ret, sizeLeft);
89 : }
90 : }
91 :
92 3511601 : va_end(args);
93 3511601 : }
94 118594 : void IncreaseDepth()
95 : {
96 118594 : gPrettyPrintingDepthLevel++;
97 118594 : }
98 :
99 118593 : void DecreaseDepth()
100 : {
101 118593 : gPrettyPrintingDepthLevel--;
102 118593 : }
103 : #endif
104 :
105 : #if CHIP_CONFIG_IM_PRETTY_PRINT
106 :
107 52352 : CHIP_ERROR CheckIMPayload(TLV::TLVReader & aReader, int aDepth, const char * aLabel)
108 : {
109 : // do not allow fully unbounded recursion.
110 52352 : constexpr int kMaxRecursionDepth = 100;
111 :
112 52352 : if (aDepth > kMaxRecursionDepth)
113 : {
114 0 : PRETTY_PRINT("!!! RECURSION LIMIT REACHED !!!");
115 0 : return CHIP_ERROR_RECURSION_DEPTH_LIMIT;
116 : }
117 :
118 52352 : if (aDepth == 0)
119 : {
120 12112 : PRETTY_PRINT("%s = ", aLabel);
121 : }
122 : else
123 : {
124 40240 : if (TLV::IsContextTag(aReader.GetTag()))
125 : {
126 29405 : PRETTY_PRINT("0x%" PRIx32 " = ", TLV::TagNumFromTag(aReader.GetTag()));
127 : }
128 10835 : else if (TLV::IsProfileTag(aReader.GetTag()))
129 : {
130 0 : PRETTY_PRINT("0x%" PRIx32 "::0x%" PRIx32 " = ", TLV::ProfileIdFromTag(aReader.GetTag()),
131 : TLV::TagNumFromTag(aReader.GetTag()));
132 : }
133 : else
134 : {
135 : // Anonymous tag, don't print anything
136 : }
137 : }
138 :
139 52352 : switch (aReader.GetType())
140 : {
141 6602 : case TLV::kTLVType_Structure:
142 6602 : PRETTY_PRINT("{");
143 6602 : break;
144 :
145 7143 : case TLV::kTLVType_Array:
146 7143 : PRETTY_PRINT_SAMELINE("[");
147 7143 : PRETTY_PRINT("\t\t");
148 7143 : break;
149 :
150 94 : case TLV::kTLVType_SignedInteger: {
151 : int64_t value_s64;
152 :
153 94 : ReturnErrorOnFailure(aReader.Get(value_s64));
154 :
155 : // TODO: Figure out how to not use PRId64 here, since it's not supported
156 : // on all libcs.
157 94 : PRETTY_PRINT_SAMELINE("%" PRId64 " (signed), ", value_s64);
158 94 : break;
159 : }
160 :
161 18492 : case TLV::kTLVType_UnsignedInteger: {
162 : uint64_t value_u64;
163 :
164 18492 : ReturnErrorOnFailure(aReader.Get(value_u64));
165 :
166 : // TODO: Figure out how to not use PRIu64 here, since it's not supported
167 : // on all libcs.
168 18492 : PRETTY_PRINT_SAMELINE("%" PRIu64 " (unsigned), ", value_u64);
169 18492 : break;
170 : }
171 :
172 3266 : case TLV::kTLVType_FloatingPointNumber: {
173 : double value_fp;
174 :
175 3266 : ReturnErrorOnFailure(aReader.Get(value_fp));
176 :
177 3266 : PRETTY_PRINT_SAMELINE("%f, ", value_fp);
178 3266 : break;
179 : }
180 3361 : case TLV::kTLVType_Boolean: {
181 : bool value_b;
182 :
183 3361 : ReturnErrorOnFailure(aReader.Get(value_b));
184 :
185 3361 : PRETTY_PRINT_SAMELINE("%s, ", value_b ? "true" : "false");
186 3361 : break;
187 : }
188 :
189 1711 : case TLV::kTLVType_UTF8String: {
190 1711 : chip::Platform::ScopedMemoryBuffer<char> value_s;
191 1711 : VerifyOrReturnError(!value_s.Alloc(CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE).IsNull(), CHIP_ERROR_NO_MEMORY);
192 :
193 : #if CHIP_DETAIL_LOGGING
194 1711 : uint32_t readerLen = aReader.GetLength();
195 : #endif // CHIP_DETAIL_LOGGING
196 1711 : CHIP_ERROR err = aReader.GetString(value_s.Get(), CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE);
197 3422 : VerifyOrReturnError(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, err);
198 :
199 3422 : if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
200 : {
201 0 : PRETTY_PRINT_SAMELINE("... (char string too long: %" PRIu32 " chars) ...", readerLen);
202 : }
203 : else
204 : {
205 1711 : PRETTY_PRINT_SAMELINE("\"%s\" (%" PRIu32 " chars), ", value_s.Get(), readerLen);
206 : }
207 1711 : break;
208 1711 : }
209 :
210 11479 : case TLV::kTLVType_ByteString: {
211 11479 : chip::Platform::ScopedMemoryBuffer<uint8_t> value_b;
212 11479 : VerifyOrReturnError(!value_b.Alloc(CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE).IsNull(), CHIP_ERROR_NO_MEMORY);
213 :
214 11479 : uint32_t readerLen = aReader.GetLength();
215 :
216 11479 : CHIP_ERROR err = aReader.GetBytes(value_b.Get(), CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE);
217 22958 : VerifyOrReturnError(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, err);
218 :
219 11479 : PRETTY_PRINT_SAMELINE("[");
220 11479 : PRETTY_PRINT("\t\t");
221 :
222 22958 : if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
223 : {
224 0 : PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
225 : }
226 : else
227 : {
228 11479 : const uint32_t len = std::min(readerLen, static_cast<uint32_t>(CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE));
229 3008276 : for (size_t i = 0; i < len; i++)
230 : {
231 2996797 : PRETTY_PRINT_SAMELINE("0x%02x, ", value_b[i]);
232 : }
233 : }
234 :
235 11479 : PRETTY_PRINT("] (%" PRIu32 " bytes)", readerLen);
236 11479 : break;
237 11479 : }
238 :
239 204 : case TLV::kTLVType_Null:
240 204 : PRETTY_PRINT_SAMELINE("NULL");
241 204 : break;
242 :
243 0 : default:
244 0 : PRETTY_PRINT_SAMELINE("--");
245 0 : break;
246 : }
247 :
248 52352 : if (aReader.GetType() == TLV::kTLVType_Structure || aReader.GetType() == TLV::kTLVType_Array)
249 : {
250 13745 : const char terminating_char = (aReader.GetType() == TLV::kTLVType_Structure) ? '}' : ']';
251 : TLV::TLVType type;
252 :
253 : IgnoreUnusedVariable(terminating_char);
254 :
255 13745 : ReturnErrorOnFailure(aReader.EnterContainer(type));
256 :
257 : CHIP_ERROR err;
258 107970 : while ((err = aReader.Next()) == CHIP_NO_ERROR)
259 : {
260 40240 : PRETTY_PRINT_INCDEPTH();
261 :
262 40240 : ReturnErrorOnFailure(CheckIMPayload(aReader, aDepth + 1, aLabel));
263 :
264 40240 : PRETTY_PRINT_DECDEPTH();
265 : }
266 :
267 13745 : PRETTY_PRINT("%c,", terminating_char);
268 :
269 13745 : ReturnErrorOnFailure(aReader.ExitContainer(type));
270 : }
271 :
272 52352 : return CHIP_NO_ERROR;
273 : }
274 : #endif // CHIP_CONFIG_IM_PRETTY_PRINT
275 :
276 : }; // namespace app
277 : }; // namespace chip
|