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