1 /*
2 * Copyright (c) 2022 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 #include "route_head_handler_impl.h"
16
17 #define LOG_TAG "RouteHeadHandler"
18 #include <chrono>
19 #include <cinttypes>
20 #include "auth_delegate.h"
21 #include "device_manager_adapter.h"
22 #include "kvstore_meta_manager.h"
23 #include "log_print.h"
24 #include "metadata/meta_data_manager.h"
25 #include "metadata/store_meta_data.h"
26 #include "securec.h"
27 #include "upgrade_manager.h"
28 #include "bootstrap.h"
29 #include "utils/anonymous.h"
30 #include "utils/endian_converter.h"
31
32 namespace OHOS::DistributedData {
33 using namespace OHOS::DistributedKv;
34 using namespace std::chrono;
35 using DmAdapter = DistributedData::DeviceManagerAdapter;
36 constexpr const int ALIGN_WIDTH = 8;
Create(const ExtendInfo & info)37 std::shared_ptr<RouteHeadHandler> RouteHeadHandlerImpl::Create(const ExtendInfo &info)
38 {
39 auto handler = std::make_shared<RouteHeadHandlerImpl>(info);
40 if (handler == nullptr) {
41 ZLOGE("new instance failed");
42 return nullptr;
43 }
44 handler->Init();
45 return handler;
46 }
47
RouteHeadHandlerImpl(const ExtendInfo & info)48 RouteHeadHandlerImpl::RouteHeadHandlerImpl(const ExtendInfo &info)
49 : userId_(info.userId), appId_(info.appId), storeId_(info.storeId), deviceId_(info.dstTarget), headSize_(0)
50 {
51 ZLOGD("init route handler, app:%{public}s, user:%{public}s, peer:%{public}s", appId_.c_str(), userId_.c_str(),
52 Anonymous::Change(deviceId_).c_str());
53 }
54
Init()55 void RouteHeadHandlerImpl::Init()
56 {
57 ZLOGD("begin");
58 if (deviceId_.empty()) {
59 return;
60 }
61 SessionPoint localPoint { DmAdapter::GetInstance().GetLocalDevice().uuid,
62 static_cast<uint32_t>(atoi(userId_.c_str())), appId_, storeId_ };
63 session_ = SessionManager::GetInstance().GetSession(localPoint, deviceId_);
64 ZLOGD("valid session:appId:%{public}s, srcDevId:%{public}s, srcUser:%{public}u, trgDevId:%{public}s,",
65 session_.appId.c_str(), Anonymous::Change(session_.sourceDeviceId).c_str(),
66 session_.sourceUserId, Anonymous::Change(session_.targetDeviceId).c_str());
67 }
68
GetHeadDataSize(uint32_t & headSize)69 DistributedDB::DBStatus RouteHeadHandlerImpl::GetHeadDataSize(uint32_t &headSize)
70 {
71 ZLOGD("begin");
72 headSize = 0;
73 if (appId_ == Bootstrap::GetInstance().GetProcessLabel()) {
74 ZLOGI("meta data permitted");
75 return DistributedDB::OK;
76 }
77 bool flag = false;
78 auto peerCap = UpgradeManager::GetInstance().GetCapability(session_.targetDeviceId, flag);
79 auto devInfo = DmAdapter::GetInstance().GetDeviceInfo(session_.targetDeviceId);
80 if (devInfo.osType != OH_OS_TYPE && devInfo.deviceType ==
81 static_cast<uint32_t>(DistributedHardware::DmDeviceType::DEVICE_TYPE_CAR)) {
82 ZLOGI("type car set version. devicdId:%{public}s", Anonymous::Change(session_.targetDeviceId).c_str());
83 flag = true;
84 peerCap.version = CapMetaData::CURRENT_VERSION;
85 }
86 if (!flag) {
87 ZLOGI("get peer cap failed");
88 return DistributedDB::DB_ERROR;
89 }
90 if (peerCap.version == CapMetaData::INVALID_VERSION) {
91 // older versions ignore pack extend head
92 ZLOGI("ignore older version device");
93 return DistributedDB::OK;
94 }
95 if (!session_.IsValid()) {
96 ZLOGI("no valid session to peer device");
97 return DistributedDB::DB_ERROR;
98 }
99 size_t expectSize = sizeof(RouteHead) + sizeof(SessionDevicePair) + sizeof(SessionUserPair)
100 + session_.targetUserIds.size() * sizeof(int) + sizeof(SessionAppId) + session_.appId.size();
101
102 // align message uint width
103 headSize = GET_ALIGNED_SIZE(expectSize, ALIGN_WIDTH);
104 auto time =
105 static_cast<uint64_t>(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count());
106 ZLOGI("packed size:%{public}u times %{public}" PRIu64 ".", headSize, time);
107 headSize_ = headSize;
108 return DistributedDB::OK;
109 }
110
FillHeadData(uint8_t * data,uint32_t headSize,uint32_t totalLen)111 DistributedDB::DBStatus RouteHeadHandlerImpl::FillHeadData(uint8_t *data, uint32_t headSize, uint32_t totalLen)
112 {
113 ZLOGD("begin");
114 if (headSize != headSize_) {
115 ZLOGI("size not match");
116 return DistributedDB::DB_ERROR;
117 }
118 if (headSize_ == 0) {
119 ZLOGI("ignore older version device");
120 return DistributedDB::OK;
121 }
122 auto packRet = PackData(data, headSize);
123 ZLOGD("pack result:%{public}d", packRet);
124 return packRet ? DistributedDB::OK : DistributedDB::DB_ERROR;
125 }
126
PackData(uint8_t * data,uint32_t totalLen)127 bool RouteHeadHandlerImpl::PackData(uint8_t *data, uint32_t totalLen)
128 {
129 if (headSize_ > totalLen) {
130 ZLOGE("the buffer size is not enough, headSize:%{public}d, tatalLen:%{public}d",
131 headSize_, totalLen);
132 return false;
133 }
134
135 auto isOk = PackDataHead(data, headSize_);
136 if (isOk) {
137 return PackDataBody(data + sizeof(RouteHead), headSize_ - sizeof(RouteHead));
138 }
139 return false;
140 }
141
PackDataHead(uint8_t * data,uint32_t totalLen)142 bool RouteHeadHandlerImpl::PackDataHead(uint8_t *data, uint32_t totalLen)
143 {
144 uint8_t *ptr = data;
145 if (headSize_ < sizeof(RouteHead)) {
146 return false;
147 }
148 RouteHead *head = reinterpret_cast<RouteHead *>(ptr);
149 head->magic = HostToNet(RouteHead::MAGIC_NUMBER);
150 head->version = HostToNet(RouteHead::VERSION);
151 head->checkSum = HostToNet(uint64_t(0));
152 head->dataLen = HostToNet(uint32_t(totalLen - sizeof(RouteHead)));
153 return true;
154 }
155
PackDataBody(uint8_t * data,uint32_t totalLen)156 bool RouteHeadHandlerImpl::PackDataBody(uint8_t *data, uint32_t totalLen)
157 {
158 uint8_t *ptr = data;
159 SessionDevicePair *devicePair = reinterpret_cast<SessionDevicePair *>(ptr);
160 auto ret = strcpy_s(devicePair->sourceId, SessionDevicePair::MAX_DEVICE_ID, session_.sourceDeviceId.c_str());
161 if (ret != 0) {
162 ZLOGE("strcpy for source device id failed, ret is %{public}d", ret);
163 return false;
164 }
165 ret = strcpy_s(devicePair->targetId, SessionDevicePair::MAX_DEVICE_ID, session_.targetDeviceId.c_str());
166 if (ret != 0) {
167 ZLOGE("strcpy for target device id failed, ret is %{public}d", ret);
168 return false;
169 }
170 ptr += sizeof(SessionDevicePair);
171
172 SessionUserPair *userPair = reinterpret_cast<SessionUserPair *>(ptr);
173 userPair->sourceUserId = HostToNet(session_.sourceUserId);
174 userPair->targetUserCount = session_.targetUserIds.size();
175 for (size_t i = 0; i < session_.targetUserIds.size(); ++i) {
176 *(userPair->targetUserIds + i) = HostToNet(session_.targetUserIds[i]);
177 }
178 ptr += (sizeof(SessionUserPair) + session_.targetUserIds.size() * sizeof(int));
179
180 SessionAppId *appPair = reinterpret_cast<SessionAppId *>(ptr);
181 ptr += sizeof(SessionAppId);
182
183 uint8_t *end = data + totalLen;
184 uint32_t appIdSize = session_.appId.size();
185 ret = memcpy_s(appPair->appId, end - ptr, session_.appId.data(), appIdSize);
186 if (ret != 0) {
187 ZLOGE("strcpy for app id failed, error:%{public}d", errno);
188 return false;
189 }
190 appPair->len = HostToNet(appIdSize);
191 return true;
192 }
193
ParseHeadData(const uint8_t * data,uint32_t len,uint32_t & headSize,std::vector<std::string> & users)194 bool RouteHeadHandlerImpl::ParseHeadData(
195 const uint8_t *data, uint32_t len, uint32_t &headSize, std::vector<std::string> &users)
196 {
197 auto ret = UnPackData(data, len, headSize);
198 if (!ret) {
199 headSize = 0;
200 return false;
201 }
202 auto time =
203 static_cast<uint64_t>(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count());
204 ZLOGI("unpacked size:%{public}u times %{public}" PRIu64 ".", headSize, time);
205 // flip the local and peer ends
206 SessionPoint local { .deviceId = session_.targetDeviceId, .appId = session_.appId };
207 SessionPoint peer { .deviceId = session_.sourceDeviceId, .userId = session_.sourceUserId, .appId = session_.appId };
208 ZLOGD("valid session:appId:%{public}s, srcDevId:%{public}s, srcUser:%{public}u, trgDevId:%{public}s,",
209 session_.appId.c_str(), Anonymous::Change(session_.sourceDeviceId).c_str(),
210 session_.sourceUserId, Anonymous::Change(session_.targetDeviceId).c_str());
211 for (const auto &item : session_.targetUserIds) {
212 local.userId = item;
213 if (SessionManager::GetInstance().CheckSession(local, peer)) {
214 users.emplace_back(std::to_string(item));
215 }
216 }
217 return true;
218 }
219
UnPackData(const uint8_t * data,uint32_t totalLen,uint32_t & unpackedSize)220 bool RouteHeadHandlerImpl::UnPackData(const uint8_t *data, uint32_t totalLen, uint32_t &unpackedSize)
221 {
222 if (data == nullptr || totalLen < sizeof(RouteHead)) {
223 ZLOGE("invalid input data, totalLen:%{public}d", totalLen);
224 return false;
225 }
226 unpackedSize = 0;
227 RouteHead head = { 0 };
228 bool result = UnPackDataHead(data, totalLen, head);
229 if (result && head.version == RouteHead::VERSION) {
230 auto isOk = UnPackDataBody(data + sizeof(RouteHead), totalLen - sizeof(RouteHead));
231 if (isOk) {
232 unpackedSize = sizeof(RouteHead) + head.dataLen;
233 }
234 return isOk;
235 }
236 return false;
237 }
238
UnPackDataHead(const uint8_t * data,uint32_t totalLen,RouteHead & routeHead)239 bool RouteHeadHandlerImpl::UnPackDataHead(const uint8_t *data, uint32_t totalLen, RouteHead &routeHead)
240 {
241 if (totalLen < sizeof(RouteHead)) {
242 ZLOGE("invalid route head len:%{public}d", totalLen);
243 return false;
244 }
245 const RouteHead *head = reinterpret_cast<const RouteHead *>(data);
246 routeHead.magic = NetToHost(head->magic);
247 routeHead.version = NetToHost(head->version);
248 routeHead.checkSum = NetToHost(head->checkSum);
249 routeHead.dataLen = NetToHost(head->dataLen);
250 if (routeHead.magic != RouteHead::MAGIC_NUMBER) {
251 ZLOGD("not route head data");
252 return false;
253 }
254 if (totalLen - sizeof(RouteHead) < routeHead.dataLen) {
255 ZLOGE("invalid route data len:%{public}d, totalLen:%{public}d.", routeHead.dataLen, totalLen);
256 return false;
257 }
258 return true;
259 }
260
UnPackDataBody(const uint8_t * data,uint32_t totalLen)261 bool RouteHeadHandlerImpl::UnPackDataBody(const uint8_t *data, uint32_t totalLen)
262 {
263 const uint8_t *ptr = data;
264 uint32_t leftSize = totalLen;
265
266 if (leftSize < sizeof(SessionDevicePair)) {
267 ZLOGE("failed to parse device pair, leftSize : %{public}d", leftSize);
268 return false;
269 }
270 const SessionDevicePair *devicePair = reinterpret_cast<const SessionDevicePair *>(ptr);
271 session_.sourceDeviceId =
272 std::string(devicePair->sourceId, strnlen(devicePair->sourceId, SessionDevicePair::MAX_DEVICE_ID));
273 session_.targetDeviceId =
274 std::string(devicePair->targetId, strnlen(devicePair->targetId, SessionDevicePair::MAX_DEVICE_ID));
275 ptr += sizeof(SessionDevicePair);
276 leftSize -= sizeof(SessionDevicePair);
277
278 if (leftSize < sizeof(SessionUserPair)) {
279 ZLOGE("failed to parse user pair, leftSize : %{public}d", leftSize);
280 return false;
281 }
282 const SessionUserPair *userPair = reinterpret_cast<const SessionUserPair *>(ptr);
283 session_.sourceUserId = NetToHost(userPair->sourceUserId);
284
285 auto userPairSize = sizeof(SessionUserPair) + userPair->targetUserCount * sizeof(uint32_t);
286 if (leftSize < userPairSize) {
287 ZLOGE("failed to parse user pair, target user, leftSize : %{public}d", leftSize);
288 return false;
289 }
290 for (int i = 0; i < userPair->targetUserCount; ++i) {
291 session_.targetUserIds.push_back(NetToHost(*(userPair->targetUserIds + i)));
292 }
293 ptr += userPairSize;
294 leftSize -= userPairSize;
295
296 if (leftSize < sizeof(SessionAppId)) {
297 ZLOGE("failed to parse app id, leftSize : %{public}d", leftSize);
298 return false;
299 }
300 const SessionAppId *appId = reinterpret_cast<const SessionAppId *>(ptr);
301 auto appIdLen = NetToHost(appId->len);
302 if (leftSize - sizeof(SessionAppId) < appIdLen) {
303 ZLOGE("failed to parse app id, appIdLen:%{public}d, leftSize:%{public}d.", appIdLen, leftSize);
304 return false;
305 }
306 session_.appId.append(appId->appId, appIdLen);
307 return true;
308 }
309 } // namespace OHOS::DistributedData