Change script for apply upstream code
[platform/upstream/connectedhomeip.git] / examples / common / chip-app-server / DataModelHandler.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *
5  *    Licensed under the Apache License, Version 2.0 (the "License");
6  *    you may not use this file except in compliance with the License.
7  *    You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *    Unless required by applicable law or agreed to in writing, software
12  *    distributed under the License is distributed on an "AS IS" BASIS,
13  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *    See the License for the specific language governing permissions and
15  *    limitations under the License.
16  */
17
18 /**
19  * @file
20  *   This file implements the handler for data model messages.
21  */
22
23 #include "DataModelHandler.h"
24
25 #include <app/chip-zcl-zpro-codec.h>
26 #include <app/util/af-types.h>
27 #include <app/util/attribute-storage.h>
28 #include <app/util/util.h>
29 #include <lib/support/logging/CHIPLogging.h>
30 #include <support/logging/CHIPLogging.h>
31 #include <system/SystemPacketBuffer.h>
32
33 using namespace ::chip;
34
35 /**
36  * A data model message has nonzero length and always has a first byte whose
37  * value is one of: 0x00, 0x01, 0x02, 0x03.  See chipZclEncodeZclHeader for the
38  * construction of the message and in particular the first byte.
39  *
40  * Echo messages should generally not have a first byte with those values, so we
41  * can use that to try to distinguish between the two.
42  */
43 bool ContentMayBeADataModelMessage(const System::PacketBufferHandle & buffer)
44 {
45     const size_t data_len      = buffer->DataLength();
46     const uint8_t * data       = buffer->Start();
47     bool maybeDataModelMessage = true;
48
49     // Has to have nonzero length.
50     VerifyOrExit(data_len > 0, maybeDataModelMessage = false);
51
52     // Has to have a valid first byte value.
53     VerifyOrExit(data[0] < 0x04, maybeDataModelMessage = false);
54
55 exit:
56     return maybeDataModelMessage;
57 }
58
59 /**
60  * @brief implements something like "od -c", changes an arbitrary byte string
61  *   into a single-line of ascii.  Destroys any byte-wise encoding that
62  *   might be present, e.g. utf-8.
63  *
64  * @param bytes     potentially unprintable buffer
65  * @param bytes_len length of bytes
66  * @param out       where to put the printable string
67  * @param out_len   length of out
68  * @return size_t required size of output buffer, including null-termination
69  */
70 static size_t BinaryBytesToPrintableString(const uint8_t * bytes, size_t bytes_len, char * out, size_t out_len)
71 {
72     size_t required = 1; // always need null termination
73     memset(out, 0, out_len);
74     // count and print
75     for (; bytes_len > 0; bytes_len--, bytes++)
76     {
77         uint8_t byte = *bytes;
78
79         if ((byte >= '\t' && byte <= '\r') || byte == '\\')
80         {
81             static const char * kCodes = "tnvfr";
82             char code                  = (byte == '\\') ? '\\' : kCodes[byte - '\t'];
83             required += 2;
84             if (out_len > 2)
85             {
86                 *out++ = '\\';
87                 *out++ = code;
88                 out_len -= 2;
89             }
90         }
91         else if (byte >= ' ' && byte <= '~')
92         {
93             required += 1;
94             if (out_len > 1)
95             {
96                 *out++ = byte;
97                 out_len--;
98             }
99         }
100         else
101         {
102             static const size_t kBinCodeLen = sizeof("\\xFF") - 1;
103             static const char * kCodes      = "0123456789ABCDEF";
104
105             required += kBinCodeLen;
106             if (out_len > kBinCodeLen)
107             {
108                 *out++ = '\\';
109                 *out++ = 'x';
110                 *out++ = kCodes[(byte & 0xf0) >> 4];
111                 *out++ = kCodes[byte & 0xf];
112                 out_len -= kBinCodeLen;
113             }
114         }
115     }
116
117     return required;
118 }
119
120 void ProcessOthersMessage(const PacketHeader & header, System::PacketBufferHandle & buffer, SecureSessionMgr * mgr)
121 {
122     CHIP_ERROR err;
123     char logmsg[512];
124
125     BinaryBytesToPrintableString(buffer->Start(), buffer->DataLength(), logmsg, sizeof(logmsg));
126
127     ChipLogProgress(AppServer, "Client sent: %s", logmsg);
128
129     // Attempt to echo back
130     err = mgr->SendMessage(header.GetSourceNodeId().Value(), std::move(buffer));
131     if (err != CHIP_NO_ERROR)
132     {
133         ChipLogProgress(AppServer, "Unable to echo back to client: %s", ErrorStr(err));
134     }
135     else
136     {
137         ChipLogProgress(AppServer, "Echo sent");
138     }
139 }
140
141 void ProcessDataModelMessage(const PacketHeader & header, System::PacketBufferHandle & buffer)
142 {
143     EmberApsFrame frame;
144     bool ok = extractApsFrame(buffer->Start(), buffer->DataLength(), &frame) > 0;
145     if (ok)
146     {
147         ChipLogProgress(Zcl, "APS frame processing success!");
148     }
149     else
150     {
151         ChipLogProgress(Zcl, "APS frame processing failure!");
152         return;
153     }
154
155     uint8_t * message;
156     uint16_t messageLen = extractMessage(buffer->Start(), buffer->DataLength(), &message);
157     ok                  = emberAfProcessMessage(&frame,
158                                0, // type
159                                message, messageLen,
160                                header.GetSourceNodeId().Value(), // source identifier
161                                NULL);
162
163     if (ok)
164     {
165         ChipLogProgress(Zcl, "Data model processing success!");
166     }
167     else
168     {
169         ChipLogProgress(Zcl, "Data model processing failure!");
170     }
171 }
172
173 /**
174  * Handle a message that should be processed via our data model processing
175  * codepath. This function will free the packet buffer.
176  *
177  * @param [in] buffer The buffer holding the message.  This function guarantees
178  *                    that it will free the buffer before returning.
179  */
180 void HandleDataModelMessage(const PacketHeader & header, System::PacketBufferHandle buffer, SecureSessionMgr * mgr)
181 {
182     // FIXME: Long-term we shouldn't be guessing what sort of message this is
183     // based on the message bytes.  We're doing this for now to support both
184     // data model messages and text echo messages, but in the long term we
185     // should either do echo via a data model command or do echo on a separate
186     // port from data model processing.
187     if (ContentMayBeADataModelMessage(buffer))
188     {
189         ProcessDataModelMessage(header, buffer);
190     }
191     else
192     {
193         ProcessOthersMessage(header, buffer, mgr);
194     }
195 }
196
197 void InitDataModelHandler()
198 {
199     emberAfEndpointConfigure();
200     emberAfInit();
201 }