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 ¬ifyType, 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