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
21 namespace {
22 constexpr size_t READ_BUFFER_SIZE = 1024 * 16;
23 const std::string DEFAULT_NET_PATH("/proc/net/xt_qtaguid/stats");
24 } // namespace
25
NetworkPlugin()26 NetworkPlugin::NetworkPlugin()
27 : buffer_(new (std::nothrow) uint8_t[READ_BUFFER_SIZE]), fp_(nullptr, nullptr)
28 {
29 pidUid_.clear();
30 }
31
Start(const uint8_t * configData,uint32_t configSize)32 int NetworkPlugin::Start(const uint8_t* configData, uint32_t configSize)
33 {
34 CHECK_NOTNULL(buffer_, -1, "%s:NetworkPlugin, buffer_ is null", __func__);
35
36 if (protoConfig_.ParseFromArray(configData, configSize) <= 0) {
37 HILOG_ERROR(LOG_CORE, "%s:NetworkPlugin, parseFromArray failed!", __func__);
38 return -1;
39 }
40
41 for (int i = 0; i < protoConfig_.pid().size(); i++) {
42 int32_t pid = protoConfig_.pid(i);
43 pidUid_.emplace(pid, GetUid(pid));
44 }
45
46 HILOG_INFO(LOG_CORE, "%s:NetworkPlugin, start success!", __func__);
47
48 return 0;
49 }
50
Report(uint8_t * data,uint32_t dataSize)51 int NetworkPlugin::Report(uint8_t* data, uint32_t dataSize)
52 {
53 NetworkDatas dataProto;
54 std::string file = GetRateNodePath();
55 char realPath[PATH_MAX + 1] = {0};
56
57 if ((file.length() > PATH_MAX) || (realpath(file.c_str(), realPath) == nullptr)) {
58 return -1;
59 }
60 fp_ = std::unique_ptr<FILE, int (*)(FILE*)>(fopen(realPath, "r"), fclose);
61 CHECK_NOTNULL(fp_, -1, "%s:NetworkPlugin, open(%s) Failed, errno(%d)", __func__, file.c_str(), errno);
62
63 for (int i = 0; i < protoConfig_.pid().size(); i++) {
64 auto* info = dataProto.add_networkinfo();
65 int32_t pid = protoConfig_.pid(i);
66 NetworkCell dataCell = {0};
67 ReadTxRxBytes(pid, dataCell);
68 // set proto
69 for (auto& it : dataCell.details) {
70 NetworkDetails* data = info->add_details();
71 data->set_tx_bytes(it.tx);
72 data->set_rx_bytes(it.rx);
73 data->set_type(it.type);
74 }
75 info->set_pid(pid);
76 info->set_tx_bytes(dataCell.tx);
77 info->set_rx_bytes(dataCell.rx);
78 info->set_tv_sec(dataCell.ts.tv_sec);
79 info->set_tv_nsec(dataCell.ts.tv_nsec);
80 }
81
82 uint32_t length = dataProto.ByteSizeLong();
83 if (length > dataSize) {
84 return -length;
85 }
86 if (dataProto.SerializeToArray(data, length) > 0) {
87 return length;
88 }
89 return 0;
90 }
91
Stop()92 int NetworkPlugin::Stop()
93 {
94 HILOG_INFO(LOG_CORE, "%s:NetworkPlugin, stop success!", __func__);
95 return 0;
96 }
97
GetRateNodePath()98 std::string NetworkPlugin::GetRateNodePath()
99 {
100 std::string name = "";
101
102 if (!fileForTest_.empty()) {
103 name = fileForTest_ + DEFAULT_NET_PATH;
104 return name;
105 }
106 if (access(DEFAULT_NET_PATH.c_str(), F_OK) == 0) {
107 name = DEFAULT_NET_PATH;
108 }
109 return name;
110 }
111
GetUid(int32_t pid)112 int32_t NetworkPlugin::GetUid(int32_t pid)
113 {
114 if (pid <= 0) {
115 HILOG_ERROR(LOG_CORE, "%s:NetworkPlugin, check param fail, pid less than 0!", __func__);
116 return -1;
117 }
118
119 char* end = nullptr;
120 std::string path = std::string("/proc/") + std::to_string(pid) + std::string("/status");
121 if (!fileForTest_.empty()) {
122 path = fileForTest_ + std::string("/proc/") + std::to_string(pid) + std::string("/status");
123 }
124 std::ifstream input(path, std::ios::in);
125 if (input.fail()) {
126 const int bufSize = 1024;
127 char buf[bufSize] = { 0 };
128 strerror_r(errno, buf, bufSize);
129 HILOG_ERROR(LOG_CORE, "%s:NetworkPlugin, open %s failed, errno(%s)", __func__, path.c_str(), buf);
130 return -1;
131 }
132 do {
133 if (!input.good()) {
134 return -1;
135 }
136 std::string line;
137 getline(input, line);
138 if (!strncmp(line.c_str(), "Uid:", strlen("Uid:"))) {
139 std::string str = line.substr(strlen("Uid:\t"));
140 HILOG_INFO(LOG_CORE, "%s:NetworkPlugin, line(%s), str(%s)", __func__, line.c_str(), str.c_str());
141 return strtol(str.c_str(), &end, DEC_BASE);
142 }
143 } while (!input.eof());
144 input.close();
145
146 return -1;
147 }
148
ReadTxRxBytes(int32_t pid,NetworkCell & cell)149 bool NetworkPlugin::ReadTxRxBytes(int32_t pid, NetworkCell &cell)
150 {
151 int32_t uid = pidUid_.at(pid);
152 CHECK_NOTNULL(fp_.get(), false, "%s:NetworkPlugin, fp_ is null", __func__);
153 int ret = fseek(fp_.get(), 0, SEEK_SET);
154 CHECK_TRUE(ret == 0, false, "%s:NetworkPlugin, fseek failed, error(%d)!", __func__, errno);
155 size_t rsize = static_cast<size_t>(fread(buffer_.get(), sizeof(char), READ_BUFFER_SIZE - 1, fp_.get()));
156 buffer_.get()[rsize] = '\0';
157 CHECK_TRUE(rsize >= 0, false, "%s:NetworkPlugin, read failed, errno(%d)", __func__, errno);
158 char* end = nullptr;
159 BufferSplitter totalbuffer((const char*)buffer_.get(), rsize + 1);
160 do {
161 int index = 0;
162 NetDetails cache = {0};
163 char tmp[TX_INDEX + 1] = {0};
164 while (totalbuffer.NextWord(' ')) {
165 index++;
166 if (totalbuffer.CurWord() == nullptr) {
167 continue;
168 }
169 if (index == IFACE_INDEX && !strncmp(totalbuffer.CurWord(), "lo", strlen("lo"))) {
170 break;
171 }
172 if (index == IFACE_INDEX &&
173 strncpy_s(tmp, sizeof(tmp), totalbuffer.CurWord(), totalbuffer.CurWordSize()) == EOK) {
174 cache.type = tmp;
175 }
176 uint64_t value = static_cast<uint64_t>(strtoull(totalbuffer.CurWord(), &end, DEC_BASE));
177 CHECK_TRUE(value >= 0, false, "%s:NetworkPlugin, strtoull value failed", __func__);
178 if ((index == UID_INDEX) && (uid != static_cast<int32_t>(value))) {
179 break;
180 }
181 if (index == RX_INDEX) {
182 uint64_t rx_bytes = value;
183 cache.rx = rx_bytes;
184 cell.rx += rx_bytes;
185 }
186 if (index == TX_INDEX) {
187 uint64_t tx_bytes = value;
188 cache.tx = tx_bytes;
189 cell.tx += tx_bytes;
190 AddNetDetails(cell, cache);
191 }
192 }
193 } while (totalbuffer.NextLine());
194
195 clock_gettime(CLOCK_REALTIME, &cell.ts);
196
197 return true;
198 }
199
AddNetDetails(NetworkCell & cell,NetDetails & data)200 void NetworkPlugin::AddNetDetails(NetworkCell& cell, NetDetails& data)
201 {
202 bool finded = false;
203
204 // 处理重复数据
205 for (auto it = cell.details.begin(); it != cell.details.end(); it++) {
206 if (it->type == data.type) {
207 it->tx += data.tx;
208 it->rx += data.rx;
209 finded = true;
210 }
211 }
212
213 if (!finded) {
214 cell.details.push_back(data);
215 }
216 }
217