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 368060 : void PrettyPrintIMBlankLine()
45 : {
46 368060 : if (gCurLineBufferSize)
47 : {
48 : // Don't need to explicitly NULL-terminate the string because
49 : // snprintf takes care of that.
50 360177 : ChipLogDetail(DataManagement, "%s", gLineBuffer);
51 360177 : gCurLineBufferSize = 0;
52 : }
53 :
54 1382858 : for (uint32_t i = 0; i < gPrettyPrintingDepthLevel; i++)
55 : {
56 1014798 : if (sizeof(gLineBuffer) > gCurLineBufferSize)
57 : {
58 1014798 : size_t sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
59 1014798 : size_t ret = (size_t) (snprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, "\t"));
60 1014798 : if (ret > 0)
61 : {
62 1014798 : gCurLineBufferSize += std::min(ret, sizeLeft);
63 : }
64 : }
65 : }
66 368060 : }
67 :
68 1888965 : void PrettyPrintIM(bool aIsNewLine, const char * aFmt, ...)
69 : {
70 : va_list args;
71 1888965 : va_start(args, aFmt);
72 :
73 1888965 : if (aIsNewLine)
74 : {
75 329214 : PrettyPrintIMBlankLine();
76 : }
77 :
78 1888965 : if (sizeof(gLineBuffer) > gCurLineBufferSize)
79 : {
80 850175 : size_t sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
81 850175 : size_t ret = (size_t) (vsnprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, aFmt, args));
82 850175 : if (ret > 0)
83 : {
84 850175 : gCurLineBufferSize += std::min(ret, sizeLeft);
85 : }
86 : }
87 :
88 1888965 : va_end(args);
89 1888965 : }
90 88339 : void IncreaseDepth()
91 : {
92 88339 : gPrettyPrintingDepthLevel++;
93 88339 : }
94 :
95 88338 : void DecreaseDepth()
96 : {
97 88338 : gPrettyPrintingDepthLevel--;
98 88338 : }
99 : #endif
100 :
101 : #if CHIP_CONFIG_IM_PRETTY_PRINT
102 42754 : CHIP_ERROR CheckIMPayload(TLV::TLVReader & aReader, int aDepth, const char * aLabel)
103 : {
104 42754 : if (aDepth == 0)
105 : {
106 8236 : PRETTY_PRINT("%s = ", aLabel);
107 : }
108 : else
109 : {
110 34518 : if (TLV::IsContextTag(aReader.GetTag()))
111 : {
112 28183 : PRETTY_PRINT("0x%" PRIx32 " = ", TLV::TagNumFromTag(aReader.GetTag()));
113 : }
114 6335 : 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 42754 : switch (aReader.GetType())
126 : {
127 6005 : case TLV::kTLVType_Structure:
128 6005 : PRETTY_PRINT("{");
129 6005 : break;
130 :
131 5507 : case TLV::kTLVType_Array:
132 5507 : PRETTY_PRINT_SAMELINE("[");
133 5507 : PRETTY_PRINT("\t\t");
134 5507 : 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 15900 : case TLV::kTLVType_UnsignedInteger: {
148 : uint64_t value_u64;
149 :
150 15900 : 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 15900 : PRETTY_PRINT_SAMELINE("%" PRIu64 " (unsigned), ", value_u64);
155 15900 : 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 6869 : case TLV::kTLVType_ByteString: {
196 : uint8_t value_b[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
197 : uint32_t len, readerLen;
198 :
199 6869 : readerLen = aReader.GetLength();
200 :
201 6869 : CHIP_ERROR err = aReader.GetBytes(value_b, sizeof(value_b));
202 6869 : VerifyOrReturnError(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, err);
203 :
204 6869 : PRETTY_PRINT_SAMELINE("[");
205 6869 : PRETTY_PRINT("\t\t");
206 :
207 6869 : if (readerLen < sizeof(value_b))
208 : {
209 6869 : len = readerLen;
210 : }
211 : else
212 : {
213 0 : len = sizeof(value_b);
214 : }
215 :
216 6869 : if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
217 : {
218 0 : PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
219 : }
220 : else
221 : {
222 1529871 : for (size_t i = 0; i < len; i++)
223 : {
224 1523002 : PRETTY_PRINT_SAMELINE("0x%02x, ", value_b[i]);
225 : }
226 : }
227 :
228 6869 : PRETTY_PRINT("] (%" PRIu32 " bytes)", readerLen);
229 6869 : 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 42754 : if (aReader.GetType() == TLV::kTLVType_Structure || aReader.GetType() == TLV::kTLVType_Array)
242 : {
243 11512 : const char terminating_char = (aReader.GetType() == TLV::kTLVType_Structure) ? '}' : ']';
244 : TLV::TLVType type;
245 :
246 : IgnoreUnusedVariable(terminating_char);
247 :
248 11512 : ReturnErrorOnFailure(aReader.EnterContainer(type));
249 :
250 : CHIP_ERROR err;
251 46030 : while ((err = aReader.Next()) == CHIP_NO_ERROR)
252 : {
253 34518 : PRETTY_PRINT_INCDEPTH();
254 :
255 34518 : ReturnErrorOnFailure(CheckIMPayload(aReader, aDepth + 1, aLabel));
256 :
257 34518 : PRETTY_PRINT_DECDEPTH();
258 : }
259 :
260 11512 : PRETTY_PRINT("%c,", terminating_char);
261 :
262 11512 : ReturnErrorOnFailure(aReader.ExitContainer(type));
263 : }
264 :
265 42754 : return CHIP_NO_ERROR;
266 : }
267 : #endif // CHIP_CONFIG_IM_PRETTY_PRINT
268 :
269 : }; // namespace app
270 : }; // namespace chip
|