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