1 /*
2 * Copyright (c) 2021-2022 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 "distributed_agent.h"
17
18 #include <cstring>
19 #include <cerrno>
20
21 #include <poll.h>
22 #include <unistd.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26
27 namespace OHOS {
28 namespace DistributeSystemTest {
29 using namespace std;
30 using namespace OHOS::HiviewDFX;
31
DistributedAgent()32 DistributedAgent::DistributedAgent()
33 {
34 agentPort_ = 0;
35 agentIpAddr_ = "";
36 mpthCmdProcess_ = nullptr;
37 mbStop_ = false;
38 clientSockFd_ = -1;
39 agentCfg_ = DistributedCfg();
40 }
41
~DistributedAgent()42 DistributedAgent::~DistributedAgent()
43 {
44 if (mpthCmdProcess_ != nullptr) {
45 mbStop_ = true;
46 if (mpthCmdProcess_->joinable()) {
47 mpthCmdProcess_->join();
48 }
49 }
50 close(clientSockFd_);
51 clientSockFd_ = -1;
52 }
53
54 /*
55 * The result of init test environment is returned. if false is return, the init operation failed.
56 * Note that, the test environment should be inited for the test case.
57 */
SetUp()58 bool DistributedAgent::SetUp()
59 {
60 return true;
61 }
62
63 /*
64 * The result of reset test environment is returned. if false is return, the reset operation failed.
65 * Note that, the test environment should be reset by the test case in the end.
66 */
TearDown()67 bool DistributedAgent::TearDown()
68 {
69 return true;
70 }
71
InitAgentServer()72 int DistributedAgent::InitAgentServer()
73 {
74 HiLog::Info(DistributedAgent::LABEL, "begin create agent server.\n");
75 volatile int serverSockFd = socket(AF_INET, SOCK_STREAM, 0);
76 if (serverSockFd < 0) {
77 return -1;
78 }
79
80 int num = 1;
81 if (setsockopt(serverSockFd, SOL_SOCKET, SO_REUSEADDR, &num, sizeof(num))) {
82 close(serverSockFd);
83 serverSockFd = -1;
84 return serverSockFd;
85 }
86
87 struct sockaddr_in addr;
88 errno_t ret = EOK;
89 ret = memset_s(&addr, sizeof(addr), 0, sizeof(addr));
90 if (ret != EOK) {
91 return -1;
92 }
93 addr.sin_family = AF_INET;
94 if (agentIpAddr_ != "") {
95 inet_pton(AF_INET, agentIpAddr_.c_str(), &addr.sin_addr);
96 } else {
97 addr.sin_addr.s_addr = htonl(INADDR_ANY);
98 }
99
100 addr.sin_port = htons(agentPort_);
101 int err = ::bind(serverSockFd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr));
102 if (err < 0) {
103 HiLog::Error(DistributedAgent::LABEL, "agent bind error.\n");
104 close(serverSockFd);
105 serverSockFd = -1;
106 return serverSockFd;
107 }
108
109 if (listen(serverSockFd, 1) < 0) {
110 HiLog::Error(DistributedAgent::LABEL, "agent listen error.\n");
111 close(serverSockFd);
112 serverSockFd = -1;
113 return serverSockFd;
114 }
115
116 mpthCmdProcess_ = std::make_unique<std::thread>([=]() {
117 DoCmdServer(serverSockFd);
118 });
119
120 OnLocalInit();
121 return serverSockFd;
122 }
123
DoCmdServer(int serverSockFd)124 int DistributedAgent::DoCmdServer(int serverSockFd)
125 {
126 char buff[MAX_BUFF_LEN] = {0};
127 char returnValue[MAX_BUFF_LEN] = {0};
128 int rlen = 0;
129 int receiveLen = 0;
130 struct sockaddr_in clientAddr;
131 socklen_t sinSize = 0;
132 int clientSockFd = -1;
133 sinSize = sizeof(struct sockaddr_in);
134 bzero(&clientAddr, sizeof(clientAddr));
135 receiveLen = DistributedAgent::RECE_LEN;
136
137 while (receiveLen > 0) {
138 HiLog::Info(DistributedAgent::LABEL, "wait client .......\n");
139 if ((clientSockFd = accept(serverSockFd, reinterpret_cast<struct sockaddr *>(&clientAddr), &sinSize)) > 0) {
140 break;
141 }
142 receiveLen--;
143 continue;
144 }
145 if (receiveLen <= 0) {
146 HiLog::Error(DistributedAgent::LABEL, "test case runner can not work because I can not accept it.");
147 close(serverSockFd);
148 return -1;
149 }
150 clientSockFd_ = clientSockFd;
151 HiLog::Info(DistributedAgent::LABEL, "accept testcase runner IP:%s port:%d \n",
152 inet_ntoa(clientAddr.sin_addr), clientAddr.sin_port);
153 while (mbStop_ != true) {
154 errno_t ret = EOK;
155 ret = memset_s(buff, sizeof(buff), 0, MAX_BUFF_LEN);
156 if (ret != EOK) {
157 return -1;
158 }
159 // every cmd length less than MAX_BUFF_LEN bytes;
160 int recvCmdLen = recv(clientSockFd_, buff, DST_COMMAND_HEAD_LEN, 0);
161 if (static_cast<unsigned long>(recvCmdLen) < DST_COMMAND_HEAD_LEN) {
162 if (!recvCmdLen) {
163 HiLog::Info(DistributedAgent::LABEL, "agent connect socket closed, IP:%s .\n",
164 inet_ntoa(clientAddr.sin_addr));
165 mbStop_ = true;
166 }
167 continue;
168 }
169 auto pcline = reinterpret_cast<DistributedMsg *>(buff);
170 pcline->cmdTestType = ntohs(pcline->cmdTestType);
171 pcline->len = ntohs(pcline->len);
172 HiLog::Info(DistributedAgent::LABEL, "test agent get message type:%d .\n", pcline->cmdTestType);
173 if (pcline->len > 0 && static_cast<unsigned long>(pcline->len) <= (MAX_BUFF_LEN - DST_COMMAND_HEAD_LEN)) {
174 receiveLen = recv(clientSockFd_, pcline->alignmentCmd, static_cast<size_t>(pcline->len), 0);
175 HiLog::Info(DistributedAgent::LABEL, "agent get message cmd=%s .\n", pcline->alignmentCmd);
176 switch (pcline->cmdTestType) {
177 case DST_COMMAND_CALL: {
178 errno_t ret = EOK;
179 unsigned int cmdLen = ntohs(*reinterpret_cast<int *>(pcline->alignmentCmd));
180 rlen = sizeof(int);
181 // check cmdLen length < 100, copy command + args data ;
182 char *pAlignmentCmd = new char[cmdLen + 1];
183 ret = memcpy_s(pAlignmentCmd, cmdLen + 1, pcline->alignmentCmd + rlen, cmdLen);
184 if (ret != EOK) {
185 delete []pAlignmentCmd;
186 return -1;
187 }
188 pAlignmentCmd[cmdLen] = '\0';
189 rlen += cmdLen + 1;
190 unsigned int eValueLen = ntohs(*reinterpret_cast<int *>(pcline->alignmentCmd + rlen));
191 rlen += sizeof(int);
192 char *pszEValue = new char[eValueLen + 1];
193 ret = memcpy_s(pszEValue, eValueLen + 1, pcline->alignmentCmd + rlen, eValueLen);
194 if (ret != EOK) {
195 delete []pAlignmentCmd;
196 delete []pszEValue;
197 return -1;
198 }
199 pszEValue[eValueLen] = '\0';
200 int nresult = OnProcessCmd(pAlignmentCmd, cmdLen, pszEValue, eValueLen);
201 ret = memset_s(returnValue, sizeof(returnValue), 0, MAX_BUFF_LEN);
202 if (ret != EOK) {
203 delete []pAlignmentCmd;
204 delete []pszEValue;
205 return -1;
206 }
207 auto pclinereturn = reinterpret_cast<DistributedMsg *>(returnValue);
208 pclinereturn->no = pcline->no;
209 pclinereturn->cmdTestType = htons(DST_COMMAND_CALL);
210 sprintf_s(pclinereturn->alignmentCmd, (MAX_BUFF_LEN - DST_COMMAND_HEAD_LEN), "%d", nresult);
211 rlen = strlen(pclinereturn->alignmentCmd) + 1;
212 pclinereturn->len = htons(rlen);
213 HiLog::Info(DistributedAgent::LABEL, "agent get message :%s .\n",
214 pclinereturn->alignmentCmd);
215 send(clientSockFd_, pclinereturn, static_cast<size_t>(rlen + DST_COMMAND_HEAD_LEN), 0);
216 delete []pAlignmentCmd;
217 delete []pszEValue;
218 break;
219 }
220 case DST_COMMAND_MSG: {
221 errno_t ret = EOK;
222 int nresult = 0;
223 ret = memset_s(returnValue, sizeof(returnValue), 0, MAX_BUFF_LEN);
224 if (ret != EOK) {
225 return -1;
226 }
227 auto pclinereturn = reinterpret_cast<DistributedMsg *>(returnValue);
228 pclinereturn->no = pcline->no;
229 pclinereturn->cmdTestType = htons(DST_COMMAND_MSG);
230 pclinereturn->len = MAX_BUFF_LEN - DST_COMMAND_HEAD_LEN;
231 std::string resultcmd = pclinereturn->alignmentCmd;
232 nresult = OnProcessMsg(pcline->alignmentCmd, pcline->len, resultcmd, pclinereturn->len);
233 if (resultcmd == "") {
234 resultcmd = "agent return message";
235 }
236 if (strcpy_s(pclinereturn->alignmentCmd, pclinereturn->len, resultcmd.c_str()) != EOK) {
237 return -1;
238 }
239 pclinereturn->len = htons(nresult);
240 send(clientSockFd_, pclinereturn, static_cast<size_t>(nresult + DST_COMMAND_HEAD_LEN), 0);
241 break;
242 }
243 case DST_COMMAND_NOTIFY: {
244 OnNotifyImf(pcline);
245 break;
246 }
247 case DST_COMMAND_END:
248 mbStop_ = true;
249 break;
250 default:
251 break;
252 }
253 }
254 if (EAGAIN == errno) {
255 continue;
256 }
257 }
258 return 0;
259 }
260
OnNotifyImf(DistributedMsg * pcline)261 void DistributedAgent::OnNotifyImf(DistributedMsg *pcline)
262 {
263 char alignmentCmd[DistributedAgent::CMD_LENGTH];
264 char szMsg[MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH];
265 int cmdNo = 0;
266 errno_t ret = EOK;
267 ret = memset_s(alignmentCmd, sizeof(alignmentCmd), 0, DistributedAgent::CMD_LENGTH);
268 if (ret != EOK) {
269 return;
270 }
271 (void)memset_s(szMsg,
272 MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH, 0,
273 MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH);
274 for (cmdNo = 0; cmdNo < DistributedAgent::CMD_LENGTH; cmdNo++) {
275 if (pcline->alignmentCmd[cmdNo] == ':') {
276 break;
277 }
278 }
279 if (cmdNo >= DistributedAgent::CMD_LENGTH) {
280 HiLog::Error(DistributedAgent::LABEL, "error command.\n");
281 } else {
282 errno_t ret = EOK;
283 ret = memcpy_s(alignmentCmd, sizeof(alignmentCmd), pcline->alignmentCmd, cmdNo);
284 if (ret != EOK) {
285 return;
286 }
287 ret = memcpy_s(szMsg, MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH,
288 pcline->alignmentCmd + cmdNo + 1, pcline->len - cmdNo - 1);
289 if (ret != EOK) {
290 return;
291 }
292 OnNotify(alignmentCmd, szMsg, pcline->len - cmdNo);
293 }
294 }
295
296 /*
297 * function : when testcase need this device to do something, or tell device something, agent process it.
298 * this interface is opened for user.
299 * param :
300 * strMsg: message from testcase .
301 * len : length of strMsg
302 * strReturnValue: return message buffer
303 * returnbuflen: max length of strReturnValue
304 * return : real length of strReturnValue filled
305 */
OnProcessMsg(const std::string & strMsg,int msgLen,std::string & strReturnValue,int returnBufLen)306 int DistributedAgent::OnProcessMsg(const std::string &strMsg, int msgLen,
307 std::string &strReturnValue, int returnBufLen)
308 {
309 // default test code
310 std::string returnStr = "agent return message";
311 int returnLen = returnStr.size();
312 if (strReturnValue != "" && returnLen <= returnBufLen) {
313 strReturnValue = returnStr;
314 }
315 return returnLen;
316 }
317
318 /*
319 * function : execute command from testcase.
320 * param :
321 * strCommand: command from testcase ,format is : command_string:args_string.
322 * cmdLen : length of strCommand
323 * strExpectValue: expectvalue string
324 * expectvaluelen: length of strExpectValue
325 * return : return integer value, default 0 is returned.
326 */
OnProcessCmd(const std::string & strCommand,int cmdLen,const std::string & strExpectValue,int expectValueLen)327 int DistributedAgent::OnProcessCmd(const std::string &strCommand, int cmdLen,
328 const std::string &strExpectValue, int expectValueLen)
329 {
330 int nresult = 0;
331 char alignmentCmd[DistributedAgent::CMD_LENGTH];
332 char szArgs[MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH];
333 int cmdNo = 0;
334 errno_t ret = EOK;
335 ret = memset_s(alignmentCmd, sizeof(alignmentCmd), 0, DistributedAgent::CMD_LENGTH);
336 if (ret != EOK) {
337 return -1;
338 }
339 (void)memset_s(szArgs,
340 MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH, 0,
341 MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH);
342 for (cmdNo = 0; cmdNo < DistributedAgent::CMD_LENGTH; cmdNo++) {
343 if (strCommand[cmdNo] == ':') {
344 break;
345 }
346 }
347 if (cmdNo >= DistributedAgent::CMD_LENGTH) {
348 HiLog::Error(DistributedAgent::LABEL, "error command.\n");
349 nresult = -1;
350 return nresult;
351 }
352
353 ret = memcpy_s(alignmentCmd, sizeof(alignmentCmd), strCommand.c_str(), cmdNo);
354 if (ret != EOK) {
355 return -1;
356 }
357 ret = memcpy_s(szArgs,
358 MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH,
359 strCommand.c_str() + cmdNo + 1,
360 cmdLen - cmdNo - 1);
361 if (ret != EOK) {
362 return -1;
363 }
364
365 nresult = OnProcessCmd(alignmentCmd, cmdNo, szArgs, cmdLen - cmdNo, strExpectValue, expectValueLen);
366 return nresult;
367 }
368
OnProcessCmd(const std::string & strCommand,int cmdLen,const std::string & strArgs,int argsLen,const std::string & strExpectValue,int expectValueLen)369 int DistributedAgent::OnProcessCmd(const std::string &strCommand, int cmdLen, const std::string &strArgs,
370 int argsLen, const std::string &strExpectValue, int expectValueLen)
371 {
372 int nresult = 0;
373 HiLog::Info(DistributedAgent::LABEL, "this is a agent.\n");
374 if (static_cast<int>(strExpectValue.size()) > expectValueLen ||
375 static_cast<int>(strCommand.size()) > cmdLen ||
376 static_cast<int>(strArgs.size()) > argsLen) {
377 return -1;
378 }
379 return nresult;
380 }
381
Start(std::string cfgFile)382 int DistributedAgent::Start(std::string cfgFile)
383 {
384 std::string agentPort;
385 agentCfg_.OpenCfg(cfgFile);
386 if (!agentCfg_.GetCfgVal("agentport", agentPort)) {
387 HiLog::Error(DistributedAgent::LABEL, "agent can not get port.\n");
388 return 0;
389 }
390 if (sscanf_s(agentPort.c_str(), "%d", &agentPort_) < 1) {
391 agentPort_ = DEFAULT_AGENT_PORT;
392 }
393 return InitAgentServer();
394 }
395
Join()396 void DistributedAgent::Join()
397 {
398 if (mpthCmdProcess_ != nullptr) {
399 mpthCmdProcess_->join();
400 }
401 }
402
OnNotify(const std::string & notifyType,const std::string & msg,int msgLen)403 int DistributedAgent::OnNotify(const std::string ¬ifyType, const std::string &msg, int msgLen)
404 {
405 if (strcmp(notifyType.c_str(), "testcasename")) {
406 HiLog::Error(DistributedAgent::LABEL, "onNotify: %s.\n", msg.c_str());
407 }
408 if (msgLen < 0) {
409 HiLog::Error(DistributedAgent::LABEL, "msgLen < 0.");
410 }
411 return 0;
412 }
413
Stop()414 int DistributedAgent::Stop()
415 {
416 return 0;
417 }
418 } // namespace DistributeSystemTest
419 } // namespace OHOS
420