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