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