• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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