1 /*
2 * Copyright (c) 2023 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 "connection_detector.h"
17
18 #include <dirent.h>
19 #include <iostream>
20 #include <sstream>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <vector>
24
25 #include "dfs_error.h"
26 #include "utils_log.h"
27
28 namespace OHOS {
29 namespace Storage {
30 namespace DistributedFile {
31 constexpr int32_t INVALID_USER_ID = -1;
GetCellByIndex(const std::string & str,int targetIndex)32 std::string ConnectionDetector::GetCellByIndex(const std::string &str, int targetIndex)
33 {
34 size_t begin = 0;
35 size_t end = 0;
36 int count = 0;
37 do {
38 size_t i;
39 for (i = begin; i < str.size(); ++i) {
40 if (str[i] != '\t' && str[i] != ' ') {
41 break;
42 }
43 }
44 begin = i;
45 for (i = begin; i < str.size(); ++i) {
46 if (!(str[i] != '\t' && str[i] != ' ')) {
47 break;
48 }
49 }
50 end = i;
51 if (end == str.size()) {
52 break;
53 }
54 ++count;
55 if (count == targetIndex) {
56 break;
57 }
58 begin = end;
59 } while (true);
60 return str.substr(begin, end - begin);
61 }
62
MatchConnectionStatus(ifstream & inputFile)63 bool ConnectionDetector::MatchConnectionStatus(ifstream &inputFile)
64 {
65 string str;
66 getline(inputFile, str);
67 if (str.find("connection_status") == string::npos) {
68 return false;
69 }
70 while (getline(inputFile, str)) {
71 if (str.empty()) {
72 return false;
73 }
74 auto connectionStatus = GetCellByIndex(str, 2); // 2 indicates the position of connection status
75 auto tcpStatus = GetCellByIndex(str, 3); // 3 indicates the position of tcp status
76 // "2"|"3" indicates socket status is connecting|connected;
77 if (connectionStatus == "2" && (tcpStatus == "2" || tcpStatus == "3")) {
78 return true;
79 }
80 }
81 return false;
82 }
83
MatchConnectionGroup(const std::string & fileName,const string & networkId)84 bool ConnectionDetector::MatchConnectionGroup(const std::string &fileName, const string &networkId)
85 {
86 if (access(fileName.c_str(), F_OK) != 0) {
87 LOGE("Cannot find the status file");
88 return false;
89 }
90 ifstream statusFile(fileName);
91 std::string str;
92 getline(statusFile, str);
93 bool result = false;
94 while (getline(statusFile, str)) {
95 if (str.find(networkId) == 0) {
96 result = MatchConnectionStatus(statusFile);
97 break;
98 }
99 }
100 statusFile.close();
101 return result;
102 }
103
FilterFunc(const struct dirent * filename)104 static int FilterFunc(const struct dirent *filename)
105 {
106 if (string_view(filename->d_name) == "." || string_view(filename->d_name) == "..") {
107 return DISMATCH;
108 }
109 return MATCH;
110 }
111
112 struct NameList {
113 struct dirent **namelist = {nullptr};
114 int direntNum = 0;
115 };
116
Deleter(struct NameList * arg)117 static void Deleter(struct NameList *arg)
118 {
119 if (arg == nullptr) {
120 return;
121 }
122
123 if (arg->namelist != nullptr) {
124 for (int i = 0; i < arg->direntNum; i++) {
125 free((arg->namelist)[i]);
126 (arg->namelist)[i] = nullptr;
127 }
128 free(arg->namelist);
129 arg->namelist = nullptr;
130 }
131 delete arg;
132 arg = nullptr;
133 }
134
CheckValidDir(const std::string & path)135 bool ConnectionDetector::CheckValidDir(const std::string &path)
136 {
137 struct stat buf {
138 };
139 auto ret = stat(path.c_str(), &buf);
140 if (ret == -1) {
141 LOGE("stat failed, errno = %{public}d", errno);
142 return false;
143 }
144 if ((buf.st_mode & S_IFMT) != S_IFDIR) {
145 LOGE("It is not a dir.");
146 return false;
147 }
148 return true;
149 }
150
GetConnectionStatus(const std::string & targetDir,const std::string & networkId)151 bool ConnectionDetector::GetConnectionStatus(const std::string &targetDir, const std::string &networkId)
152 {
153 if (!CheckValidDir(SYS_HMDFS_PATH)) {
154 return false;
155 }
156 unique_ptr<struct NameList, decltype(Deleter) *> pNameList = {new (nothrow) struct NameList, Deleter};
157 if (pNameList == nullptr) {
158 LOGE("Failed to request heap memory.");
159 return false;
160 }
161 int num = scandir(SYS_HMDFS_PATH.c_str(), &(pNameList->namelist), FilterFunc, alphasort);
162 if (num < 0) {
163 LOGE("Failed to scandir.");
164 return false;
165 }
166 pNameList->direntNum = num;
167 for (int i = 0; i < num; i++) {
168 if ((pNameList->namelist[i])->d_name != targetDir) {
169 continue;
170 }
171 string dest = SYS_HMDFS_PATH + '/' + targetDir;
172 if ((pNameList->namelist[i])->d_type == DT_DIR) {
173 string statusFile = SYS_HMDFS_PATH + '/' + targetDir + '/' + CONNECTION_STATUS_FILE_NAME;
174 if (MatchConnectionGroup(statusFile, networkId)) {
175 LOGI("Parse connection status success.");
176 return true;
177 }
178 break;
179 }
180 }
181 return false;
182 }
183
MocklispHash(const string & str)184 uint64_t ConnectionDetector::MocklispHash(const string &str)
185 {
186 struct stat statBuf;
187 auto err = stat(str.c_str(), &statBuf);
188 if (err != 0) {
189 LOGE("stat failed %{public}s error, err: %{public}d", GetAnonyString(str).c_str(), err);
190 return static_cast<uint64_t>(FileManagement::ERR_BAD_VALUE);
191 }
192 LOGI("statBuf dev id: %{public}lu", static_cast<unsigned long>(statBuf.st_dev));
193 return statBuf.st_dev;
194 }
195
RepeatGetConnectionStatus(const std::string & targetDir,const std::string & networkId)196 int32_t ConnectionDetector::RepeatGetConnectionStatus(const std::string &targetDir, const std::string &networkId)
197 {
198 int retryCount = 0;
199 while (retryCount++ < MAX_RETRY - 1 && !GetConnectionStatus(targetDir, networkId)) {
200 usleep(CHECK_SESSION_DELAY_TIME);
201 }
202 return retryCount == MAX_RETRY ? -1 : NO_ERROR;
203 }
204
GetCurrentUserId()205 int32_t ConnectionDetector::GetCurrentUserId()
206 {
207 std::vector<int32_t> userIds{};
208 auto ret = AccountSA::OsAccountManager::QueryActiveOsAccountIds(userIds);
209 if (ret != NO_ERROR || userIds.empty()) {
210 LOGE("query active os account id failed, ret = %{public}d", ret);
211 return INVALID_USER_ID;
212 }
213 return userIds[0];
214 }
215
ParseHmdfsPath()216 std::string ConnectionDetector::ParseHmdfsPath()
217 {
218 auto userId = GetCurrentUserId();
219 if (userId == INVALID_USER_ID) {
220 return "";
221 }
222 std::string path = HMDFS_PATH;
223 size_t pos = path.find(CURRENT_USER_ID_FLAG);
224 if (pos == std::string::npos) {
225 return "";
226 }
227 return path.replace(pos, CURRENT_USER_ID_FLAG.length(), std::to_string(userId));
228 }
229 } // namespace DistributedFile
230 } // namespace Storage
231 } // namespace OHOS
232