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 32namespace OHOS { 33namespace DistributeSystemTest { 34using namespace std; 35using namespace testing; 36using namespace OHOS::HiviewDFX; 37DistributeTestEnvironment *g_pDistributetestEnv = nullptr; 38namespace { 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 45DistributeTestEnvironment::DistributeTestEnvironment() : serverPort_(DEFAULT_AGENT_PORT) 46{ 47} 48 49DistributeTestEnvironment::DistributeTestEnvironment(std::string cfgFile) : serverPort_(DEFAULT_AGENT_PORT) 50{ 51 Init(cfgFile); 52} 53 54void 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 87DistributeTestEnvironment::~DistributeTestEnvironment() 88{ 89} 90 91int DistributeTestEnvironment::GetSerial() 92{ 93 static int serialno = 0; 94 return serialno++; 95} 96 97int 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 114int 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 147void 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 157void 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 166bool 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 244bool 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 291bool 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 311bool 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 336DistributeTest::DistributeTest() 337{ 338 returnVal_ = 0; 339} 340 341DistributeTest::~DistributeTest() 342{ 343} 344 345int 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 */ 361bool 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 */ 383bool 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 */ 409bool 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 421bool 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 432int 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 */ 446bool 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 */ 469bool 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 478bool 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 */ 493bool DistributeTest::Notify(AGENT_NO devNo, const std::string ¬ifyType, 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