1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "dms_packet.h"
17
18 #include <algorithm>
19 #include <cstdint>
20 #include <functional>
21 #include <limits>
22 #include <string>
23
24 namespace {
25 #define CHECK_BOUNDARY() \
26 if ((integerValue < std::numeric_limits<T>::min()) || (integerValue > std::numeric_limits<T>::max())) { \
27 printf("CHECK_BOUNDARY: bad boundary\n"); \
28 return false; \
29 }
30
31 constexpr uint8_t TLV_LENGTH_SHIFT_BITS = 7;
32 constexpr uint8_t LOW_BIT_MASK = 0x7F;
33 constexpr uint8_t HIGH_BIT_MASK = 0x80;
34 constexpr uint8_t BYTE_MASK = 0xFF;
35
36 constexpr uint8_t ONE_BYTE_BITS_NUM = 8;
37 constexpr uint8_t ONE_BYTE_LENGTH = 1;
38 constexpr uint8_t TYPE_FILED_LENGTH = 1;
39
40 constexpr uint8_t MIN_BYTE_NUM_OF_LENGTH_FILED = 1;
41 constexpr uint8_t MAX_BYTE_NUM_OF_LENGTH_FILED = 2;
42 }
43
DmsPacket(char * buffer,uint16_t bufferCapacity)44 DmsPacket::DmsPacket(char* buffer, uint16_t bufferCapacity)
45 : buffer_(buffer), bufferCapacity_(bufferCapacity), counter_(0) {}
46
BuildDmsPacket(const DmsMsgInfo & dmsMsgInfo,uint16_t & bufferSize)47 bool DmsPacket::BuildDmsPacket(const DmsMsgInfo& dmsMsgInfo, uint16_t& bufferSize)
48 {
49 bufferSize = 0;
50 if (buffer_ == nullptr || bufferCapacity_ > PACKET_DATA_SIZE) {
51 printf("DmsPacket:BuildDmsPacket bad parameters [bufferCapacity = %d]", bufferCapacity_);
52 return false;
53 }
54
55 if (!MarshallDmsMsgInfo(dmsMsgInfo)) {
56 printf("DmsPacket:MarshallDmsMsgInfo failed\n");
57 return false;
58 }
59
60 bufferSize = counter_;
61 return true;
62 }
63
MarshallStringField(const std::string & field,MSG_TYPE_SEQ type,uint16_t & dataLength)64 bool DmsPacket::MarshallStringField(const std::string& field, MSG_TYPE_SEQ type, uint16_t& dataLength)
65 {
66 if (field.empty()) {
67 return false;
68 }
69
70 // one more byte for '\0'
71 size_t sz = field.size() + 1;
72 uint8_t bytesNum = 0;
73 IntToHex<uint8_t>(static_cast<uint8_t>(type));
74 bytesNum = EncodeLengthOfTlv(sz);
75 dataLength += TYPE_FILED_LENGTH + bytesNum;
76 if (dataLength + sz > bufferCapacity_) {
77 printf("DmsPacket:MarshallStringField DmsMsgInfo is too big to fit\n");
78 return false;
79 }
80 StringToHex(field);
81 dataLength += sz;
82
83 return true;
84 }
85
MarshallDmsMsgInfo(const DmsMsgInfo & dmsMsgInfo)86 bool DmsPacket::MarshallDmsMsgInfo(const DmsMsgInfo& dmsMsgInfo)
87 {
88 uint16_t dataLength = 0;
89 uint8_t bytesNum = 0;
90
91 // marshall command id
92 IntToHex<uint8_t>(static_cast<uint8_t>(MSG_TYPE_SEQ::COMMAND_ID));
93 bytesNum = EncodeLengthOfTlv(ONE_BYTE_LENGTH);
94 IntToHex<uint8_t>(dmsMsgInfo.commandId);
95 dataLength += (TYPE_FILED_LENGTH + bytesNum + ONE_BYTE_LENGTH);
96
97 // marshall callee package name
98 if (!MarshallStringField(dmsMsgInfo.calleePkgName, MSG_TYPE_SEQ::CALLEE_PKG_NAME, dataLength)) {
99 return false;
100 }
101
102 // marshall callee ability name
103 if (!MarshallStringField(dmsMsgInfo.calleeAbilityName, MSG_TYPE_SEQ::CALLEE_ABILITY_NAME, dataLength)) {
104 return false;
105 }
106
107 // marshall caller signature
108 if (!MarshallStringField(dmsMsgInfo.callerSignature, MSG_TYPE_SEQ::CALLER_SIGNATURE, dataLength)) {
109 return false;
110 }
111
112 return true;
113 }
114
StringToHex(const std::string & stringValue)115 bool DmsPacket::StringToHex(const std::string& stringValue)
116 {
117 if (stringValue.empty()) {
118 return false;
119 }
120
121 for_each(std::begin(stringValue), std::end(stringValue), [this] (char ch) {
122 buffer_[counter_++] = ch;
123 });
124 buffer_[counter_++] = '\0';
125
126 return true;
127 }
128
129 template<typename T>
IntToHex(uint64_t integerValue)130 typename std::enable_if<std::is_unsigned<T>::value, bool>::type DmsPacket::IntToHex(uint64_t integerValue)
131 {
132 CHECK_BOUNDARY();
133 ToHex(integerValue, sizeof(T));
134 return true;
135 }
136
137 template<typename T>
IntToHex(int64_t integerValue)138 typename std::enable_if<std::is_signed<T>::value, bool>::type DmsPacket::IntToHex(int64_t integerValue)
139 {
140 CHECK_BOUNDARY();
141 ToHex(integerValue, sizeof(T));
142 return true;
143 }
144
EncodeLengthOfTlv(uint16_t length)145 uint8_t DmsPacket::EncodeLengthOfTlv(uint16_t length)
146 {
147 uint8_t bytesNum = MIN_BYTE_NUM_OF_LENGTH_FILED;
148 buffer_[counter_] = ((length >> TLV_LENGTH_SHIFT_BITS) & LOW_BIT_MASK);
149 if (buffer_[counter_]) {
150 buffer_[counter_++] |= HIGH_BIT_MASK;
151 buffer_[counter_++] = (length & LOW_BIT_MASK);
152 bytesNum = MAX_BYTE_NUM_OF_LENGTH_FILED;
153 } else {
154 buffer_[counter_++] = (length & LOW_BIT_MASK);
155 }
156
157 return bytesNum;
158 }
159
ToHex(uint64_t value,uint8_t typeSize)160 void DmsPacket::ToHex(uint64_t value, uint8_t typeSize)
161 {
162 for (int8_t i = typeSize - 1; i >= 0; i--) {
163 uint8_t val = (value >> (static_cast<uint8_t>(i) * ONE_BYTE_BITS_NUM)) & BYTE_MASK;
164 buffer_[counter_++] = val;
165 }
166 }
167