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