• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "network_plugin.h"
16 #include "buffer_splitter.h"
17 #include "securec.h"
18 
19 #include <string>
20 #include <sys/stat.h>
21 
22 namespace {
23 constexpr size_t READ_BUFFER_SIZE = 1024 * 16;
24 const std::string DEFAULT_NET_PATH("/proc/net/xt_qtaguid/stats");
25 } // namespace
26 
NetworkPlugin()27 NetworkPlugin::NetworkPlugin()
28     : buffer_(new (std::nothrow) uint8_t[READ_BUFFER_SIZE]), fp_(nullptr, nullptr)
29 {
30     pidUid_.clear();
31 }
32 
Start(const uint8_t * configData,uint32_t configSize)33 int NetworkPlugin::Start(const uint8_t* configData, uint32_t configSize)
34 {
35     CHECK_NOTNULL(buffer_, -1, "%s:NetworkPlugin, buffer_ is null", __func__);
36 
37     if (protoConfig_.ParseFromArray(configData, configSize) <= 0) {
38         HILOG_ERROR(LOG_CORE, "%s:NetworkPlugin, parseFromArray failed!", __func__);
39         return -1;
40     }
41 
42     for (int i = 0; i < protoConfig_.pid().size(); i++) {
43         int32_t pid = protoConfig_.pid(i);
44         pidUid_.emplace(pid, GetUid(pid));
45     }
46 
47     HILOG_INFO(LOG_CORE, "%s:NetworkPlugin, start success!", __func__);
48 
49     return 0;
50 }
51 
Report(uint8_t * data,uint32_t dataSize)52 int NetworkPlugin::Report(uint8_t* data, uint32_t dataSize)
53 {
54     NetworkDatas dataProto;
55     std::string file = GetRateNodePath();
56     if (protoConfig_.test_file() != "") {
57         file = protoConfig_.test_file();
58     }
59 
60     struct stat s;
61     lstat(file.c_str(), &s);
62     if (S_ISDIR(s.st_mode)) {
63         HILOG_ERROR(LOG_CORE, "%s:path(%s) is directory, no data to report", __func__, file.c_str());
64         return -1;
65     }
66 
67     char realPath[PATH_MAX + 1] = {0};
68     if ((file.length() >= PATH_MAX) || (realpath(file.c_str(), realPath) == nullptr)) {
69         HILOG_ERROR(LOG_CORE, "%s:path is invalid: %s, errno=%d", __func__, file.c_str(), errno);
70         return -1;
71     }
72     fp_ = std::unique_ptr<FILE, int (*)(FILE*)>(fopen(realPath, "r"), fclose);
73     CHECK_NOTNULL(fp_, -1, "%s:NetworkPlugin, open(%s) Failed, errno(%d)", __func__, file.c_str(), errno);
74 
75     if (protoConfig_.pid().size() > 0) {
76         for (int i = 0; i < protoConfig_.pid().size(); i++) {
77             auto* info = dataProto.add_networkinfo();
78             int32_t pid = protoConfig_.pid(i);
79             NetworkCell dataCell = {0};
80             ReadTxRxBytes(pid, dataCell);
81             // set proto
82             for (auto& it : dataCell.details) {
83                 NetworkDetails* data = info->add_details();
84                 data->set_tx_bytes(it.tx);
85                 data->set_rx_bytes(it.rx);
86                 data->set_type(it.type);
87             }
88             info->set_pid(pid);
89             info->set_tx_bytes(dataCell.tx);
90             info->set_rx_bytes(dataCell.rx);
91             info->set_tv_sec(dataCell.ts.tv_sec);
92             info->set_tv_nsec(dataCell.ts.tv_nsec);
93         }
94     } else if (protoConfig_.test_file() != "") { // test data
95         NetSystemData systemData = {};
96         ReadSystemTxRxBytes(systemData);
97         static int randNum = 0;
98         randNum++;
99         auto* systemInfo = dataProto.mutable_network_system_info();
100         for (auto& it : systemData.details) {
101             NetworkSystemDetails* data = systemInfo->add_details();
102             data->set_rx_bytes(it.rxBytes + randNum * RX_BYTES_INDEX);
103             data->set_rx_packets(it.rxPackets + randNum * RX_PACKETS_INDEX);
104             data->set_tx_bytes(it.txBytes + randNum * TX_BYTES_INDEX);
105             data->set_tx_packets(it.txPackets + randNum * TX_PACKETS_INDEX);
106             data->set_type(it.type);
107         }
108         systemInfo->set_tv_sec(systemData.ts.tv_sec);
109         systemInfo->set_tv_nsec(systemData.ts.tv_nsec);
110         systemInfo->set_rx_bytes(systemData.rxBytes + (randNum * RX_BYTES_INDEX * systemData.details.size()));
111         systemInfo->set_rx_packets(systemData.rxPackets + (randNum * RX_PACKETS_INDEX * systemData.details.size()));
112         systemInfo->set_tx_bytes(systemData.txBytes + (randNum * TX_BYTES_INDEX * systemData.details.size()));
113         systemInfo->set_tx_packets(systemData.txPackets + (randNum * TX_PACKETS_INDEX * systemData.details.size()));
114     } else { // real data
115         NetSystemData systemData = {};
116         ReadSystemTxRxBytes(systemData);
117         auto* systemInfo = dataProto.mutable_network_system_info();
118         for (auto& it : systemData.details) {
119             NetworkSystemDetails* data = systemInfo->add_details();
120             data->set_rx_bytes(it.rxBytes);
121             data->set_rx_packets(it.rxPackets);
122             data->set_tx_bytes(it.txBytes);
123             data->set_tx_packets(it.txPackets);
124             data->set_type(it.type);
125         }
126         systemInfo->set_tv_sec(systemData.ts.tv_sec);
127         systemInfo->set_tv_nsec(systemData.ts.tv_nsec);
128         systemInfo->set_rx_bytes(systemData.rxBytes);
129         systemInfo->set_rx_packets(systemData.rxPackets);
130         systemInfo->set_tx_bytes(systemData.txBytes);
131         systemInfo->set_tx_packets(systemData.txPackets);
132     }
133 
134     uint32_t length = dataProto.ByteSizeLong();
135     if (length > dataSize) {
136         return -length;
137     }
138     if (dataProto.SerializeToArray(data, length) > 0) {
139         return length;
140     }
141     return 0;
142 }
143 
Stop()144 int NetworkPlugin::Stop()
145 {
146     buffer_ = nullptr;
147     fp_ = nullptr;
148     pidUid_.clear();
149 
150     HILOG_INFO(LOG_CORE, "%s:NetworkPlugin, stop success!", __func__);
151     return 0;
152 }
153 
GetRateNodePath()154 std::string NetworkPlugin::GetRateNodePath()
155 {
156     std::string name = "";
157 
158     if (!fileForTest_.empty()) {
159         name = fileForTest_ + DEFAULT_NET_PATH;
160         return name;
161     }
162     if (access(DEFAULT_NET_PATH.c_str(), F_OK) == 0) {
163         name = DEFAULT_NET_PATH;
164     }
165     return name;
166 }
167 
GetUid(int32_t pid)168 int32_t NetworkPlugin::GetUid(int32_t pid)
169 {
170     if (pid <= 0) {
171         HILOG_ERROR(LOG_CORE, "%s:NetworkPlugin, check param fail, pid less than 0!", __func__);
172         return -1;
173     }
174 
175     char* end = nullptr;
176     std::string path = std::string("/proc/") + std::to_string(pid) + std::string("/status");
177     if (!fileForTest_.empty()) {
178         path = fileForTest_ + std::string("/proc/") + std::to_string(pid) + std::string("/status");
179     }
180     std::ifstream input(path, std::ios::in);
181     if (input.fail()) {
182         const int bufSize = 256;
183         char buf[bufSize] = { 0 };
184         strerror_r(errno, buf, bufSize);
185         HILOG_ERROR(LOG_CORE, "%s:NetworkPlugin, open %s failed, errno(%s)", __func__, path.c_str(), buf);
186         return -1;
187     }
188     do {
189         if (!input.good()) {
190             return -1;
191         }
192         std::string line;
193         getline(input, line);
194         if (!strncmp(line.c_str(), "Uid:", strlen("Uid:"))) {
195             std::string str = line.substr(strlen("Uid:\t"));
196             HILOG_INFO(LOG_CORE, "%s:NetworkPlugin, line(%s), str(%s)", __func__, line.c_str(), str.c_str());
197             return strtol(str.c_str(), &end, DEC_BASE);
198         }
199     } while (!input.eof());
200     input.close();
201 
202     return -1;
203 }
204 
ReadTxRxBytes(int32_t pid,NetworkCell & cell)205 bool NetworkPlugin::ReadTxRxBytes(int32_t pid, NetworkCell &cell)
206 {
207     int32_t uid = pidUid_.at(pid);
208     CHECK_NOTNULL(fp_.get(), false, "%s:NetworkPlugin, fp_ is null", __func__);
209     int ret = fseek(fp_.get(), 0, SEEK_SET);
210     CHECK_TRUE(ret == 0, false, "%s:NetworkPlugin, fseek failed, error(%d)!", __func__, errno);
211     size_t rsize = static_cast<size_t>(fread(buffer_.get(), sizeof(char), READ_BUFFER_SIZE - 1, fp_.get()));
212     buffer_.get()[rsize] = '\0';
213     CHECK_TRUE(rsize >= 0, false, "%s:NetworkPlugin, read failed, errno(%d)", __func__, errno);
214     char* end = nullptr;
215     BufferSplitter totalbuffer((const char*)buffer_.get(), rsize + 1);
216     do {
217         int index = 0;
218         NetDetails cache = {0};
219         char tmp[TX_BYTES_INDEX + 1] = {0};
220         while (totalbuffer.NextWord(' ')) {
221             index++;
222             if (totalbuffer.CurWord() == nullptr) {
223                 continue;
224             }
225             if (index == IFACE_INDEX && !strncmp(totalbuffer.CurWord(), "lo", strlen("lo"))) {
226                 break;
227             }
228             if (index == IFACE_INDEX &&
229                 strncpy_s(tmp, sizeof(tmp), totalbuffer.CurWord(), totalbuffer.CurWordSize()) == EOK) {
230                 cache.type = tmp;
231             }
232             uint64_t value = static_cast<uint64_t>(strtoull(totalbuffer.CurWord(), &end, DEC_BASE));
233             CHECK_TRUE(value >= 0, false, "%s:NetworkPlugin, strtoull value failed", __func__);
234             if ((index == UID_INDEX) && (uid != static_cast<int32_t>(value))) {
235                 break;
236             }
237             if (index == RX_BYTES_INDEX) {
238                 uint64_t rxBytes = value;
239                 cache.rx = rxBytes;
240                 cell.rx += rxBytes;
241             }
242             if (index == TX_BYTES_INDEX) {
243                 uint64_t txBytes = value;
244                 cache.tx = txBytes;
245                 cell.tx += txBytes;
246                 AddNetDetails(cell, cache);
247             }
248         }
249     } while (totalbuffer.NextLine());
250 
251     clock_gettime(CLOCK_REALTIME, &cell.ts);
252 
253     return true;
254 }
255 
AddNetDetails(NetworkCell & cell,NetDetails & data)256 void NetworkPlugin::AddNetDetails(NetworkCell& cell, NetDetails& data)
257 {
258     bool finded = false;
259 
260     // 处理重复数据
261     for (auto it = cell.details.begin(); it != cell.details.end(); it++) {
262         if (it->type == data.type) {
263             it->tx += data.tx;
264             it->rx += data.rx;
265             finded = true;
266         }
267     }
268 
269     if (!finded) {
270         cell.details.push_back(data);
271     }
272 }
273 
ReadSystemTxRxBytes(NetSystemData & systemData)274 bool NetworkPlugin::ReadSystemTxRxBytes(NetSystemData &systemData)
275 {
276     CHECK_NOTNULL(fp_.get(), false, "%s:NetworkPlugin, fp_ is null", __func__);
277     int ret = fseek(fp_.get(), 0, SEEK_SET);
278     CHECK_TRUE(ret == 0, false, "%s:NetworkPlugin, fseek failed, error(%d)!", __func__, errno);
279     size_t rsize = static_cast<size_t>(fread(buffer_.get(), sizeof(char), READ_BUFFER_SIZE - 1, fp_.get()));
280     buffer_.get()[rsize] = '\0';
281     CHECK_TRUE(rsize >= 0, false, "%s:NetworkPlugin, read failed, errno(%d)", __func__, errno);
282     char* end = nullptr;
283     BufferSplitter totalbuffer((const char*)buffer_.get(), rsize + 1);
284     do {
285         int index = 0;
286         NetSystemDetails systemCache = {};
287         char tmp[TX_BYTES_INDEX + 1] = "";
288         while (totalbuffer.NextWord(' ')) {
289             index++;
290             if (totalbuffer.CurWord() == nullptr) {
291                 continue;
292             }
293             if (index == IFACE_INDEX && !strncmp(totalbuffer.CurWord(), "lo", strlen("lo"))) {
294                 break;
295             }
296             if (index == IFACE_INDEX &&
297                 strncpy_s(tmp, sizeof(tmp), totalbuffer.CurWord(), totalbuffer.CurWordSize()) == EOK) {
298                 systemCache.type = tmp;
299             }
300             if (strcmp(systemCache.type.c_str(), "iface") == 0) {
301                 break;
302             }
303             uint64_t value = static_cast<uint64_t>(strtoull(totalbuffer.CurWord(), &end, DEC_BASE));
304             CHECK_TRUE(value >= 0, false, "%s:NetworkPlugin, strtoull value failed", __func__);
305             if (index == RX_BYTES_INDEX) {
306                 uint64_t rxBytes = value;
307                 systemCache.rxBytes = rxBytes;
308                 systemData.rxBytes += rxBytes;
309             } else if (index == RX_PACKETS_INDEX) {
310                 uint64_t rxPackets = value;
311                 systemCache.rxPackets = rxPackets;
312                 systemData.rxPackets += rxPackets;
313             } else if (index == TX_BYTES_INDEX) {
314                 uint64_t txBytes = value;
315                 systemCache.txBytes = txBytes;
316                 systemData.txBytes += txBytes;
317             } else if (index == TX_PACKETS_INDEX) {
318                 uint64_t txPackets = value;
319                 systemCache.txPackets = txPackets;
320                 systemData.txPackets += txPackets;
321                 AddNetSystemDetails(systemData, systemCache);
322             }
323         }
324     } while (totalbuffer.NextLine());
325 
326     clock_gettime(CLOCK_REALTIME, &systemData.ts);
327 
328     return true;
329 }
330 
AddNetSystemDetails(NetSystemData & systemData,NetSystemDetails & data)331 void NetworkPlugin::AddNetSystemDetails(NetSystemData& systemData, NetSystemDetails& data)
332 {
333     bool finded = false;
334 
335     // 处理重复数据
336     for (auto it = systemData.details.begin(); it != systemData.details.end(); it++) {
337         if (it->type == data.type) {
338             it->rxBytes += data.rxBytes;
339             it->rxPackets += data.rxPackets;
340             it->txBytes += data.txBytes;
341             it->txPackets += data.txPackets;
342             finded = true;
343         }
344     }
345 
346     if (!finded) {
347         systemData.details.push_back(data);
348     }
349 }
350