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