• 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 {
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