• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                     (void)sprintf_s(pclinereturn->alignmentCmd, (MAX_BUFF_LEN - DST_COMMAND_HEAD_LEN),
211                                     "%d", nresult) < 0);
212                     rlen = strlen(pclinereturn->alignmentCmd) + 1;
213                     pclinereturn->len = htons(rlen);
214                     HiLog::Info(DistributedAgent::LABEL, "agent get message :%s .\n",
215                                 pclinereturn->alignmentCmd);
216                     send(clientSockFd_, pclinereturn, static_cast<size_t>(rlen + DST_COMMAND_HEAD_LEN), 0);
217                     delete []pAlignmentCmd;
218                     delete []pszEValue;
219                     break;
220                 }
221                 case DST_COMMAND_MSG: {
222                     errno_t ret = EOK;
223                     int nresult = 0;
224                     ret = memset_s(returnValue, sizeof(returnValue), 0, MAX_BUFF_LEN);
225                     if (ret != EOK) {
226                         return -1;
227                     }
228                     auto pclinereturn = reinterpret_cast<DistributedMsg *>(returnValue);
229                     pclinereturn->no = pcline->no;
230                     pclinereturn->cmdTestType = htons(DST_COMMAND_MSG);
231                     pclinereturn->len = MAX_BUFF_LEN - DST_COMMAND_HEAD_LEN;
232                     std::string resultcmd = pclinereturn->alignmentCmd;
233                     nresult = OnProcessMsg(pcline->alignmentCmd, pcline->len, resultcmd, pclinereturn->len);
234                     if (resultcmd == "") {
235                         resultcmd = "agent return message";
236                     }
237                     if (strcpy_s(pclinereturn->alignmentCmd, pclinereturn->len, resultcmd.c_str()) != EOK) {
238                         return -1;
239                     }
240                     pclinereturn->len = htons(nresult);
241                     send(clientSockFd_, pclinereturn, static_cast<size_t>(nresult + DST_COMMAND_HEAD_LEN), 0);
242                     break;
243                 }
244                 case DST_COMMAND_NOTIFY: {
245                     OnNotifyImf(pcline);
246                     break;
247                 }
248                 case DST_COMMAND_END:
249                     mbStop_ = true;
250                     break;
251                 default:
252                     break;
253             }
254         }
255         if (EAGAIN == errno) {
256             continue;
257         }
258     }
259     return 0;
260 }
261 
OnNotifyImf(DistributedMsg * pcline)262 void DistributedAgent::OnNotifyImf(DistributedMsg *pcline)
263 {
264     char alignmentCmd[DistributedAgent::CMD_LENGTH];
265     char szMsg[MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH];
266     int cmdNo = 0;
267     errno_t ret = EOK;
268     ret = memset_s(alignmentCmd, sizeof(alignmentCmd), 0, DistributedAgent::CMD_LENGTH);
269     if (ret != EOK) {
270         return;
271     }
272     (void)memset_s(szMsg,
273         MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH, 0,
274         MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH);
275     for (cmdNo = 0; cmdNo < DistributedAgent::CMD_LENGTH; cmdNo++) {
276         if (pcline->alignmentCmd[cmdNo] == ':') {
277             break;
278         }
279     }
280     if (cmdNo >= DistributedAgent::CMD_LENGTH) {
281         HiLog::Error(DistributedAgent::LABEL, "error command.\n");
282     }  else {
283         errno_t ret = EOK;
284         ret = memcpy_s(alignmentCmd, sizeof(alignmentCmd), pcline->alignmentCmd, cmdNo);
285         if (ret != EOK) {
286             return;
287         }
288         ret = memcpy_s(szMsg, MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH,
289             pcline->alignmentCmd + cmdNo + 1, pcline->len - cmdNo - 1);
290         if (ret != EOK) {
291             return;
292         }
293         OnNotify(alignmentCmd, szMsg, pcline->len - cmdNo);
294     }
295 }
296 
297 /*
298  * function : when testcase need this device to do something, or tell device something, agent process it.
299  *     this interface is opened for user.
300  * param :
301  *     strMsg: message from testcase .
302  *     len : length of strMsg
303  *     strReturnValue: return message buffer
304  *     returnbuflen: max length of strReturnValue
305  * return : real length of strReturnValue filled
306  */
OnProcessMsg(const std::string & strMsg,int msgLen,std::string & strReturnValue,int returnBufLen)307 int DistributedAgent::OnProcessMsg(const std::string &strMsg, int msgLen,
308     std::string &strReturnValue, int returnBufLen)
309 {
310     // default test code
311     std::string returnStr = "agent return message";
312     int returnLen = returnStr.size();
313     if (strReturnValue != "" && returnLen <= returnBufLen) {
314         strReturnValue = returnStr;
315     }
316     return returnLen;
317 }
318 
319 /*
320  * function : execute command from testcase.
321  * param :
322  *     strCommand: command from testcase ,format is : command_string:args_string.
323  *     cmdLen : length of strCommand
324  *     strExpectValue: expectvalue string
325  *     expectvaluelen: length of strExpectValue
326  * return : return integer value, default 0 is returned.
327  */
OnProcessCmd(const std::string & strCommand,int cmdLen,const std::string & strExpectValue,int expectValueLen)328 int DistributedAgent::OnProcessCmd(const std::string &strCommand, int cmdLen,
329     const std::string &strExpectValue, int expectValueLen)
330 {
331     int nresult = 0;
332     char alignmentCmd[DistributedAgent::CMD_LENGTH];
333     char szArgs[MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH];
334     int cmdNo = 0;
335     errno_t ret = EOK;
336     ret = memset_s(alignmentCmd, sizeof(alignmentCmd), 0, DistributedAgent::CMD_LENGTH);
337     if (ret != EOK) {
338         return -1;
339     }
340     (void)memset_s(szArgs,
341         MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH, 0,
342         MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH);
343     for (cmdNo = 0; cmdNo < DistributedAgent::CMD_LENGTH; cmdNo++) {
344         if (strCommand[cmdNo] == ':') {
345             break;
346         }
347     }
348     if (cmdNo >= DistributedAgent::CMD_LENGTH) {
349         HiLog::Error(DistributedAgent::LABEL, "error command.\n");
350         nresult = -1;
351         return nresult;
352     }
353 
354     errno_t ret = EOK;
355     ret = memcpy_s(alignmentCmd, sizeof(alignmentCmd), strCommand.c_str(), cmdNo);
356     if (ret != EOK) {
357         return -1;
358     }
359     ret = memcpy_s(szArgs,
360         MAX_BUFF_LEN / DistributedAgent::HALF_NUM - DistributedAgent::CMD_LENGTH,
361         strCommand.c_str() + cmdNo + 1,
362         cmdLen - cmdNo - 1);
363     if (ret != EOK) {
364         return -1;
365     }
366 
367     nresult = OnProcessCmd(alignmentCmd, cmdNo, szArgs, cmdLen - cmdNo, strExpectValue, expectValueLen);
368     return nresult;
369 }
370 
OnProcessCmd(const std::string & strCommand,int cmdLen,const std::string & strArgs,int argsLen,const std::string & strExpectValue,int expectValueLen)371 int DistributedAgent::OnProcessCmd(const std::string &strCommand, int cmdLen, const std::string &strArgs,
372     int argsLen, const std::string &strExpectValue, int expectValueLen)
373 {
374     int nresult = 0;
375     HiLog::Info(DistributedAgent::LABEL, "this is a agent.\n");
376     if (static_cast<int>(strExpectValue.size()) > expectValueLen ||
377         static_cast<int>(strCommand.size()) > cmdLen ||
378         static_cast<int>(strArgs.size()) > argsLen) {
379         return -1;
380     }
381     return nresult;
382 }
383 
Start(std::string cfgFile)384 int DistributedAgent::Start(std::string cfgFile)
385 {
386     std::string agentPort;
387     agentCfg_.OpenCfg(cfgFile);
388     if (!agentCfg_.GetCfgVal("agentport", agentPort)) {
389         HiLog::Error(DistributedAgent::LABEL, "agent can not get port.\n");
390         return 0;
391     }
392     if (sscanf_s(agentPort.c_str(), "%d", &agentPort_) < 1) {
393         agentPort_ = DEFAULT_AGENT_PORT;
394     }
395     return InitAgentServer();
396 }
397 
Join()398 void DistributedAgent::Join()
399 {
400     if (mpthCmdProcess_ != nullptr) {
401         mpthCmdProcess_->join();
402     }
403 }
404 
OnNotify(const std::string & notifyType,const std::string & msg,int msgLen)405 int DistributedAgent::OnNotify(const std::string &notifyType, const std::string &msg, int msgLen)
406 {
407     if (strcmp(notifyType.c_str(), "testcasename")) {
408         HiLog::Error(DistributedAgent::LABEL, "onNotify: %s.\n", msg.c_str());
409     }
410     if (msgLen < 0) {
411         HiLog::Error(DistributedAgent::LABEL, "msgLen < 0.");
412     }
413     return 0;
414 }
415 
Stop()416 int DistributedAgent::Stop()
417 {
418     return 0;
419 }
420 } // namespace DistributeSystemTest
421 } // namespace OHOS
422