• 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 
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 &notifyType, 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