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 : #include <algorithm>
26 : #include <app/AppConfig.h>
27 : #include <app/SpecificationDefinedRevisions.h>
28 : #include <app/util/basic-types.h>
29 : #include <inttypes.h>
30 : #include <lib/support/logging/CHIPLogging.h>
31 : #include <stdarg.h>
32 : #include <stdio.h>
33 :
34 : namespace chip {
35 : namespace app {
36 : #if CHIP_CONFIG_IM_PRETTY_PRINT && CHIP_DETAIL_LOGGING
37 : // this is used to run in signle thread for IM message debug purpose
38 : namespace {
39 : uint32_t gPrettyPrintingDepthLevel = 0;
40 : char gLineBuffer[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
41 : size_t gCurLineBufferSize = 0;
42 : } // namespace
43 :
44 368251 : void PrettyPrintIMBlankLine()
45 : {
46 368251 : if (gCurLineBufferSize)
47 : {
48 : // Don't need to explicitly NULL-terminate the string because
49 : // snprintf takes care of that.
50 360104 : ChipLogDetail(DataManagement, "%s", gLineBuffer);
51 360104 : gCurLineBufferSize = 0;
52 : }
53 :
54 1366625 : for (uint32_t i = 0; i < gPrettyPrintingDepthLevel; i++)
55 : {
56 998374 : if (sizeof(gLineBuffer) > gCurLineBufferSize)
57 : {
58 998374 : size_t sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
59 998374 : size_t ret = (size_t) (snprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, "\t"));
60 998374 : if (ret > 0)
61 : {
62 998374 : gCurLineBufferSize += std::min(ret, sizeLeft);
63 : }
64 : }
65 : }
66 368251 : }
67 :
68 1889204 : void PrettyPrintIM(bool aIsNewLine, const char * aFmt, ...)
69 : {
70 : va_list args;
71 1889204 : va_start(args, aFmt);
72 :
73 1889204 : if (aIsNewLine)
74 : {
75 329185 : PrettyPrintIMBlankLine();
76 : }
77 :
78 1889204 : if (sizeof(gLineBuffer) > gCurLineBufferSize)
79 : {
80 850414 : size_t sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
81 850414 : size_t ret = (size_t) (vsnprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, aFmt, args));
82 850414 : if (ret > 0)
83 : {
84 850414 : gCurLineBufferSize += std::min(ret, sizeLeft);
85 : }
86 : }
87 :
88 1889204 : va_end(args);
89 1889204 : }
90 88146 : void IncreaseDepth()
91 : {
92 88146 : gPrettyPrintingDepthLevel++;
93 88146 : }
94 :
95 88145 : void DecreaseDepth()
96 : {
97 88145 : gPrettyPrintingDepthLevel--;
98 88145 : }
99 : #endif
100 :
101 : #if CHIP_CONFIG_IM_PRETTY_PRINT
102 42406 : CHIP_ERROR CheckIMPayload(TLV::TLVReader & aReader, int aDepth, const char * aLabel)
103 : {
104 42406 : if (aDepth == 0)
105 : {
106 8554 : PRETTY_PRINT("%s = ", aLabel);
107 : }
108 : else
109 : {
110 33852 : if (TLV::IsContextTag(aReader.GetTag()))
111 : {
112 26951 : PRETTY_PRINT("0x%" PRIx32 " = ", TLV::TagNumFromTag(aReader.GetTag()));
113 : }
114 6901 : else if (TLV::IsProfileTag(aReader.GetTag()))
115 : {
116 0 : PRETTY_PRINT("0x%" PRIx32 "::0x%" PRIx32 " = ", TLV::ProfileIdFromTag(aReader.GetTag()),
117 : TLV::TagNumFromTag(aReader.GetTag()));
118 : }
119 : else
120 : {
121 : // Anonymous tag, don't print anything
122 : }
123 : }
124 :
125 42406 : switch (aReader.GetType())
126 : {
127 5389 : case TLV::kTLVType_Structure:
128 5389 : PRETTY_PRINT("{");
129 5389 : break;
130 :
131 5821 : case TLV::kTLVType_Array:
132 5821 : PRETTY_PRINT_SAMELINE("[");
133 5821 : PRETTY_PRINT("\t\t");
134 5821 : break;
135 :
136 90 : case TLV::kTLVType_SignedInteger: {
137 : int64_t value_s64;
138 :
139 90 : ReturnErrorOnFailure(aReader.Get(value_s64));
140 :
141 : // TODO: Figure out how to not use PRId64 here, since it's not supported
142 : // on all libcs.
143 90 : PRETTY_PRINT_SAMELINE("%" PRId64 " (signed), ", value_s64);
144 90 : break;
145 : }
146 :
147 16470 : case TLV::kTLVType_UnsignedInteger: {
148 : uint64_t value_u64;
149 :
150 16470 : ReturnErrorOnFailure(aReader.Get(value_u64));
151 :
152 : // TODO: Figure out how to not use PRIu64 here, since it's not supported
153 : // on all libcs.
154 16470 : PRETTY_PRINT_SAMELINE("%" PRIu64 " (unsigned), ", value_u64);
155 16470 : break;
156 : }
157 :
158 3254 : case TLV::kTLVType_FloatingPointNumber: {
159 : double value_fp;
160 :
161 3254 : ReturnErrorOnFailure(aReader.Get(value_fp));
162 :
163 3254 : PRETTY_PRINT_SAMELINE("%f, ", value_fp);
164 3254 : break;
165 : }
166 3343 : case TLV::kTLVType_Boolean: {
167 : bool value_b;
168 :
169 3343 : ReturnErrorOnFailure(aReader.Get(value_b));
170 :
171 3343 : PRETTY_PRINT_SAMELINE("%s, ", value_b ? "true" : "false");
172 3343 : break;
173 : }
174 :
175 1704 : case TLV::kTLVType_UTF8String: {
176 : char value_s[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
177 :
178 : #if CHIP_DETAIL_LOGGING
179 1704 : uint32_t readerLen = aReader.GetLength();
180 : #endif // CHIP_DETAIL_LOGGING
181 1704 : CHIP_ERROR err = aReader.GetString(value_s, sizeof(value_s));
182 1704 : VerifyOrReturnError(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, err);
183 :
184 1704 : if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
185 : {
186 0 : PRETTY_PRINT_SAMELINE("... (char string too long: %" PRIu32 " chars) ...", readerLen);
187 : }
188 : else
189 : {
190 1704 : PRETTY_PRINT_SAMELINE("\"%s\" (%" PRIu32 " chars), ", value_s, readerLen);
191 : }
192 1704 : break;
193 : }
194 :
195 6253 : case TLV::kTLVType_ByteString: {
196 : uint8_t value_b[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
197 : uint32_t len, readerLen;
198 :
199 6253 : readerLen = aReader.GetLength();
200 :
201 6253 : CHIP_ERROR err = aReader.GetBytes(value_b, sizeof(value_b));
202 6253 : VerifyOrReturnError(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, err);
203 :
204 6253 : PRETTY_PRINT_SAMELINE("[");
205 6253 : PRETTY_PRINT("\t\t");
206 :
207 6253 : if (readerLen < sizeof(value_b))
208 : {
209 6253 : len = readerLen;
210 : }
211 : else
212 : {
213 0 : len = sizeof(value_b);
214 : }
215 :
216 6253 : if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
217 : {
218 0 : PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
219 : }
220 : else
221 : {
222 1529255 : for (size_t i = 0; i < len; i++)
223 : {
224 1523002 : PRETTY_PRINT_SAMELINE("0x%02x, ", value_b[i]);
225 : }
226 : }
227 :
228 6253 : PRETTY_PRINT("] (%" PRIu32 " bytes)", readerLen);
229 6253 : break;
230 : }
231 :
232 82 : case TLV::kTLVType_Null:
233 82 : PRETTY_PRINT_SAMELINE("NULL");
234 82 : break;
235 :
236 0 : default:
237 0 : PRETTY_PRINT_SAMELINE("--");
238 0 : break;
239 : }
240 :
241 42406 : if (aReader.GetType() == TLV::kTLVType_Structure || aReader.GetType() == TLV::kTLVType_Array)
242 : {
243 11210 : const char terminating_char = (aReader.GetType() == TLV::kTLVType_Structure) ? '}' : ']';
244 : TLV::TLVType type;
245 :
246 : IgnoreUnusedVariable(terminating_char);
247 :
248 11210 : ReturnErrorOnFailure(aReader.EnterContainer(type));
249 :
250 : CHIP_ERROR err;
251 45062 : while ((err = aReader.Next()) == CHIP_NO_ERROR)
252 : {
253 33852 : PRETTY_PRINT_INCDEPTH();
254 :
255 33852 : ReturnErrorOnFailure(CheckIMPayload(aReader, aDepth + 1, aLabel));
256 :
257 33852 : PRETTY_PRINT_DECDEPTH();
258 : }
259 :
260 11210 : PRETTY_PRINT("%c,", terminating_char);
261 :
262 11210 : ReturnErrorOnFailure(aReader.ExitContainer(type));
263 : }
264 :
265 42406 : return CHIP_NO_ERROR;
266 : }
267 : #endif // CHIP_CONFIG_IM_PRETTY_PRINT
268 :
269 : }; // namespace app
270 : }; // namespace chip
|