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#include "client.h" 16#ifndef TEST_HASH 17#include "hdc_hash_gen.h" 18#endif 19#include "host_updater.h" 20#include "server.h" 21#include "file.h" 22 23std::map<std::string, std::string> g_lists; 24bool g_show = true; 25 26namespace Hdc { 27bool g_terminalStateChange = false; 28HdcClient::HdcClient(const bool serverOrClient, const string &addrString, uv_loop_t *loopMainIn, bool checkVersion) 29 : HdcChannelBase(serverOrClient, addrString, loopMainIn) 30{ 31 MallocChannel(&channel); // free by logic 32 debugRetryCount = 0; 33#ifndef _WIN32 34 Base::ZeroStruct(terminalState); 35#endif 36 isCheckVersionCmd = checkVersion; 37} 38 39HdcClient::~HdcClient() 40{ 41#ifndef _WIN32 42 if (g_terminalStateChange) { 43 tcsetattr(STDIN_FILENO, TCSAFLUSH, &terminalState); 44 } 45#endif 46 Base::TryCloseLoop(loopMain, "ExecuteCommand finish"); 47} 48 49void HdcClient::NotifyInstanceChannelFree(HChannel hChannel) 50{ 51 if (bShellInteractive) { 52 WRITE_LOG(LOG_DEBUG, "Restore tty"); 53 ModifyTty(false, &hChannel->stdinTty); 54 } 55} 56 57uint32_t HdcClient::GetLastPID() 58{ 59 char bufPath[BUF_SIZE_MEDIUM] = ""; 60 size_t size = BUF_SIZE_MEDIUM; 61 char pidBuf[BUF_SIZE_TINY] = ""; 62 // get running pid to kill it 63 if (uv_os_tmpdir(bufPath, &size) < 0) { 64 WRITE_LOG(LOG_FATAL, "Tmppath failed"); 65 return 0; 66 } 67 string path = Base::StringFormat("%s%c.%s.pid", bufPath, Base::GetPathSep(), SERVER_NAME.c_str()); 68 Base::ReadBinFile(path.c_str(), reinterpret_cast<void **>(&pidBuf), BUF_SIZE_TINY); 69 int pid = atoi(pidBuf); // pid maybe 0 70 return pid; 71} 72 73bool HdcClient::StartServer(const string &cmd) 74{ 75 int serverStatus = Base::ProgramMutex(SERVER_NAME.c_str(), true); 76 if (serverStatus < 0) { 77 WRITE_LOG(LOG_DEBUG, "get server status failed, serverStatus:%d", serverStatus); 78 return false; 79 } 80 81 // server is not running 82 if (serverStatus == 0) { 83 HdcServer::PullupServer(channelHostPort.c_str()); 84 return true; 85 } 86 87 // server is running 88 if (cmd.find(" -r") == std::string::npos) { 89 return true; 90 } 91 92 // restart server 93 uint32_t pid = GetLastPID(); 94 if (pid == 0) { 95 Base::PrintMessage(TERMINAL_HDC_PROCESS_FAILED.c_str()); 96 return false; 97 } 98 int rc = uv_kill(pid, SIGKILL); 99 WRITE_LOG(LOG_DEBUG, "uv_kill rc:%d", rc); 100 HdcServer::PullupServer(channelHostPort.c_str()); 101 return true; 102} 103 104bool HdcClient::KillServer(const string &cmd) 105{ 106 int serverStatus = Base::ProgramMutex(SERVER_NAME.c_str(), true); 107 if (serverStatus < 0) { 108 WRITE_LOG(LOG_DEBUG, "get server status failed, serverStatus:%d", serverStatus); 109 return false; 110 } 111 112 // server is not running 113 if (serverStatus == 0) { 114 if (cmd.find(" -r") != std::string::npos) { 115 HdcServer::PullupServer(channelHostPort.c_str()); 116 } 117 return true; 118 } 119 120 // server is running 121 uint32_t pid = GetLastPID(); 122 if (pid == 0) { 123 Base::PrintMessage(TERMINAL_HDC_PROCESS_FAILED.c_str()); 124 return false; 125 } 126 int rc = uv_kill(pid, SIGKILL); 127 if (rc == 0) { 128 Base::PrintMessage("Kill server finish"); 129 } else { 130 constexpr int size = 1024; 131 char buf[size] = { 0 }; 132 uv_strerror_r(rc, buf, size); 133 Base::PrintMessage("Kill server failed %s", buf); 134 } 135 if (cmd.find(" -r") != std::string::npos) { 136 HdcServer::PullupServer(channelHostPort.c_str()); 137 } 138 return true; 139} 140 141void HdcClient::DoCtrlServiceWork(uv_check_t *handle) 142{ 143 HdcClient *thisClass = (HdcClient *)handle->data; 144 string &strCmd = thisClass->command; 145 if (!strncmp(thisClass->command.c_str(), CMDSTR_SERVICE_START.c_str(), CMDSTR_SERVICE_START.size())) { 146 thisClass->StartServer(strCmd); 147 } else if (!strncmp(thisClass->command.c_str(), CMDSTR_SERVICE_KILL.c_str(), CMDSTR_SERVICE_KILL.size())) { 148 thisClass->KillServer(strCmd); 149 // clang-format off 150 } else if (!strncmp(thisClass->command.c_str(), CMDSTR_GENERATE_KEY.c_str(), CMDSTR_GENERATE_KEY.size()) && 151 strCmd.find(" ") != std::string::npos) { 152 // clang-format on 153 string keyPath = strCmd.substr(CMDSTR_GENERATE_KEY.size() + 1, strCmd.size()); 154 HdcAuth::GenerateKey(keyPath.c_str()); 155 } else { 156 Base::PrintMessage("Unknown command"); 157 } 158 Base::TryCloseHandle((const uv_handle_t *)handle); 159} 160 161int HdcClient::CtrlServiceWork(const char *commandIn) 162{ 163 command = commandIn; 164 ctrlServerWork.data = this; 165 uv_check_init(loopMain, &ctrlServerWork); 166 uv_check_start(&ctrlServerWork, DoCtrlServiceWork); 167 uv_run(loopMain, UV_RUN_NOWAIT); 168 return 0; 169} 170 171string HdcClient::AutoConnectKey(string &doCommand, const string &preConnectKey) const 172{ 173 string key = preConnectKey; 174 bool isNoTargetCommand = false; 175 vector<string> vecNoConnectKeyCommand; 176 vecNoConnectKeyCommand.push_back(CMDSTR_SOFTWARE_VERSION); 177 vecNoConnectKeyCommand.push_back(CMDSTR_SOFTWARE_HELP); 178 vecNoConnectKeyCommand.push_back(CMDSTR_TARGET_DISCOVER); 179 vecNoConnectKeyCommand.push_back(CMDSTR_LIST_TARGETS); 180 vecNoConnectKeyCommand.push_back(CMDSTR_CHECK_SERVER); 181 vecNoConnectKeyCommand.push_back(CMDSTR_CONNECT_TARGET); 182 vecNoConnectKeyCommand.push_back(CMDSTR_CHECK_DEVICE); 183 vecNoConnectKeyCommand.push_back(CMDSTR_WAIT_FOR); 184 vecNoConnectKeyCommand.push_back(CMDSTR_FORWARD_FPORT + " ls"); 185 vecNoConnectKeyCommand.push_back(CMDSTR_FORWARD_FPORT + " rm"); 186 for (string v : vecNoConnectKeyCommand) { 187 if (!doCommand.compare(0, v.size(), v)) { 188 isNoTargetCommand = true; 189 break; 190 } 191 } 192 if (isNoTargetCommand) { 193 if (this->command != CMDSTR_WAIT_FOR) { 194 key = ""; 195 } 196 } else { 197 if (!preConnectKey.size()) { 198 key = CMDSTR_CONNECT_ANY; 199 } 200 } 201 return key; 202} 203 204#ifdef _WIN32 205static void ReadFileThreadFunc(void* arg) 206{ 207 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 208 DWORD bytesRead = 0; 209 210 HANDLE* read = reinterpret_cast<HANDLE*>(arg); 211 while (true) { 212 if (!ReadFile(*read, buffer, BUF_SIZE_DEFAULT - 1, &bytesRead, NULL)) { 213 break; 214 } 215 string str = std::to_string(bytesRead); 216 const char* zero = "0"; 217 if (!strncmp(zero, str.c_str(), strlen(zero))) { 218 return; 219 } 220 printf("%s", buffer); 221 if (memset_s(buffer, sizeof(buffer), 0, sizeof(buffer)) != EOK) { 222 return; 223 } 224 } 225} 226 227string HdcClient::GetHilogPath() 228{ 229 string hdcPath = Base::GetHdcAbsolutePath(); 230 int index = hdcPath.find_last_of(Base::GetPathSep()); 231 string exePath = hdcPath.substr(0, index) + Base::GetPathSep() + HILOG_NAME; 232 233 return exePath; 234} 235 236void HdcClient::RunCommandWin32(const string& cmd) 237{ 238 HANDLE hSubWrite; 239 HANDLE hParentRead; 240 HANDLE hParentWrite; 241 HANDLE hSubRead; 242 STARTUPINFO si; 243 PROCESS_INFORMATION pi; 244 SECURITY_ATTRIBUTES sa; 245 sa.nLength = sizeof(SECURITY_ATTRIBUTES); 246 sa.lpSecurityDescriptor = NULL; 247 sa.bInheritHandle = true; 248 249 if (!CreatePipe(&hParentRead, &hSubWrite, &sa, 0) || 250 !CreatePipe(&hSubRead, &hParentWrite, &sa, 0) || 251 !SetHandleInformation(hParentRead, HANDLE_FLAG_INHERIT, 0) || 252 !SetHandleInformation(hParentWrite, HANDLE_FLAG_INHERIT, 0)) { 253 return; 254 } 255 256 ZeroMemory(&si, sizeof(STARTUPINFO)); 257 si.cb = sizeof(STARTUPINFO); 258 GetStartupInfo(&si); 259 si.hStdError = hSubWrite; 260 si.hStdOutput = hSubWrite; 261 si.hStdInput = hSubRead; 262 si.wShowWindow = SW_HIDE; 263 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; 264 265 const char *msg = cmd.c_str(); 266 char buffer[BUF_SIZE_SMALL] = {0}; 267 if (strcpy_s(buffer, sizeof(buffer), msg) != EOK) { 268 return; 269 } 270 const string exePath = GetHilogPath(); 271 if (!CreateProcess(_T(exePath.c_str()), _T(buffer), NULL, NULL, true, NULL, NULL, NULL, &si, &pi)) { 272 WRITE_LOG(LOG_INFO, "create process failed, error:%d", GetLastError()); 273 return; 274 } 275 auto thread = std::thread([&hParentRead]() { 276 ReadFileThreadFunc(&hParentRead); 277 }); 278 WaitForSingleObject(pi.hProcess, INFINITE); 279 CloseHandle(hSubWrite); 280 CloseHandle(pi.hProcess); 281 CloseHandle(pi.hThread); 282 thread.join(); 283 CloseHandle(hParentRead); 284 CloseHandle(hParentWrite); 285 CloseHandle(hSubRead); 286} 287#else 288void HdcClient::RunCommand(const string& cmd) 289{ 290 FILE *procFileInfo = nullptr; 291 procFileInfo = popen(cmd.c_str(), "r"); 292 if (procFileInfo == nullptr) { 293 perror("popen execute failed"); 294 return; 295 } 296 char resultBufShell[BUF_SIZE_DEFAULT] = {0}; 297 while (fgets(resultBufShell, sizeof(resultBufShell), procFileInfo) != nullptr) { 298 printf("%s", resultBufShell); 299 if (memset_s(resultBufShell, sizeof(resultBufShell), 0, sizeof(resultBufShell)) != EOK) { 300 break; 301 } 302 } 303 pclose(procFileInfo); 304} 305#endif 306 307void HdcClient::RunExecuteCommand(const string& cmd) 308{ 309#ifdef _WIN32 310 RunCommandWin32(cmd); 311#else 312 RunCommand(cmd); 313#endif 314} 315 316bool IsCaptureCommand(const string& cmd) 317{ 318 int index = string(CMDSTR_HILOG).length(); 319 int length = cmd.length(); 320 const string captureOption = "parse"; 321 while (index < length) { 322 if (cmd[index] == ' ') { 323 index++; 324 continue; 325 } 326 if (!strncmp(cmd.c_str() + index, captureOption.c_str(), captureOption.size())) { 327 return true; 328 } else { 329 return false; 330 } 331 } 332 return false; 333} 334 335int HdcClient::ExecuteCommand(const string &commandIn) 336{ 337 char ip[BUF_SIZE_TINY] = ""; 338 uint16_t port = 0; 339 int ret = Base::ConnectKey2IPPort(channelHostPort.c_str(), ip, &port, sizeof(ip)); 340 if (ret < 0) { 341 WRITE_LOG(LOG_FATAL, "ConnectKey2IPPort %s failed with %d", 342 channelHostPort.c_str(), ret); 343 return -1; 344 } 345 346 if (!strncmp(commandIn.c_str(), CMDSTR_HILOG.c_str(), CMDSTR_HILOG.size()) && 347 IsCaptureCommand(commandIn)) { 348 RunExecuteCommand(commandIn); 349 return 0; 350 } 351 352 if (!strncmp(commandIn.c_str(), CMDSTR_FILE_SEND.c_str(), CMDSTR_FILE_SEND.size()) || 353 !strncmp(commandIn.c_str(), CMDSTR_FILE_RECV.c_str(), CMDSTR_FILE_RECV.size())) { 354 WRITE_LOG(LOG_DEBUG, "Set file send mode"); 355 channel->remote = RemoteType::REMOTE_FILE; 356 } 357 if (!strncmp(commandIn.c_str(), CMDSTR_APP_INSTALL.c_str(), CMDSTR_APP_INSTALL.size())) { 358 channel->remote = RemoteType::REMOTE_APP; 359 } 360 command = commandIn; 361 connectKey = AutoConnectKey(command, connectKey); 362 ConnectServerForClient(ip, port); 363 uv_timer_init(loopMain, &waitTimeDoCmd); 364 waitTimeDoCmd.data = this; 365 uv_timer_start(&waitTimeDoCmd, CommandWorker, UV_START_TIMEOUT, UV_START_REPEAT); 366 WorkerPendding(); 367 return 0; 368} 369 370int HdcClient::Initial(const string &connectKeyIn) 371{ 372 connectKey = connectKeyIn; 373 if (!channelHostPort.size() || !channelHost.size() || !channelPort) { 374 WRITE_LOG(LOG_FATAL, "Listen string initial failed"); 375 return ERR_PARM_FAIL; 376 } 377 return 0; 378} 379 380int HdcClient::ConnectServerForClient(const char *ip, uint16_t port) 381{ 382 if (uv_is_closing((const uv_handle_t *)&channel->hWorkTCP)) { 383 WRITE_LOG(LOG_FATAL, "ConnectServerForClient uv_is_closing"); 384 return ERR_SOCKET_FAIL; 385 } 386 WRITE_LOG(LOG_DEBUG, "Try to connect %s:%d", ip, port); 387 uv_connect_t *conn = new(std::nothrow) uv_connect_t(); 388 if (conn == nullptr) { 389 WRITE_LOG(LOG_FATAL, "ConnectServerForClient new conn failed"); 390 return ERR_GENERIC; 391 } 392 conn->data = this; 393 tcpConnectRetryCount = 0; 394 uv_timer_init(loopMain, &retryTcpConnTimer); 395 retryTcpConnTimer.data = this; 396 if (strchr(ip, '.')) { 397 isIpV4 = true; 398 std::string s = ip; 399 size_t index = s.find(IPV4_MAPPING_PREFIX); 400 size_t size = IPV4_MAPPING_PREFIX.size(); 401 if (index != std::string::npos) { 402 s = s.substr(index + size); 403 } 404 WRITE_LOG(LOG_DEBUG, "ConnectServerForClient ipv4 %s:%d", s.c_str(), port); 405 uv_ip4_addr(s.c_str(), port, &destv4); 406 uv_tcp_connect(conn, (uv_tcp_t *)&channel->hWorkTCP, (const struct sockaddr *)&destv4, Connect); 407 } else { 408 isIpV4 = false; 409 WRITE_LOG(LOG_DEBUG, "ConnectServerForClient ipv6 %s:%d", ip, port); 410 uv_ip6_addr(ip, port, &dest); 411 uv_tcp_connect(conn, (uv_tcp_t *)&channel->hWorkTCP, (const struct sockaddr *)&dest, Connect); 412 } 413 return 0; 414} 415 416void HdcClient::CommandWorker(uv_timer_t *handle) 417{ 418 const uint16_t maxWaitRetry = 1200; // client socket try 12s 419 HdcClient *thisClass = (HdcClient *)handle->data; 420 if (++thisClass->debugRetryCount > maxWaitRetry) { 421 uv_timer_stop(handle); 422 uv_stop(thisClass->loopMain); 423 WRITE_LOG(LOG_DEBUG, "Connect server failed"); 424 fprintf(stderr, "Connect server failed\n"); 425 return; 426 } 427 if (!thisClass->channel->handshakeOK) { 428 return; 429 } 430 uv_timer_stop(handle); 431 WRITE_LOG(LOG_DEBUG, "Connect server successful"); 432 bool closeInput = false; 433 if (!HostUpdater::ConfirmCommand(thisClass->command, closeInput)) { 434 uv_timer_stop(handle); 435 uv_stop(thisClass->loopMain); 436 WRITE_LOG(LOG_DEBUG, "Cmd \'%s\' has been canceld", thisClass->command.c_str()); 437 return; 438 } 439 while (closeInput) { 440#ifndef _WIN32 441 if (tcgetattr(STDIN_FILENO, &thisClass->terminalState)) { 442 break; 443 } 444 termios tio; 445 if (tcgetattr(STDIN_FILENO, &tio)) { 446 break; 447 } 448 cfmakeraw(&tio); 449 tio.c_cc[VTIME] = 0; 450 tio.c_cc[VMIN] = 1; 451 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio); 452 g_terminalStateChange = true; 453#endif 454 break; 455 } 456 thisClass->Send(thisClass->channel->channelId, 457 const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(thisClass->command.c_str())), 458 thisClass->command.size() + 1); 459} 460 461void HdcClient::AllocStdbuf(uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf) 462{ 463 if (sizeWanted <= 0) { 464 return; 465 } 466 HChannel context = (HChannel)handle->data; 467 int availSize = strlen(context->bufStd); 468 buf->base = (char *)context->bufStd + availSize; 469 buf->len = sizeof(context->bufStd) - availSize - 2; // reserve 2bytes 470} 471 472void HdcClient::ReadStd(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) 473{ 474 HChannel hChannel = (HChannel)stream->data; 475 HdcClient *thisClass = (HdcClient *)hChannel->clsChannel; 476 char *cmd = hChannel->bufStd; 477 if (nread <= 0) { 478 WRITE_LOG(LOG_FATAL, "ReadStd error nread:%zd", nread); 479 return; // error 480 } 481 thisClass->Send(hChannel->channelId, reinterpret_cast<uint8_t *>(cmd), strlen(cmd)); 482 Base::ZeroArray(hChannel->bufStd); 483} 484 485void HdcClient::ModifyTty(bool setOrRestore, uv_tty_t *tty) 486{ 487 if (setOrRestore) { 488#ifdef _WIN32 489 uv_tty_set_mode(tty, UV_TTY_MODE_RAW); 490#else 491 if (tcgetattr(STDIN_FILENO, &terminalState)) { 492 return; 493 } 494 termios tio; 495 if (tcgetattr(STDIN_FILENO, &tio)) { 496 return; 497 } 498 cfmakeraw(&tio); 499 tio.c_cc[VTIME] = 0; 500 tio.c_cc[VMIN] = 1; 501 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio); 502#endif 503 } else { 504#ifndef _WIN32 505 tcsetattr(STDIN_FILENO, TCSAFLUSH, &terminalState); 506#endif 507 } 508} 509 510void HdcClient::BindLocalStd(HChannel hChannel) 511{ 512 if (command == CMDSTR_SHELL) { 513 bShellInteractive = true; 514 } 515 if (bShellInteractive && uv_guess_handle(STDIN_FILENO) != UV_TTY) { 516 WRITE_LOG(LOG_WARN, "Not support stdio TTY mode"); 517 return; 518 } 519 520 WRITE_LOG(LOG_DEBUG, "setup stdio TTY mode"); 521 if (uv_tty_init(loopMain, &hChannel->stdoutTty, STDOUT_FILENO, 0) 522 || uv_tty_init(loopMain, &hChannel->stdinTty, STDIN_FILENO, 1)) { 523 WRITE_LOG(LOG_DEBUG, "uv_tty_init failed"); 524 return; 525 } 526 hChannel->stdoutTty.data = hChannel; 527 ++hChannel->uvHandleRef; 528 hChannel->stdinTty.data = hChannel; 529 ++hChannel->uvHandleRef; 530 if (bShellInteractive) { 531 WRITE_LOG(LOG_DEBUG, "uv_tty_init uv_tty_set_mode"); 532 ModifyTty(true, &hChannel->stdinTty); 533 uv_read_start((uv_stream_t *)&hChannel->stdinTty, AllocStdbuf, ReadStd); 534 } 535} 536 537void HdcClient::Connect(uv_connect_t *connection, int status) 538{ 539 WRITE_LOG(LOG_DEBUG, "Enter Connect, status:%d", status); 540 HdcClient *thisClass = (HdcClient *)connection->data; 541 delete connection; 542 HChannel hChannel = reinterpret_cast<HChannel>(thisClass->channel); 543 if (uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP)) { 544 WRITE_LOG(LOG_DEBUG, "uv_is_closing..."); 545 thisClass->FreeChannel(hChannel->channelId); 546 return; 547 } 548 549 // connect success 550 if (status == 0) { 551 thisClass->BindLocalStd(hChannel); 552 Base::SetTcpOptions((uv_tcp_t *)&hChannel->hWorkTCP); 553 WRITE_LOG(LOG_DEBUG, "uv_read_start"); 554 uv_read_start((uv_stream_t *)&hChannel->hWorkTCP, AllocCallback, ReadStream); 555 return; 556 } 557 558 // connect failed, start timer and retry 559 WRITE_LOG(LOG_DEBUG, "retry count:%d", thisClass->tcpConnectRetryCount); 560 if (thisClass->tcpConnectRetryCount >= TCP_CONNECT_MAX_RETRY_COUNT) { 561 WRITE_LOG(LOG_DEBUG, "stop retry for connect"); 562 thisClass->FreeChannel(hChannel->channelId); 563 return; 564 } 565 thisClass->tcpConnectRetryCount++; 566 uv_timer_start(&(thisClass->retryTcpConnTimer), thisClass->RetryTcpConnectWorker, TCP_CONNECT_RETRY_TIME_MS, 0); 567} 568 569void HdcClient::RetryTcpConnectWorker(uv_timer_t *handle) 570{ 571 HdcClient *thisClass = (HdcClient *)handle->data; 572 HChannel hChannel = reinterpret_cast<HChannel>(thisClass->channel); 573 uv_connect_t *connection = new(std::nothrow) uv_connect_t(); 574 if (connection == nullptr) { 575 WRITE_LOG(LOG_FATAL, "RetryTcpConnectWorker new conn failed"); 576 thisClass->FreeChannel(hChannel->channelId); 577 return; 578 } 579 connection->data = thisClass; 580 WRITE_LOG(LOG_DEBUG, "RetryTcpConnectWorker start tcp connect"); 581 if (thisClass->isIpV4) { 582 uv_tcp_connect(connection, &(thisClass->channel->hWorkTCP), 583 (const struct sockaddr *)&(thisClass->destv4), thisClass->Connect); 584 } else { 585 uv_tcp_connect(connection, &(thisClass->channel->hWorkTCP), 586 (const struct sockaddr *)&(thisClass->dest), thisClass->Connect); 587 } 588} 589 590int HdcClient::PreHandshake(HChannel hChannel, const uint8_t *buf) 591{ 592 ChannelHandShake *hShake = reinterpret_cast<ChannelHandShake *>(const_cast<uint8_t *>(buf)); 593 if (strncmp(hShake->banner, HANDSHAKE_MESSAGE.c_str(), HANDSHAKE_MESSAGE.size())) { 594 hChannel->availTailIndex = 0; 595 WRITE_LOG(LOG_DEBUG, "Channel Hello failed"); 596 return ERR_BUF_CHECK; 597 } 598 hChannel->isStableBuf = (hShake->banner[BANNER_FEATURE_TAG_OFFSET] != HUGE_BUF_TAG); 599 WRITE_LOG(LOG_DEBUG, "Channel PreHandshake isStableBuf:%d", hChannel->isStableBuf); 600 if (this->command == CMDSTR_WAIT_FOR && !connectKey.empty()) { 601 hShake->banner[WAIT_TAG_OFFSET] = WAIT_DEVICE_TAG; 602 } 603 // sync remote session id to local 604 uint32_t unOld = hChannel->channelId; 605 hChannel->channelId = ntohl(hShake->channelId); 606 AdminChannel(OP_UPDATE, unOld, hChannel); 607 WRITE_LOG(LOG_DEBUG, "Client channel handshake finished, use connectkey:%s", 608 Hdc::MaskString(connectKey).c_str()); 609 // send config 610 // channel handshake step2 611 if (memset_s(hShake->connectKey, sizeof(hShake->connectKey), 0, sizeof(hShake->connectKey)) != EOK 612 || memcpy_s(hShake->connectKey, sizeof(hShake->connectKey), connectKey.c_str(), connectKey.size()) != EOK) { 613 hChannel->availTailIndex = 0; 614 WRITE_LOG(LOG_DEBUG, "Channel Hello failed"); 615 return ERR_BUF_COPY; 616 } 617 618#ifdef HDC_VERSION_CHECK 619 // add check version 620 if (!isCheckVersionCmd) { // do not check version cause user want to get server version 621 string clientVer = Base::GetVersion() + HDC_MSG_HASH; 622 string serverVer(hShake->version); 623 624 if (clientVer != serverVer) { 625 serverVer = serverVer.substr(0, Base::GetVersion().size()); 626 WRITE_LOG(LOG_FATAL, "Client version:%s, server version:%s", clientVer.c_str(), serverVer.c_str()); 627 hChannel->availTailIndex = 0; 628 return ERR_CHECK_VERSION; 629 } 630 } 631 Send(hChannel->channelId, reinterpret_cast<uint8_t *>(hShake), sizeof(ChannelHandShake)); 632#else 633 // do not send version message if check feature disable 634 Send(hChannel->channelId, reinterpret_cast<uint8_t *>(hShake), offsetof(struct ChannelHandShake, version)); 635#endif 636 hChannel->handshakeOK = true; 637#ifdef HDC_CHANNEL_KEEP_ALIVE 638 // Evaluation method, non long-term support 639 Send(hChannel->channelId, 640 reinterpret_cast<uint8_t *>(const_cast<char*>(CMDSTR_INNER_ENABLE_KEEPALIVE.c_str())), 641 CMDSTR_INNER_ENABLE_KEEPALIVE.size()); 642#endif 643 return RET_SUCCESS; 644} 645 646// read serverForClient(server)TCP data 647int HdcClient::ReadChannel(HChannel hChannel, uint8_t *buf, const int bytesIO) 648{ 649 if (!hChannel->handshakeOK) { 650 return PreHandshake(hChannel, buf); 651 } 652#ifdef UNIT_TEST 653 // Do not output to console when the unit test 654 return 0; 655#endif 656 WRITE_LOG(LOG_DEBUG, "Client ReadChannel :%d", bytesIO); 657 658 uint16_t cmd = 0; 659 bool bOffset = false; 660 if (bytesIO >= static_cast<int>(sizeof(uint16_t))) { 661 cmd = *reinterpret_cast<uint16_t *>(buf); 662 bOffset = IsOffset(cmd); 663 } 664 if (cmd == CMD_CHECK_SERVER && isCheckVersionCmd) { 665 WRITE_LOG(LOG_DEBUG, "recieve CMD_CHECK_VERSION command"); 666 string version(reinterpret_cast<char *>(buf + sizeof(uint16_t)), bytesIO - sizeof(uint16_t)); 667 fprintf(stdout, "Client version:%s, server version:%s\n", Base::GetVersion().c_str(), version.c_str()); 668 fflush(stdout); 669 return 0; 670 } 671 if (hChannel->remote > RemoteType::REMOTE_NONE && bOffset) { 672 // file command 673 if (hChannel->remote == RemoteType::REMOTE_FILE) { 674 if (fileTask == nullptr) { 675 HTaskInfo hTaskInfo = GetRemoteTaskInfo(hChannel); 676 hTaskInfo->masterSlave = (cmd == CMD_FILE_INIT); 677 fileTask = std::make_unique<HdcFile>(hTaskInfo); 678 } 679 if (!fileTask->CommandDispatch(cmd, buf + sizeof(uint16_t), bytesIO - sizeof(uint16_t))) { 680 fileTask->TaskFinish(); 681 } 682 } 683 // app command 684 if (hChannel->remote == RemoteType::REMOTE_APP) { 685 if (appTask == nullptr) { 686 HTaskInfo hTaskInfo = GetRemoteTaskInfo(hChannel); 687 hTaskInfo->masterSlave = (cmd == CMD_APP_INIT); 688 appTask = std::make_unique<HdcHostApp>(hTaskInfo); 689 } 690 if (!appTask->CommandDispatch(cmd, buf + sizeof(uint16_t), bytesIO - sizeof(uint16_t))) { 691 appTask->TaskFinish(); 692 } 693 } 694 return 0; 695 } 696 697 string s(reinterpret_cast<char *>(buf), bytesIO); 698 if (WaitFor(s)) { 699 return 0; 700 } 701 s = ListTargetsAll(s); 702 if (g_show) { 703#ifdef _WIN32 704 fprintf(stdout, "%s", s.c_str()); 705 fflush(stdout); 706#else 707 constexpr int len = 512; 708 int size = s.size() / len; 709 int left = s.size() % len; 710 for (int i = 0; i <= size; i++) { 711 int cnt = len; 712 const char *p = reinterpret_cast<char *>(buf) + i * cnt; 713 if (i == size) { 714 cnt = left; 715 } 716 fprintf(stdout, "%.*s", cnt, p); 717 fflush(stdout); 718 std::this_thread::sleep_for(std::chrono::milliseconds(1)); 719 } 720#endif 721 } 722 return 0; 723} 724 725bool HdcClient::WaitFor(const string &str) 726{ 727 bool wait = false; 728 if (!strncmp(this->command.c_str(), CMDSTR_WAIT_FOR.c_str(), CMDSTR_WAIT_FOR.size())) { 729 const string waitFor = "[Fail]No any connected target"; 730 if (!strncmp(str.c_str(), waitFor.c_str(), waitFor.size())) { 731 Send(this->channel->channelId, reinterpret_cast<uint8_t *>(const_cast<char *>(this->command.c_str())), 732 this->command.size() + 1); 733 constexpr int timeout = 1; 734 std::this_thread::sleep_for(std::chrono::seconds(timeout)); 735 wait = true; 736 } else { 737 _exit(0); 738 } 739 } 740 return wait; 741} 742 743string HdcClient::ListTargetsAll(const string &str) 744{ 745 string all = str; 746 const string lists = "list targets -v"; 747 if (!strncmp(this->command.c_str(), lists.c_str(), lists.size())) { 748 UpdateList(str); 749 all = Base::ReplaceAll(all, "\n", "\thdc\n"); 750 } else if (!strncmp(this->command.c_str(), CMDSTR_LIST_TARGETS.c_str(), CMDSTR_LIST_TARGETS.size())) { 751 UpdateList(str); 752 } 753 if (!strncmp(this->command.c_str(), CMDSTR_LIST_TARGETS.c_str(), CMDSTR_LIST_TARGETS.size())) { 754 if (g_lists.size() > 0 && !strncmp(str.c_str(), EMPTY_ECHO.c_str(), EMPTY_ECHO.size())) { 755 all = ""; 756 } 757 } 758 return all; 759} 760 761void HdcClient::UpdateList(const string &str) 762{ 763 if (!strncmp(str.c_str(), EMPTY_ECHO.c_str(), EMPTY_ECHO.size())) { 764 return; 765 } 766 vector<string> devs; 767 Base::SplitString(str, "\n", devs); 768 for (size_t i = 0; i < devs.size(); i++) { 769 string::size_type pos = devs[i].find("\t"); 770 if (pos != string::npos) { 771 string key = devs[i].substr(0, pos); 772 g_lists[key] = "hdc"; 773 } else { 774 string key = devs[i]; 775 g_lists[key] = "hdc"; 776 } 777 } 778} 779 780bool HdcClient::IsOffset(uint16_t cmd) 781{ 782 return (cmd == CMD_CHECK_SERVER) || 783 (cmd == CMD_FILE_INIT) || 784 (cmd == CMD_FILE_CHECK) || 785 (cmd == CMD_FILE_BEGIN) || 786 (cmd == CMD_FILE_DATA) || 787 (cmd == CMD_FILE_FINISH) || 788 (cmd == CMD_FILE_MODE) || 789 (cmd == CMD_DIR_MODE) || 790 (cmd == CMD_APP_INIT) || 791 (cmd == CMD_APP_CHECK) || 792 (cmd == CMD_APP_BEGIN) || 793 (cmd == CMD_APP_DATA) || 794 (cmd == CMD_APP_FINISH); 795} 796 797HTaskInfo HdcClient::GetRemoteTaskInfo(HChannel hChannel) 798{ 799 HTaskInfo hTaskInfo = new TaskInformation(); 800 hTaskInfo->channelId = hChannel->channelId; 801 hTaskInfo->runLoop = loopMain; 802 hTaskInfo->serverOrDaemon = true; 803 hTaskInfo->channelTask = true; 804 hTaskInfo->channelClass = this; 805 hTaskInfo->isStableBuf = hChannel->isStableBuf; 806 hTaskInfo->isCleared = false; 807 return hTaskInfo; 808}; 809} // namespace Hdc 810