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
16 #include "distributed_major.h"
17
18 #include <cstring>
19 #include <map>
20 #include <cerrno>
21 #include <cassert>
22 #include <cstdio>
23 #include <cstdlib>
24
25 #include <unistd.h>
26 #include <poll.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include "securec.h"
31
32 namespace OHOS {
33 namespace DistributeSystemTest {
34 using namespace std;
35 using namespace testing;
36 using namespace OHOS::HiviewDFX;
37 DistributeTestEnvironment *g_pDistributetestEnv = nullptr;
38 namespace {
39 const int CONNECT_TIME = 3;
40 const int SLEEP_TIME = 1000;
41 const int HALF_BUF_LEN = 2;
42 const int CMD_LENGTH = 50;
43 }
44
DistributeTestEnvironment()45 DistributeTestEnvironment::DistributeTestEnvironment() : serverPort_(DEFAULT_AGENT_PORT)
46 {
47 }
48
DistributeTestEnvironment(std::string cfgFile)49 DistributeTestEnvironment::DistributeTestEnvironment(std::string cfgFile) : serverPort_(DEFAULT_AGENT_PORT)
50 {
51 Init(cfgFile);
52 }
53
Init(std::string fileName)54 void DistributeTestEnvironment::Init(std::string fileName)
55 {
56 clientCfg_.OpenCfg(fileName);
57 std::string iplist;
58 if (!clientCfg_.GetCfgVal("agentlist", iplist)) {
59 return;
60 }
61 std::string::size_type posend = 0;
62 std::string::size_type pos = 0;
63 do {
64 std::string ipaddr;
65 posend = iplist.find(",", pos);
66 if (posend != std::string::npos) {
67 ipaddr = iplist.substr(pos, posend - pos);
68 } else {
69 ipaddr = iplist.substr(pos);
70 }
71 AddClient(ipaddr);
72 if (posend >= iplist.length()) {
73 break;
74 }
75 pos = posend + 1;
76 } while (posend != std::string::npos);
77 std::string strPort;
78 if (!clientCfg_.GetCfgVal("agentport", strPort)) {
79 return;
80 }
81 if (sscanf_s(strPort.c_str(), "%d", &serverPort_) < 1) {
82 serverPort_ = DEFAULT_AGENT_PORT;
83 }
84 HiLog::Info(DistributeTestEnvironment::LABEL, "get device port : %d", serverPort_);
85 }
86
~DistributeTestEnvironment()87 DistributeTestEnvironment::~DistributeTestEnvironment()
88 {
89 }
90
GetSerial()91 int DistributeTestEnvironment::GetSerial()
92 {
93 static int serialno = 0;
94 return serialno++;
95 }
96
AddClient(std::string ipAddr)97 int DistributeTestEnvironment::AddClient(std::string ipAddr)
98 {
99 int count = clientList_.size();
100 struct sockaddr_in addr;
101 if (inet_pton(AF_INET, ipAddr.c_str(), &addr.sin_addr) == 1) {
102 DistDeviceInfo dev;
103 dev.devNo = count;
104 dev.ipAddr = ipAddr;
105 dev.fd = -1;
106 clientList_.push_back(dev);
107 count++;
108 } else {
109 return 0;
110 }
111 return 1;
112 }
113
ConnectAgent(size_t devNo)114 int DistributeTestEnvironment::ConnectAgent(size_t devNo)
115 {
116 if (devNo >= clientList_.size()) {
117 return 0;
118 }
119 std::string serverIp = clientList_[devNo].ipAddr;
120 struct sockaddr_in addr;
121 int clientSockFd = socket(AF_INET, SOCK_STREAM, 0);
122 if (clientSockFd < 0) {
123 return -1;
124 }
125 bzero(&addr, sizeof(addr));
126 addr.sin_family = AF_INET;
127 inet_pton(AF_INET, serverIp.c_str(), &addr.sin_addr);
128 addr.sin_port = htons(serverPort_);
129 int connectCount = 0;
130 for (connectCount = 0; connectCount < CONNECT_TIME; connectCount++) { // try connect to agent 3 times.
131 if (!connect(clientSockFd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr))) {
132 break;
133 }
134 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME)); // delay 10ms
135 }
136 if (connectCount >= CONNECT_TIME) {
137 HiLog::Error(DistributeTestEnvironment::LABEL, "connect to agent %s fail.", serverIp.c_str());
138 close(clientSockFd);
139 clientSockFd = -1;
140 return 0;
141 }
142 HiLog::Info(DistributeTestEnvironment::LABEL, "connect to agent %s success.", serverIp.c_str());
143 clientList_[devNo].fd = clientSockFd;
144 return 1;
145 }
146
SetUp()147 void DistributeTestEnvironment::SetUp()
148 {
149 // initial connect agent;
150 size_t clientNo;
151 for (clientNo = 0; clientNo < clientList_.size(); clientNo++) {
152 // create connect to agent of ipaddress is , port is 8642.
153 ConnectAgent(clientNo);
154 }
155 }
156
TearDown()157 void DistributeTestEnvironment::TearDown()
158 {
159 size_t clientNo;
160 for (clientNo = 0; clientNo < clientList_.size(); clientNo++) {
161 close(clientList_[clientNo].fd); // close socket
162 clientList_[clientNo].fd = -1;
163 }
164 }
165
SendToAgent(size_t devNo,int cmdType,void * pstrMsg,int len,std::function<bool (const std::string &,int)> onProcessReturn)166 bool DistributeTestEnvironment::SendToAgent(size_t devNo, int cmdType, void *pstrMsg, int len,
167 std::function<bool(const std::string &, int)> onProcessReturn)
168 {
169 static int globalCommandNo = 0;
170 bool breturn = false;
171 devNo = devNo - 1;
172 if (devNo >= clientList_.size()) {
173 HiLog::Info(DistributeTestEnvironment::LABEL, "can not find no %zu device.", devNo);
174 return breturn;
175 }
176 if (clientList_[devNo].fd <= 0) {
177 HiLog::Info(DistributeTestEnvironment::LABEL, "connect is failure %zu device.", devNo);
178 return breturn;
179 }
180 if (pstrMsg == nullptr) {
181 return false;
182 }
183 globalCommandNo++;
184 char szrbuf[MAX_BUFF_LEN] = {0};
185 auto pCmdMsg = reinterpret_cast<DistributedMsg *>(pstrMsg);
186 pCmdMsg->no = globalCommandNo;
187 pCmdMsg->cmdTestType = htons(cmdType);
188 pCmdMsg->len = htons(len);
189 int rlen = send(clientList_[devNo].fd, pCmdMsg, static_cast<size_t>(len + DST_COMMAND_HEAD_LEN), 0);
190 if (rlen <= 0) {
191 HiLog::Error(DistributeTestEnvironment::LABEL, "agent socket is closed.");
192 return breturn;
193 }
194 // get ret value ;
195 switch (cmdType) {
196 case DST_COMMAND_CALL:
197 case DST_COMMAND_MSG: {
198 int times = CONNECT_TIME;
199 while (times > 0) {
200 rlen = recv(clientList_[devNo].fd, szrbuf, DST_COMMAND_HEAD_LEN, 0);
201 if (static_cast<unsigned long>(rlen) >= DST_COMMAND_HEAD_LEN) {
202 auto pCmdTest = reinterpret_cast<DistributedMsg *>(szrbuf);
203 pCmdTest->cmdTestType = ntohs(pCmdTest->cmdTestType);
204 pCmdTest->len = ntohs(pCmdTest->len);
205 if (pCmdTest->len <= 0) {
206 times--;
207 continue;
208 }
209 recv(clientList_[devNo].fd, pCmdTest->alignmentCmd, pCmdTest->len, 0);
210 HiLog::Info(DistributeTestEnvironment::LABEL, "recv agent data : No.%d command type :%d length :%d",
211 pCmdTest->no, pCmdTest->cmdTestType, pCmdTest->len);
212 if ((globalCommandNo == pCmdTest->no) && (cmdType == pCmdTest->cmdTestType)) {
213 // get ret value ;
214 if (onProcessReturn != nullptr) {
215 breturn = onProcessReturn(pCmdTest->alignmentCmd, pCmdTest->len);
216 } else {
217 breturn = true;
218 }
219 break;
220 } else {
221 HiLog::Error(DistributeTestEnvironment::LABEL, "get error message. type is :%d",
222 pCmdTest->cmdTestType);
223 }
224 } else {
225 if (!rlen) {
226 // peer socket is closed.
227 HiLog::Error(DistributeTestEnvironment::LABEL, "device socket close.");
228 break;
229 }
230 }
231 usleep(SLEEP_TIME);
232 times--;
233 }
234 break;
235 }
236 default: {
237 breturn = true;
238 break;
239 }
240 }
241 return breturn;
242 }
243
RunTestCmd(size_t devNo,const std::string & strCommand,int cmdLen,const std::string & strExpectValue,int expectValueLen,std::function<bool (const std::string &,int)> onProcessReturn)244 bool DistributeTestEnvironment::RunTestCmd(size_t devNo, const std::string &strCommand, int cmdLen,
245 const std::string &strExpectValue, int expectValueLen,
246 std::function<bool(const std::string &, int)> onProcessReturn)
247 {
248 // send command data length
249 char szbuf[MAX_BUFF_LEN];
250 bool breturn = false;
251 size_t lenptr = 0;
252 errno_t ret = EOK;
253 ret = memset_s(szbuf, sizeof(szbuf), 0, MAX_BUFF_LEN);
254 if (ret != EOK) {
255 return breturn;
256 }
257 // add 2 '\0'
258 size_t rlen = cmdLen + expectValueLen + DST_COMMAND_HEAD_LEN + sizeof(int) * HALF_BUF_LEN + HALF_BUF_LEN;
259 if (rlen <= MAX_BUFF_LEN) {
260 auto pCmdTest = reinterpret_cast<DistributedMsg *>(szbuf);
261 pCmdTest->cmdTestType = DST_COMMAND_CALL;
262
263 // alignmentCmd buff format:
264 // cmd_size:int, cmd string, '\0' expectvalue_size:int
265 // expectvalue string, '\0'
266 lenptr = 0;
267 *reinterpret_cast<int *>(pCmdTest->alignmentCmd + lenptr) = htons(cmdLen);
268 lenptr += sizeof(int);
269 ret = memcpy_s(pCmdTest->alignmentCmd + lenptr, MAX_BUFF_LEN - DST_COMMAND_HEAD_LEN - lenptr,
270 strCommand.c_str(), cmdLen);
271 if (ret != EOK) {
272 return breturn;
273 }
274 lenptr += cmdLen + 1;
275 *reinterpret_cast<int *>(pCmdTest->alignmentCmd + lenptr) = htons(expectValueLen);
276 lenptr += sizeof(int);
277 ret = memcpy_s(pCmdTest->alignmentCmd + lenptr, MAX_BUFF_LEN - DST_COMMAND_HEAD_LEN - lenptr,
278 strExpectValue.c_str(), expectValueLen);
279 if (ret != EOK) {
280 return breturn;
281 }
282 lenptr += expectValueLen + 1;
283 pCmdTest->len = lenptr;
284 breturn = SendToAgent(devNo, DST_COMMAND_CALL, pCmdTest, pCmdTest->len, onProcessReturn);
285 } else {
286 HiLog::Error(DistributeTestEnvironment::LABEL, "command data is too long \n");
287 }
288 return breturn;
289 };
290
SendMessage(size_t devNo,const std::string & strMsg,int msgLen,std::function<bool (const std::string &,int)> onProcessReturnMsg)291 bool DistributeTestEnvironment::SendMessage(size_t devNo, const std::string &strMsg, int msgLen,
292 std::function<bool(const std::string &, int)> onProcessReturnMsg)
293 {
294 bool breturn = false;
295 if ((msgLen + DST_COMMAND_HEAD_LEN) <= MAX_BUFF_LEN) {
296 char szbuf[MAX_BUFF_LEN] = {0};
297 auto pCmdTest = reinterpret_cast<DistributedMsg *>(szbuf);
298 pCmdTest->cmdTestType = DST_COMMAND_MSG;
299 errno_t ret = memcpy_s(pCmdTest->alignmentCmd, MAX_BUFF_LEN - DST_COMMAND_HEAD_LEN, strMsg.c_str(), msgLen);
300 if (ret != EOK) {
301 return breturn;
302 }
303 pCmdTest->len = msgLen;
304 breturn = SendToAgent(devNo, DST_COMMAND_MSG, pCmdTest, msgLen, onProcessReturnMsg);
305 } else {
306 HiLog::Info(DistributeTestEnvironment::LABEL, "message data is too long.\n");
307 }
308 return breturn;
309 }
310
Notify(size_t devNo,const std::string & strMsg,int msgLen)311 bool DistributeTestEnvironment::Notify(size_t devNo, const std::string &strMsg, int msgLen)
312 {
313 int dstMax = MAX_BUFF_LEN - DST_COMMAND_HEAD_LEN;
314 if (msgLen < 0 || msgLen >= dstMax) {
315 return false;
316 }
317
318 bool breturn = false;
319 if ((msgLen + DST_COMMAND_HEAD_LEN) <= MAX_BUFF_LEN) {
320 char szbuf[MAX_BUFF_LEN] = {0};
321 auto pCmdTest = reinterpret_cast<DistributedMsg *>(szbuf);
322 pCmdTest->cmdTestType = DST_COMMAND_NOTIFY;
323 errno_t ret = memcpy_s(pCmdTest->alignmentCmd, dstMax, strMsg.c_str(), msgLen);
324 if (ret != EOK) {
325 return breturn;
326 }
327 pCmdTest->alignmentCmd[msgLen] = 0;
328 pCmdTest->len = msgLen;
329 breturn = SendToAgent(devNo, DST_COMMAND_NOTIFY, pCmdTest, msgLen, nullptr);
330 } else {
331 HiLog::Info(DistributeTestEnvironment::LABEL, "notify data is too long.\n");
332 }
333 return breturn;
334 }
335
DistributeTest()336 DistributeTest::DistributeTest()
337 {
338 returnVal_ = 0;
339 }
340
~DistributeTest()341 DistributeTest::~DistributeTest()
342 {
343 }
344
CheckStatus()345 int DistributeTest::CheckStatus()
346 {
347 return 0;
348 }
349
350 /*
351 * function : the testcase execute command on agent device, tell device something, agent process it.
352 * this interface is opened for user.
353 * param :
354 * devNo: agent device serial number.
355 * strCommand: command of the testcase to send.
356 * cmdLen : length of command
357 * strExpectValue: expected return value
358 * expectValueLen: real length of return value
359 * return : if false is return, execute operation failed.
360 */
RunCmdOnAgent(AGENT_NO devNo,const std::string & strCommand,int cmdLen,const std::string & strExpectValue,int expectValueLen)361 bool DistributeTest::RunCmdOnAgent(AGENT_NO devNo, const std::string &strCommand, int cmdLen,
362 const std::string &strExpectValue, int expectValueLen)
363 {
364 if (g_pDistributetestEnv != nullptr) {
365 return g_pDistributetestEnv->RunTestCmd(devNo, strCommand, cmdLen, strExpectValue, expectValueLen,
366 [&](const std::string &strReturn, int strLen)->bool {
367 return OnProcessValue(strReturn, strLen);
368 });
369 }
370 return false;
371 }
372
373 /*
374 * function : the testcase execute command on agent device, include command parameter.
375 * this interface is opened for user.
376 * param :
377 * devNo: agent device serial number.
378 * strCmd: command of the testcase to send.
379 * strArgs: command parameter.
380 * strExpectValue: expected return value
381 * return : if false is return, execute operation failed.
382 */
RunCmdOnAgent(AGENT_NO devNo,const std::string & strCmd,const std::string & strArgs,const std::string & strExpectValue)383 bool DistributeTest::RunCmdOnAgent(AGENT_NO devNo, const std::string &strCmd, const std::string &strArgs,
384 const std::string &strExpectValue)
385 {
386 if (g_pDistributetestEnv != nullptr) {
387 std::string strBuf = strCmd + ":" + strArgs;
388 int cmdLen = strBuf.length() + 1;
389 int expectValueLen = strExpectValue.length() + 1;
390 return g_pDistributetestEnv->RunTestCmd(devNo, strBuf, cmdLen, strExpectValue, expectValueLen,
391 [&](const std::string &strReturn, int strLen)->bool {
392 return OnProcessValue(strReturn, strLen);
393 });
394 }
395 return false;
396 }
397
398 /*
399 * function : the testcase execute command on agent device, include command parameter and callback.
400 * this interface is opened for user.
401 * param :
402 * devNo: agent device serial number.
403 * strCmd: command of the testcase to send.
404 * strArgs: command parameter.
405 * strExpectValue: expected return value
406 * onReturnCall: callback function to handle return value and real length of return value.
407 * return : if false is return, execute operation failed.
408 */
RunCmdOnAgent(AGENT_NO devNo,const std::string & strCmd,const std::string & strArgs,const std::string & strExpectValue,std::function<bool (const std::string &,int)> onReturnCall)409 bool DistributeTest::RunCmdOnAgent(AGENT_NO devNo, const std::string &strCmd, const std::string &strArgs,
410 const std::string &strExpectValue, std::function<bool(const std::string &, int)> onReturnCall)
411 {
412 if (g_pDistributetestEnv != nullptr) {
413 std::string strBuf = strCmd + ":" + strArgs;
414 int cmdLen = strBuf.length() + 1;
415 int expectValueLen = strExpectValue.length() + 1;
416 return g_pDistributetestEnv->RunTestCmd(devNo, strBuf, cmdLen, strExpectValue, expectValueLen, onReturnCall);
417 }
418 return false;
419 }
420
OnProcessValue(const std::string & szbuf,int len)421 bool DistributeTest::OnProcessValue(const std::string &szbuf, int len)
422 {
423 if (szbuf == "") {
424 return false;
425 }
426 if (sscanf_s(szbuf.c_str(), "%d", &returnVal_) < 1) {
427 return false;
428 }
429 return true;
430 }
431
GetReturnVal()432 int DistributeTest::GetReturnVal()
433 {
434 return returnVal_;
435 }
436
437 /*
438 * function : testcase send message to agent device, tell agent device something, agent process it.
439 * this interface is opened for user.
440 * param :
441 * devNo: the serial number of agent device.
442 * msg : message of the testcase sent to the agent
443 * len: length of strMsg
444 * return : if false is return, send operation failed.
445 */
SendMessage(AGENT_NO devNo,const std::string & msg,int len)446 bool DistributeTest::SendMessage(AGENT_NO devNo, const std::string &msg, int len)
447 {
448 if (g_pDistributetestEnv != nullptr) {
449 return g_pDistributetestEnv->SendMessage(devNo, msg, len,
450 [&](const std::string &szreturnbuf, int rlen)->bool {
451 HiLog::Info(DistributeTestEnvironment::LABEL, "onprocessmsg len :%d.", rlen);
452 return OnMsgProc(szreturnbuf, rlen);
453 });
454 }
455 return false;
456 }
457
458 /*
459 * function : testcase send message to agent device, include callback.
460 * this interface is opened for user.
461 * param :
462 * devNo: the serial number of agent device.
463 * msg : message of the testcase sent to the agent
464 * len: length of message
465 * onProcessReturnMsg: callback function that handles the agent device return message and real
466 * length of return value
467 * return : if false is return, send operation failed.
468 */
SendMessage(AGENT_NO devNo,const std::string & msg,int len,std::function<bool (const std::string &,int)> onProcessReturnMsg)469 bool DistributeTest::SendMessage(AGENT_NO devNo, const std::string &msg, int len,
470 std::function<bool(const std::string &, int)> onProcessReturnMsg)
471 {
472 if (g_pDistributetestEnv != nullptr) {
473 return g_pDistributetestEnv->SendMessage(devNo, msg, len, onProcessReturnMsg);
474 }
475 return false;
476 }
477
OnMsgProc(const std::string & szbuf,int len)478 bool DistributeTest::OnMsgProc(const std::string &szbuf, int len)
479 {
480 return (szbuf == "") ? false : true;
481 }
482
483 /*
484 * function : testcase send message to agent device, no return value from agent device.
485 * this interface is opened for user.
486 * param :
487 * devNo: the serial number of agent device.
488 * notifyType : message of the testcase notify the agent
489 * msg: message of the testcase notify the agent, message format: type:message
490 * msgLen: length of message
491 * return : if false is return, notify operation failed.
492 */
Notify(AGENT_NO devNo,const std::string & notifyType,const std::string & msg,int msgLen)493 bool DistributeTest::Notify(AGENT_NO devNo, const std::string ¬ifyType, const std::string &msg, int msgLen)
494 {
495 // maybe need justify if the length of notifytype+msg is bigger than MAX_BUFF_LEN/2;
496 // the length of notifytype must be less than 50;
497 if (notifyType.size() < CMD_LENGTH) {
498 if (g_pDistributetestEnv != nullptr) {
499 std::string strBuf = notifyType + ":" + msg;
500 return g_pDistributetestEnv->Notify(devNo, strBuf, strBuf.length() + 1);
501 }
502 }
503 return false;
504 }
505 } // namespace DistributeSystemTest
506 } // namespace OHOS
507