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 for (int i = 0; i < arg->direntNum; i++) {
118 free((arg->namelist)[i]);
119 (arg->namelist)[i] = nullptr;
120 }
121 free(arg->namelist);
122 }
123
CheckValidDir(const std::string & path)124 bool ConnectionDetector::CheckValidDir(const std::string &path)
125 {
126 struct stat buf {
127 };
128 auto ret = stat(path.c_str(), &buf);
129 if (ret == -1) {
130 LOGE("stat failed, errno = %{public}d", errno);
131 return false;
132 }
133 if ((buf.st_mode & S_IFMT) != S_IFDIR) {
134 LOGE("It is not a dir.");
135 return false;
136 }
137 return true;
138 }
139
GetConnectionStatus(const std::string & targetDir,const std::string & networkId)140 bool ConnectionDetector::GetConnectionStatus(const std::string &targetDir, const std::string &networkId)
141 {
142 if (!CheckValidDir(SYS_HMDFS_PATH)) {
143 return false;
144 }
145 unique_ptr<struct NameList, decltype(Deleter) *> pNameList = {new (nothrow) struct NameList, Deleter};
146 if (pNameList == nullptr) {
147 LOGE("Failed to request heap memory.");
148 return false;
149 }
150 int num = scandir(SYS_HMDFS_PATH.c_str(), &(pNameList->namelist), FilterFunc, alphasort);
151 pNameList->direntNum = num;
152 for (int i = 0; i < num; i++) {
153 if ((pNameList->namelist[i])->d_name != targetDir) {
154 continue;
155 }
156 string dest = SYS_HMDFS_PATH + '/' + targetDir;
157 if ((pNameList->namelist[i])->d_type == DT_DIR) {
158 string statusFile = SYS_HMDFS_PATH + '/' + targetDir + '/' + CONNECTION_STATUS_FILE_NAME;
159 if (MatchConnectionGroup(statusFile, networkId)) {
160 LOGI("Parse connection status success.");
161 return true;
162 }
163 break;
164 }
165 }
166 return false;
167 }
168
MocklispHash(const string & str)169 uint64_t ConnectionDetector::MocklispHash(const string &str)
170 {
171 uint64_t res = 0;
172 constexpr int mocklispHashPos = 5;
173 /* Mocklisp hash function. */
174 for (auto ch : str) {
175 res = (res << mocklispHashPos) - res + (uint64_t)ch;
176 }
177 return res;
178 }
179
RepeatGetConnectionStatus(const std::string & targetDir,const std::string & networkId)180 int32_t ConnectionDetector::RepeatGetConnectionStatus(const std::string &targetDir, const std::string &networkId)
181 {
182 int retryCount = 0;
183 while (retryCount++ < MAX_RETRY - 1 && !GetConnectionStatus(targetDir, networkId)) {
184 usleep(CHECK_SESSION_DELAY_TIME);
185 }
186 return retryCount == MAX_RETRY ? -1 : NO_ERROR;
187 }
188
GetCurrentUserId()189 int32_t ConnectionDetector::GetCurrentUserId()
190 {
191 std::vector<int32_t> userIds{};
192 auto ret = AccountSA::OsAccountManager::QueryActiveOsAccountIds(userIds);
193 if (ret != NO_ERROR || userIds.empty()) {
194 LOGE("query active os account id failed, ret = %{public}d", ret);
195 return INVALID_USER_ID;
196 }
197 return userIds[0];
198 }
199
ParseHmdfsPath()200 std::string ConnectionDetector::ParseHmdfsPath()
201 {
202 auto userId = GetCurrentUserId();
203 if (userId == INVALID_USER_ID) {
204 return "";
205 }
206 std::string path = HMDFS_PATH;
207 size_t pos = path.find(CURRENT_USER_ID_FLAG);
208 if (pos == std::string::npos) {
209 return "";
210 }
211 return path.replace(pos, CURRENT_USER_ID_FLAG.length(), std::to_string(userId));
212 }
213 } // namespace DistributedFile
214 } // namespace Storage
215 } // namespace OHOS
216