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 "server_for_client.h" 16#ifndef TEST_HASH 17#include "hdc_hash_gen.h" 18#endif 19#include "server.h" 20 21namespace Hdc { 22static const int MAX_RETRY_COUNT = 500; 23static const int MAX_CONNECT_DEVICE_RETRY_COUNT = 100; 24 25HdcServerForClient::HdcServerForClient(const bool serverOrClient, const string &addrString, void *pClsServer, 26 uv_loop_t *loopMainIn) 27 : HdcChannelBase(serverOrClient, addrString, loopMainIn) 28{ 29 clsServer = pClsServer; 30} 31 32HdcServerForClient::~HdcServerForClient() 33{ 34 WRITE_LOG(LOG_DEBUG, "~HdcServerForClient"); 35} 36 37void HdcServerForClient::Stop() 38{ 39 Base::TryCloseHandle((uv_handle_t *)&tcpListen); 40} 41 42uint16_t HdcServerForClient::GetTCPListenPort() 43{ 44 return channelPort; 45} 46 47void HdcServerForClient::AcceptClient(uv_stream_t *server, int status) 48{ 49 uv_tcp_t *pServTCP = (uv_tcp_t *)server; 50 HdcServerForClient *thisClass = (HdcServerForClient *)pServTCP->data; 51 HChannel hChannel = nullptr; 52 uint32_t uid = thisClass->MallocChannel(&hChannel); 53 if (!hChannel) { 54 WRITE_LOG(LOG_FATAL, "AcceptClient hChannel is nullptr"); 55 return; 56 } 57 int rc = uv_accept(server, (uv_stream_t *)&hChannel->hWorkTCP); 58 if (rc < 0) { 59 WRITE_LOG(LOG_FATAL, "AcceptClient uv_accept error rc:%d uid:%u", rc, uid); 60 thisClass->FreeChannel(uid); 61 return; 62 } 63 WRITE_LOG(LOG_DEBUG, "AcceptClient uid:%u", uid); 64 // limit first recv 65 int bufMaxSize = 0; 66 uv_recv_buffer_size((uv_handle_t *)&hChannel->hWorkTCP, &bufMaxSize); 67 auto funcChannelHeaderAlloc = [](uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf) -> void { 68 HChannel context = (HChannel)handle->data; 69 Base::ReallocBuf(&context->ioBuf, &context->bufSize, Base::GetMaxBufSize() * BUF_EXTEND_SIZE); 70 buf->base = (char *)context->ioBuf + context->availTailIndex; 71#ifdef HDC_VERSION_CHECK 72 buf->len = sizeof(struct ChannelHandShake) + DWORD_SERIALIZE_SIZE; // only recv static size 73#else 74 buf->len = offsetof(struct ChannelHandShake, version) + DWORD_SERIALIZE_SIZE; 75#endif 76 }; 77 // first packet static size, after this packet will be dup for normal recv 78 uv_read_start((uv_stream_t *)&hChannel->hWorkTCP, funcChannelHeaderAlloc, ReadStream); 79 // channel handshake step1 80 struct ChannelHandShake handShake = {}; 81 if (EOK == strcpy_s(handShake.banner, sizeof(handShake.banner), HANDSHAKE_MESSAGE.c_str())) { 82 handShake.banner[BANNER_FEATURE_TAG_OFFSET] = HUGE_BUF_TAG; // set feature tag for huge buf size 83 handShake.channelId = htonl(hChannel->channelId); 84 string ver = Base::GetVersion() + HDC_MSG_HASH; 85 WRITE_LOG(LOG_DEBUG, "Server ver:%s", ver.c_str()); 86 if (EOK != strcpy_s(handShake.version, sizeof(handShake.version), ver.c_str())) { 87 WRITE_LOG(LOG_FATAL, "strcpy_s failed"); 88 return; 89 } 90#ifdef HDC_VERSION_CHECK 91 thisClass->Send(hChannel->channelId, (uint8_t *)&handShake, sizeof(struct ChannelHandShake)); 92#else 93 // do not send version message if check feature disable 94 thisClass->Send(hChannel->channelId, reinterpret_cast<uint8_t *>(&handShake), 95 offsetof(struct ChannelHandShake, version)); 96#endif 97 } 98} 99 100bool HdcServerForClient::SetTCPListen() 101{ 102 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 103 tcpListen.data = this; 104 struct sockaddr_in6 addr; 105 uv_tcp_init(loopMain, &tcpListen); 106 107 WRITE_LOG(LOG_DEBUG, "channelHost %s, port: %d", channelHost.c_str(), channelPort); 108 int rc = uv_ip6_addr(channelHost.c_str(), channelPort, &addr); 109 if (rc != 0) { 110 uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT); 111 WRITE_LOG(LOG_FATAL, "uv_ip6_addr %d %s", rc, buffer); 112 return false; 113 } 114 rc = uv_tcp_bind(&tcpListen, (const struct sockaddr *)&addr, 0); 115 if (rc != 0) { 116 WRITE_LOG(LOG_WARN, "uv_tcp_bind ipv6 %d", rc); 117 if (rc == -EAFNOSUPPORT) { 118 size_t index = channelHost.find(IPV4_MAPPING_PREFIX); 119 size_t size = IPV4_MAPPING_PREFIX.size(); 120 if (index != std::string::npos) { 121 struct sockaddr_in addr4v; 122 std::string ipv4 = channelHost.substr(index + size); 123 uv_ip4_addr(ipv4.c_str(), channelPort, &addr4v); 124 rc = uv_tcp_bind(&tcpListen, (const struct sockaddr *)&addr4v, 0); 125 if (rc != 0) { 126 uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT); 127 WRITE_LOG(LOG_FATAL, "uv_tcp_bind ipv4 %s failed %d %s", 128 ipv4.c_str(), rc, buffer); 129 return false; 130 } 131 } 132 } else { 133 uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT); 134 WRITE_LOG(LOG_FATAL, "uv_tcp_bind %d %s", rc, buffer); 135 return false; 136 } 137 } 138 int backLog = 128; 139 rc = uv_listen((uv_stream_t *)&tcpListen, backLog, (uv_connection_cb)AcceptClient); 140 if (rc != 0) { 141 uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT); 142 WRITE_LOG(LOG_FATAL, "uv_listen %d %s", rc, buffer); 143 return false; 144 } 145 return true; 146} 147 148int HdcServerForClient::Initial() 149{ 150 if (!clsServer) { 151 WRITE_LOG(LOG_FATAL, "Module client initial failed"); 152 return -1; 153 } 154 if (!channelHostPort.size() || !channelHost.size() || !channelPort) { 155 WRITE_LOG(LOG_FATAL, "Listen string initial failed"); 156 return -2; // -2:err for Listen initial failed 157 } 158 bool b = SetTCPListen(); 159 if (!b) { 160 WRITE_LOG(LOG_FATAL, "SetTCPListen failed"); 161 int listenError = -3; // -3:error for SetTCPListen failed 162 return listenError; 163 } 164 return 0; 165} 166 167void HdcServerForClient::EchoClient(HChannel hChannel, MessageLevel level, const char *msg, ...) 168{ 169 string logInfo = ""; 170 switch (level) { 171 case MSG_FAIL: 172 logInfo = MESSAGE_FAIL; 173 break; 174 case MSG_INFO: 175 logInfo = MESSAGE_INFO; 176 break; 177 default: // successful, not append extra info 178 break; 179 } 180 va_list vaArgs; 181 va_start(vaArgs, msg); 182 string log = logInfo + Base::StringFormat(msg, vaArgs); 183 va_end(vaArgs); 184 if (log.back() != '\n') { 185 log += "\r\n"; 186 } 187 SendChannel(hChannel, const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(log.c_str())), log.size()); 188} 189 190void HdcServerForClient::EchoClientRaw(const HChannel hChannel, uint8_t *payload, const int payloadSize) 191{ 192 SendChannel(hChannel, payload, payloadSize); 193} 194 195// HdcServerForClient passthrough file command to client 196void HdcServerForClient::SendCommandToClient(const HChannel hChannel, const uint16_t commandFlag, 197 uint8_t *payload, const int payloadSize) 198{ 199 SendChannelWithCmd(hChannel, commandFlag, payload, payloadSize); 200} 201 202bool HdcServerForClient::SendToDaemon(HChannel hChannel, const uint16_t commandFlag, uint8_t *bufPtr, const int bufSize) 203{ 204 HDaemonInfo hdi = nullptr; 205 bool ret = false; 206 HdcServer *ptrServer = (HdcServer *)clsServer; 207 while (true) { 208 ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi); 209 if (hdi == nullptr) { 210 WRITE_LOG(LOG_FATAL, "SendToDaemon hdi nullptr"); 211 break; 212 } 213 if (hdi->connStatus != STATUS_CONNECTED) { 214 WRITE_LOG(LOG_FATAL, "SendToDaemon not connected"); 215 break; 216 } 217 if (!hdi->hSession) { 218 WRITE_LOG(LOG_FATAL, "SendToDaemon hdi->hSession nullptr"); 219 break; 220 } 221 if (ptrServer->Send(hdi->hSession->sessionId, hChannel->channelId, commandFlag, bufPtr, bufSize) < 0) { 222 WRITE_LOG(LOG_FATAL, "SendToDaemon Send failed channelId:%u", hChannel->channelId); 223 break; 224 } 225 ret = true; 226 break; 227 } 228 return ret; 229} 230 231void HdcServerForClient::OrderFindTargets(HChannel hChannel) 232{ 233 int count = 0; 234 EchoClient(hChannel, MSG_INFO, "Please add HDC server's firewall ruler to allow udp incoming, udpport:%d", 235 DEFAULT_PORT); 236 HdcServer *ptrServer = (HdcServer *)clsServer; 237 ptrServer->clsTCPClt->FindLanDaemon(); 238 list<string> &lst = ptrServer->clsTCPClt->lstDaemonResult; 239 // refresh main list 240 HdcDaemonInformation di; 241 while (!lst.empty()) { 242 di = {}; 243 ++count; 244 di.connectKey = lst.front(); 245 di.connType = CONN_TCP; 246 di.connStatus = STATUS_READY; 247 HDaemonInfo pDi = reinterpret_cast<HDaemonInfo>(&di); 248 ptrServer->AdminDaemonMap(OP_ADD, STRING_EMPTY, pDi); 249 lst.pop_front(); 250 } 251 EchoClient(hChannel, MSG_INFO, "Broadcast find daemon, total:%d", count); 252#ifdef UNIT_TEST 253 string bufString = std::to_string(count); 254 Base::WriteBinFile((UT_TMP_PATH + "/base-discover.result").c_str(), (uint8_t *)bufString.c_str(), bufString.size(), 255 true); 256#endif 257} 258 259void HdcServerForClient::OrderConnecTargetResult(uv_timer_t *req) 260{ 261 HChannel hChannel = (HChannel)req->data; 262 HdcServerForClient *thisClass = (HdcServerForClient *)hChannel->clsChannel; 263 HdcServer *ptrServer = (HdcServer *)thisClass->clsServer; 264 bool bConnectOK = false; 265 bool bExitRepet = false; 266 HDaemonInfo hdi = nullptr; 267 string sRet; 268 string target = std::string(hChannel->bufStd + 2); 269 if (target == "any") { 270 ptrServer->AdminDaemonMap(OP_GET_ANY, target, hdi); 271 } else { 272 ptrServer->AdminDaemonMap(OP_QUERY, target, hdi); 273 } 274 if (hdi && hdi->connStatus == STATUS_CONNECTED) { 275 bConnectOK = true; 276 } 277 while (true) { 278 if (bConnectOK) { 279 bExitRepet = true; 280 if (hChannel->isCheck) { 281 WRITE_LOG(LOG_INFO, "%s check device success and remove %s", __FUNCTION__, hChannel->key.c_str()); 282 thisClass->CommandRemoveSession(hChannel, hChannel->key.c_str()); 283 thisClass->EchoClient(hChannel, MSG_OK, const_cast<char *>(hdi->version.c_str())); 284 } else { 285 sRet = "Connect OK"; 286 thisClass->EchoClient(hChannel, MSG_OK, const_cast<char *>(sRet.c_str())); 287 } 288 break; 289 } else { 290 uint16_t *bRetryCount = reinterpret_cast<uint16_t *>(hChannel->bufStd); 291 ++(*bRetryCount); 292 if (*bRetryCount > MAX_RETRY_COUNT || 293 (hChannel->connectLocalDevice && *bRetryCount > MAX_CONNECT_DEVICE_RETRY_COUNT)) { 294 // 5s or localDevice 1s 295 bExitRepet = true; 296 sRet = "Connect failed"; 297 thisClass->EchoClient(hChannel, MSG_FAIL, const_cast<char *>(sRet.c_str())); 298 break; 299 } 300 } 301 break; 302 } 303 if (bExitRepet) { 304 thisClass->FreeChannel(hChannel->channelId); 305 Base::TryCloseHandle((const uv_handle_t *)req, Base::CloseTimerCallback); 306 } 307} 308 309bool HdcServerForClient::NewConnectTry(void *ptrServer, HChannel hChannel, const string &connectKey, bool isCheck) 310{ 311#ifdef HDC_DEBUG 312 WRITE_LOG(LOG_ALL, "%s %s", __FUNCTION__, Hdc::MaskString(connectKey).c_str()); 313#endif 314 int childRet = ((HdcServer *)ptrServer)->CreateConnect(connectKey, isCheck); 315 bool ret = false; 316 int connectError = -2; 317 constexpr uint8_t bufOffsetTwo = 2; 318 constexpr uint8_t bufOffsetThree = 3; 319 if (childRet == -1) { 320 EchoClient(hChannel, MSG_INFO, "Target is connected, repeat operation"); 321 } else if (childRet == connectError) { 322 EchoClient(hChannel, MSG_FAIL, "CreateConnect failed"); 323 WRITE_LOG(LOG_FATAL, "CreateConnect failed"); 324 } else { 325 size_t pos = connectKey.find(":"); 326 if (pos != std::string::npos) { 327 string ip = connectKey.substr(0, pos); 328 if (ip == "127.0.0.1") { 329 hChannel->connectLocalDevice = true; 330 } 331 } 332 Base::ZeroBuf(hChannel->bufStd, bufOffsetTwo); 333 childRet = snprintf_s(hChannel->bufStd + bufOffsetTwo, sizeof(hChannel->bufStd) - bufOffsetTwo, 334 sizeof(hChannel->bufStd) - bufOffsetThree, "%s", 335 const_cast<char *>(connectKey.c_str())); 336 if (childRet > 0) { 337 Base::TimerUvTask(loopMain, hChannel, OrderConnecTargetResult, UV_START_REPEAT); 338 ret = true; 339 } 340 } 341 return ret; 342} 343 344bool HdcServerForClient::CommandRemoveSession(HChannel hChannel, const char *connectKey) 345{ 346 HdcServer *ptrServer = (HdcServer *)clsServer; 347 HDaemonInfo hdiOld = nullptr; 348 (reinterpret_cast<HdcServer *>(ptrServer))->AdminDaemonMap(OP_QUERY, connectKey, hdiOld); 349 if (!hdiOld) { 350 EchoClient(hChannel, MSG_FAIL, "No target available"); 351 return false; 352 } 353 (reinterpret_cast<HdcServer *>(ptrServer))->FreeSession(hdiOld->hSession->sessionId); 354 return true; 355} 356 357bool HdcServerForClient::CommandRemoveForward(const string &forwardKey) 358{ 359 bool ret = RemoveFportkey("0|" + forwardKey); 360 ret |= RemoveFportkey("1|" + forwardKey); 361 return ret; 362} 363 364bool HdcServerForClient::RemoveFportkey(const string &forwardKey) 365{ 366 HdcServer *ptrServer = (HdcServer *)clsServer; 367 HForwardInfo hfi = nullptr; 368 ptrServer->AdminForwardMap(OP_QUERY, forwardKey, hfi); 369 if (!hfi) { 370 WRITE_LOG(LOG_FATAL, "CommandRemoveForward hfi nullptr forwardKey:%s", forwardKey.c_str()); 371 return false; 372 } 373 HSession hSession = ptrServer->AdminSession(OP_QUERY, hfi->sessionId, nullptr); 374 if (!hSession) { 375 WRITE_LOG(LOG_FATAL, "CommandRemoveForward hSession nullptr sessionId:%u", hfi->sessionId); 376 ptrServer->AdminForwardMap(OP_REMOVE, forwardKey, hfi); 377 return true; 378 } 379 ptrServer->ClearOwnTasks(hSession, hfi->channelId); 380 FreeChannel(hfi->channelId); 381 hfi = nullptr; 382 ptrServer->AdminForwardMap(OP_REMOVE, forwardKey, hfi); 383 return true; 384} 385 386void HdcServerForClient::GetTargetList(HChannel hChannel, void *formatCommandInput) 387{ 388 TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput; 389 HdcServer *ptrServer = (HdcServer *)clsServer; 390 uint16_t cmd = OP_GET_STRLIST; 391 if (formatCommand->parameters == "v") { 392 cmd = OP_GET_STRLIST_FULL; 393 } 394 HDaemonInfo hdi = nullptr; 395 string sRet = ptrServer->AdminDaemonMap(cmd, STRING_EMPTY, hdi); 396 if (!sRet.length()) { 397 sRet = EMPTY_ECHO; 398 } 399 EchoClient(hChannel, MSG_OK, const_cast<char *>(sRet.c_str())); 400#ifdef UNIT_TEST 401 Base::WriteBinFile((UT_TMP_PATH + "/base-list.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(), 402 MESSAGE_SUCCESS.size(), true); 403#endif 404} 405 406bool HdcServerForClient::GetAnyTarget(HChannel hChannel) 407{ 408 HdcServer *ptrServer = (HdcServer *)clsServer; 409 HDaemonInfo hdi = nullptr; 410 ptrServer->AdminDaemonMap(OP_GET_ANY, STRING_EMPTY, hdi); 411 if (!hdi) { 412 EchoClient(hChannel, MSG_FAIL, "No target available"); 413 return false; 414 } 415 // can not use hdi->connectKey.This memory may be released to re-Malloc 416 string connectKey = hdi->connectKey; 417 bool ret = NewConnectTry(ptrServer, hChannel, connectKey); 418#ifdef UNIT_TEST 419 Base::WriteBinFile((UT_TMP_PATH + "/base-any.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(), 420 MESSAGE_SUCCESS.size(), true); 421#endif 422 return ret; 423} 424 425bool HdcServerForClient::WaitForAny(HChannel hChannel) 426{ 427 HdcServer *ptrServer = (HdcServer *)clsServer; 428 HDaemonInfo hdi = nullptr; 429 if (!hChannel->connectKey.empty()) { 430 ptrServer->AdminDaemonMap(OP_WAIT_FOR_ANY, hChannel->connectKey, hdi); 431 } else { 432 ptrServer->AdminDaemonMap(OP_WAIT_FOR_ANY, STRING_EMPTY, hdi); 433 } 434 if (!hdi) { 435 EchoClient(hChannel, MSG_FAIL, "No any connected target"); 436 return false; 437 } 438 string key = hdi->connectKey; 439 EchoClient(hChannel, MSG_OK, "Wait for connected target is %s", key.c_str()); 440 return true; 441} 442 443bool HdcServerForClient::RemoveForward(HChannel hChannel, const char *parameterString) 444{ 445 HdcServer *ptrServer = (HdcServer *)clsServer; 446 if (parameterString == nullptr) { // remove all 447 HForwardInfo hfi = nullptr; // dummy 448 string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST, "", hfi); 449 if (!echo.length()) { 450 return false; 451 } 452 vector<string> filterStrings; 453 Base::SplitString(echo, string("\n"), filterStrings); 454 for (auto &&s : filterStrings) { 455 if (CommandRemoveForward(s.c_str())) { 456 EchoClient(hChannel, MSG_OK, "Remove forward ruler success, ruler:%s", s.c_str()); 457 } else { 458 EchoClient(hChannel, MSG_FAIL, "Remove forward ruler failed, ruler is not exist %s", s.c_str()); 459 } 460 } 461 } else { // remove single 462 if (CommandRemoveForward(parameterString)) { 463 EchoClient(hChannel, MSG_OK, "Remove forward ruler success, ruler:%s", parameterString); 464 } else { 465 EchoClient(hChannel, MSG_FAIL, "Remove forward ruler failed, ruler is not exist %s", parameterString); 466 } 467 } 468 return true; 469} 470 471bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandInput) 472{ 473 TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput; 474 HdcServer *ptrServer = (HdcServer *)clsServer; 475 bool ret = false; 476 // Main thread command, direct Listen main thread 477 switch (formatCommand->cmdFlag) { 478 case CMD_KERNEL_TARGET_DISCOVER: { 479 OrderFindTargets(hChannel); 480 ret = false; 481 break; 482 } 483 case CMD_KERNEL_TARGET_LIST: { 484 GetTargetList(hChannel, formatCommandInput); 485 ret = false; 486 break; 487 } 488 case CMD_CHECK_SERVER: { 489 WRITE_LOG(LOG_DEBUG, "CMD_CHECK_SERVER command"); 490 ReportServerVersion(hChannel); 491 ret = false; 492 break; 493 } 494 case CMD_WAIT_FOR: { 495 WRITE_LOG(LOG_DEBUG, "CMD_WAIT_FOR command"); 496 ret = !WaitForAny(hChannel); 497 break; 498 } 499 case CMD_KERNEL_TARGET_ANY: { 500#ifdef HDC_DEBUG 501 WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_ANY %s", __FUNCTION__, formatCommand->parameters.c_str()); 502#endif 503 ret = GetAnyTarget(hChannel); 504 break; 505 } 506 case CMD_KERNEL_TARGET_CONNECT: { 507#ifdef HDC_DEBUG 508 WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_CONNECT %s", __FUNCTION__, formatCommand->parameters.c_str()); 509#endif 510 ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str()); 511 break; 512 } 513 case CMD_CHECK_DEVICE: { 514 WRITE_LOG(LOG_INFO, "%s CMD_CHECK_DEVICE %s", __FUNCTION__, formatCommand->parameters.c_str()); 515 hChannel->isCheck = true; 516 hChannel->key = formatCommand->parameters.c_str(); 517 ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str(), true); 518 break; 519 } 520 case CMD_KERNEL_TARGET_DISCONNECT: { 521 CommandRemoveSession(hChannel, formatCommand->parameters.c_str()); 522 break; 523 } 524 // task will be global task,Therefore, it can only be controlled in the global session. 525 case CMD_FORWARD_LIST: { 526 HForwardInfo hfi = nullptr; // dummy 527 string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST_FULL, "", hfi); 528 if (!echo.length()) { 529 echo = EMPTY_ECHO; 530 } 531 EchoClient(hChannel, MSG_OK, const_cast<char *>(echo.c_str())); 532 break; 533 } 534 case CMD_FORWARD_REMOVE: { 535 RemoveForward(hChannel, formatCommand->parameters.c_str()); 536 break; 537 } 538 case CMD_KERNEL_ENABLE_KEEPALIVE: { 539 // just use for 'list targets' now 540 hChannel->keepAlive = true; 541 ret = true; 542 break; 543 } 544 default: { 545 EchoClient(hChannel, MSG_FAIL, "ExecuteCommand need connect-key? please confirm a device by help info"); 546 break; 547 } 548 } 549 return ret; 550} 551 552bool HdcServerForClient::TaskCommand(HChannel hChannel, void *formatCommandInput) 553{ 554 TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput; 555 HdcServer *ptrServer = (HdcServer *)clsServer; 556 string cmdFlag; 557 uint8_t sizeCmdFlag = 0; 558 if (formatCommand->cmdFlag == CMD_FILE_INIT) { 559 cmdFlag = "send "; 560 sizeCmdFlag = 5; // 5: cmdFlag send size 561 HandleRemote(hChannel, formatCommand->parameters, RemoteType::REMOTE_FILE); 562 } else if (formatCommand->cmdFlag == CMD_FORWARD_INIT) { 563 cmdFlag = "fport "; 564 sizeCmdFlag = 6; // 6: cmdFlag fport size 565 } else if (formatCommand->cmdFlag == CMD_APP_INIT) { 566 cmdFlag = "install "; 567 sizeCmdFlag = 8; // 8: cmdFlag install size 568 HandleRemote(hChannel, formatCommand->parameters, RemoteType::REMOTE_APP); 569 } else if (formatCommand->cmdFlag == CMD_APP_UNINSTALL) { 570 cmdFlag = "uninstall "; 571 sizeCmdFlag = 10; // 10: cmdFlag uninstall size 572 } else if (formatCommand->cmdFlag == CMD_UNITY_BUGREPORT_INIT) { 573 cmdFlag = "bugreport "; 574 sizeCmdFlag = 10; // 10: cmdFlag bugreport size 575 } else if (formatCommand->cmdFlag == CMD_APP_SIDELOAD) { 576 cmdFlag = "sideload "; 577 sizeCmdFlag = 9; // 9: cmdFlag sideload size 578 } else if (formatCommand->cmdFlag == CMD_FLASHD_UPDATE_INIT) { 579 cmdFlag = "update "; 580 sizeCmdFlag = 7; // 7: cmdFlag update size 581 } else if (formatCommand->cmdFlag == CMD_FLASHD_FLASH_INIT) { 582 cmdFlag = "flash "; 583 sizeCmdFlag = 6; // 6: cmdFlag flash size 584 } 585 int sizeSend = formatCommand->parameters.size(); 586 if (!strncmp(formatCommand->parameters.c_str(), cmdFlag.c_str(), sizeCmdFlag)) { // local do 587 HSession hSession = FindAliveSession(hChannel->targetSessionId); 588 if (!hSession) { 589 return false; 590 } 591 if ((formatCommand->cmdFlag == CMD_FILE_INIT || formatCommand->cmdFlag == CMD_APP_INIT) && 592 hChannel->fromClient) { 593 // remote client mode, CMD_FILE_INIT and CMD_APP_INIT command send back to client 594 WRITE_LOG(LOG_DEBUG, "command send back to remote client channelId:%u", hChannel->channelId); 595 SendChannelWithCmd(hChannel, formatCommand->cmdFlag, 596 reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag, 597 sizeSend - sizeCmdFlag); 598 return false; 599 } 600 ptrServer->DispatchTaskData(hSession, hChannel->channelId, formatCommand->cmdFlag, 601 reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag, 602 sizeSend - sizeCmdFlag); 603 } else { // Send to Daemon-side to do 604 SendToDaemon(hChannel, formatCommand->cmdFlag, 605 reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag, 606 sizeSend - sizeCmdFlag); 607 } 608 return true; 609} 610 611void HdcServerForClient::HandleRemote(HChannel hChannel, string ¶meters, RemoteType flag) 612{ 613 hChannel->remote = flag; 614 int argc = 0; 615 char **argv = Base::SplitCommandToArgs(parameters.c_str(), &argc); 616 for (int i = 0; i < argc; i++) { 617 if (argv[i] == CMDSTR_REMOTE_PARAMETER) { 618 hChannel->fromClient = true; 619 WRITE_LOG(LOG_DEBUG, "remote client mode channelId:%u", hChannel->channelId); 620 break; 621 } 622 } 623 if (hChannel->fromClient) { 624 string remote = CMDSTR_REMOTE_PARAMETER + " "; 625 if (parameters.find(remote) != std::string::npos) { 626 parameters.replace(parameters.find(remote), remote.size(), ""); 627 WRITE_LOG(LOG_DEBUG, "parameters: %s", parameters.c_str()); 628 } 629 } 630} 631 632bool HdcServerForClient::DoCommandRemote(HChannel hChannel, void *formatCommandInput) 633{ 634 TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput; 635 bool ret = false; 636 int sizeSend = formatCommand->parameters.size(); 637 string cmdFlag; 638 switch (formatCommand->cmdFlag) { 639 // Some simple commands only need to forward the instruction, no need to start Task 640 case CMD_SHELL_INIT: 641 case CMD_SHELL_DATA: 642 case CMD_UNITY_EXECUTE: 643 case CMD_UNITY_REMOUNT: 644 case CMD_UNITY_REBOOT: 645 case CMD_UNITY_RUNMODE: 646 case CMD_UNITY_HILOG: 647 case CMD_UNITY_ROOTRUN: 648 case CMD_JDWP_TRACK: 649 case CMD_JDWP_LIST: { 650 if (!SendToDaemon(hChannel, formatCommand->cmdFlag, 651 reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())), 652 sizeSend)) { 653 break; 654 } 655 ret = true; 656 if (formatCommand->cmdFlag == CMD_SHELL_INIT) { 657 hChannel->interactiveShellMode = true; 658 } 659 break; 660 } 661 case CMD_FILE_INIT: 662 case CMD_FORWARD_INIT: 663 case CMD_APP_INIT: 664 case CMD_APP_UNINSTALL: 665 case CMD_UNITY_BUGREPORT_INIT: 666 case CMD_APP_SIDELOAD: 667 case CMD_FLASHD_UPDATE_INIT: 668 case CMD_FLASHD_FLASH_INIT: 669 case CMD_FLASHD_ERASE: 670 case CMD_FLASHD_FORMAT: { 671 TaskCommand(hChannel, formatCommandInput); 672 ret = true; 673 break; 674 } 675 default: 676 break; 677 } 678 if (!ret) { 679 EchoClient(hChannel, MSG_FAIL, "Failed to communicate with daemon"); 680 } 681 return ret; 682} 683// Do not specify Target's operations no longer need to put it in the thread. 684bool HdcServerForClient::DoCommand(HChannel hChannel, void *formatCommandInput) 685{ 686 bool ret = false; 687 TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput; 688 if (!hChannel->hChildWorkTCP.loop || formatCommand->cmdFlag == CMD_FORWARD_REMOVE) { 689 // Main thread command, direct Listen main thread 690 ret = DoCommandLocal(hChannel, formatCommandInput); 691 } else { // CONNECT DAEMON's work thread command, non-primary thread 692 ret = DoCommandRemote(hChannel, formatCommandInput); 693 } 694 return ret; 695} 696 697// just call from BindChannelToSession 698HSession HdcServerForClient::FindAliveSessionFromDaemonMap(const HChannel hChannel) 699{ 700 HSession hSession = nullptr; 701 HDaemonInfo hdi = nullptr; 702 HdcServer *ptrServer = (HdcServer *)clsServer; 703 ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi); 704 if (!hdi) { 705 EchoClient(hChannel, MSG_FAIL, "Not match target founded, check connect-key please"); 706 return nullptr; 707 } 708 if (hdi->connStatus != STATUS_CONNECTED) { 709 EchoClient(hChannel, MSG_FAIL, "Device not founded or connected"); 710 return nullptr; 711 } 712 if (hdi->hSession->isDead) { 713 EchoClient(hChannel, MSG_FAIL, "Bind tartget session is dead"); 714 return nullptr; 715 } 716 if (!hdi->hSession->handshakeOK) { 717 WRITE_LOG(LOG_WARN, "hSession handShake is false sid:%u cid:%u", 718 hdi->hSession->sessionId, hChannel->channelId); 719 const string errMsg = "[E000004]:The communication channel is being established.\r\n"\ 720 "Please wait for several seconds and try again."; 721 EchoClient(hChannel, MSG_FAIL, errMsg.c_str()); 722 return nullptr; 723 } 724 hSession = reinterpret_cast<HSession>(hdi->hSession); 725 return hSession; 726} 727 728int HdcServerForClient::BindChannelToSession(HChannel hChannel, uint8_t *bufPtr, const int bytesIO) 729{ 730 if (FindAliveSessionFromDaemonMap(hChannel) == nullptr) { 731 WRITE_LOG(LOG_FATAL, "Find no alive session channelId:%u", hChannel->channelId); 732 return ERR_SESSION_NOFOUND; 733 } 734 bool isClosing = uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP); 735 if (!isClosing && (hChannel->fdChildWorkTCP = Base::DuplicateUvSocket(&hChannel->hWorkTCP)) < 0) { 736 WRITE_LOG(LOG_FATAL, "Duplicate socket failed channelId:%u", hChannel->channelId); 737 return ERR_SOCKET_DUPLICATE; 738 } 739 uv_close_cb funcWorkTcpClose = [](uv_handle_t *handle) -> void { 740 HChannel hChannel = (HChannel)handle->data; 741 --hChannel->ref; 742 }; 743 ++hChannel->ref; 744 if (!isClosing) { 745 uv_close((uv_handle_t *)&hChannel->hWorkTCP, funcWorkTcpClose); 746 } 747 Base::DoNextLoop(loopMain, hChannel, [](const uint8_t flag, string &msg, const void *data) { 748 // Thread message can avoid using thread lock and improve program efficiency 749 // If not next loop call, ReadStream will thread conflict 750 HChannel hChannel = (HChannel)data; 751 auto thisClass = (HdcServerForClient *)hChannel->clsChannel; 752 HSession hSession = nullptr; 753 if ((hSession = thisClass->FindAliveSessionFromDaemonMap(hChannel)) == nullptr) { 754 WRITE_LOG(LOG_FATAL, "hSession nullptr channelId:%u", hChannel->channelId); 755 return; 756 } 757 auto ctrl = HdcSessionBase::BuildCtrlString(SP_ATTACH_CHANNEL, hChannel->channelId, nullptr, 0); 758 Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size()); 759 }); 760 return RET_SUCCESS; 761} 762 763bool HdcServerForClient::CheckAutoFillTarget(HChannel hChannel) 764{ 765 HdcServer *ptrServer = (HdcServer *)clsServer; 766 if (!hChannel->connectKey.size()) { 767 WRITE_LOG(LOG_FATAL, "connectKey.size 0 channelId:%u", hChannel->channelId); 768 return false; // Operation of non-bound destination of scanning 769 } 770 if (hChannel->connectKey == CMDSTR_CONNECT_ANY) { 771 HDaemonInfo hdiOld = nullptr; 772 ptrServer->AdminDaemonMap(OP_GET_ONLY, "", hdiOld); 773 if (!hdiOld) { 774 WRITE_LOG(LOG_WARN, "No any key found channelId:%u", hChannel->channelId); 775 return false; 776 } 777 if (!hdiOld->hSession) { 778 WRITE_LOG(LOG_WARN, "hSession is null. channelId:%u", hChannel->channelId); 779 return false; 780 } 781 if (!hdiOld->hSession->handshakeOK) { 782 WRITE_LOG(LOG_WARN, "hSession handShake is false SessionId:%u", hdiOld->hSession->sessionId); 783 return false; 784 } 785 hChannel->connectKey = hdiOld->connectKey; 786 return true; 787 } 788 return true; 789} 790 791int HdcServerForClient::ChannelHandShake(HChannel hChannel, uint8_t *bufPtr, const int bytesIO) 792{ 793 vector<uint8_t> rebuildHandshake; 794 rebuildHandshake.insert(rebuildHandshake.end(), bufPtr, bufPtr + bytesIO); 795 rebuildHandshake.push_back(0x00); 796 struct ChannelHandShake *handShake = reinterpret_cast<struct ChannelHandShake *>(rebuildHandshake.data()); 797 if (strncmp(handShake->banner, HANDSHAKE_MESSAGE.c_str(), HANDSHAKE_MESSAGE.size())) { 798 hChannel->availTailIndex = 0; 799 WRITE_LOG(LOG_DEBUG, "Channel Hello failed"); 800 return ERR_HANDSHAKE_NOTMATCH; 801 } 802 if (strlen(handShake->connectKey) > sizeof(handShake->connectKey)) { 803 hChannel->availTailIndex = 0; 804 WRITE_LOG(LOG_DEBUG, "Connectkey's size incorrect"); 805 return ERR_HANDSHAKE_CONNECTKEY_FAILED; 806 } 807 // channel handshake step3 808 WRITE_LOG(LOG_DEBUG, "ServerForClient cid:%u sid:%u handshake finished", 809 hChannel->channelId, hChannel->targetSessionId); 810 hChannel->connectKey = handShake->connectKey; 811 hChannel->handshakeOK = true; 812 if (handShake->banner[WAIT_TAG_OFFSET] == WAIT_DEVICE_TAG || !CheckAutoFillTarget(hChannel)) { 813 WRITE_LOG(LOG_WARN, "No target channelId:%u", hChannel->channelId); 814 return 0; 815 } 816 // channel handshake stBindChannelToSession 817 if (BindChannelToSession(hChannel, nullptr, 0)) { 818 hChannel->availTailIndex = 0; 819 WRITE_LOG(LOG_FATAL, "BindChannelToSession failed channelId:%u sid:%u", 820 hChannel->channelId, hChannel->targetSessionId); 821 return ERR_GENERIC; 822 } 823 return 0; 824} 825 826void HdcServerForClient::ReportServerVersion(HChannel hChannel) 827{ 828 string version = Base::GetVersion(); 829 SendChannelWithCmd(hChannel, CMD_CHECK_SERVER, 830 const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(version.c_str())), 831 version.size()); 832} 833 834// Here is Server to get data, the source is the SERVER's ChildWork to send data 835int HdcServerForClient::ReadChannel(HChannel hChannel, uint8_t *bufPtr, const int bytesIO) 836{ 837 int ret = 0; 838 if (!hChannel->handshakeOK) { 839 return ChannelHandShake(hChannel, bufPtr, bytesIO); 840 } 841 HDaemonInfo hdi = nullptr; 842 HdcServer *ptrServer = (HdcServer *)clsServer; 843 ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi); 844 if (hdi && !hdi->emgmsg.empty()) { 845 EchoClient(hChannel, MSG_FAIL, hdi->emgmsg.c_str()); 846 return ERR_GENERIC; 847 } 848 uint16_t command = *reinterpret_cast<uint16_t *>(bufPtr); 849 if (command != 0 && (hChannel->remote > RemoteType::REMOTE_NONE)) { 850 // server directly passthrough file command to daemon 851 if (!SendToDaemon(hChannel, command, bufPtr + sizeof(uint16_t), bytesIO - sizeof(uint16_t))) { 852 WRITE_LOG(LOG_FATAL, "Client ReadChannel : direct send to daemon failed"); 853 } 854 return ret; 855 } 856 struct TranslateCommand::FormatCommand formatCommand = { 0 }; 857 if (!hChannel->interactiveShellMode) { 858 string retEcho = String2FormatCommand(reinterpret_cast<char *>(bufPtr), bytesIO, &formatCommand); 859 if (retEcho.length()) { 860 if (!strncmp(reinterpret_cast<char *>(bufPtr), CMDSTR_SOFTWARE_HELP.c_str(), 861 CMDSTR_SOFTWARE_HELP.size()) || 862 !strcmp(reinterpret_cast<char *>(bufPtr), CMDSTR_SOFTWARE_VERSION.c_str()) || 863 !strcmp(reinterpret_cast<char *>(bufPtr), "flash")) { 864 EchoClient(hChannel, MSG_OK, retEcho.c_str()); 865 } else { 866 EchoClient(hChannel, MSG_FAIL, retEcho.c_str()); 867 } 868 } 869 WRITE_LOG(LOG_DEBUG, "ReadChannel cid:%u sid:%u key:%s command: %s", 870 hChannel->channelId, hChannel->targetSessionId, Hdc::MaskString(hChannel->connectKey).c_str(), bufPtr); 871 if (formatCommand.bJumpDo) { 872 WRITE_LOG(LOG_FATAL, "ReadChannel bJumpDo true"); 873 return -10; // -10 error formatCommand 874 } 875 } else { 876 formatCommand.parameters = string(reinterpret_cast<char *>(bufPtr), bytesIO); 877 formatCommand.cmdFlag = CMD_SHELL_DATA; 878 } 879 880 if (!DoCommand(hChannel, &formatCommand)) { 881 return -3; // -3: error or want close 882 } 883 ret = bytesIO; 884 return ret; 885}; 886 887// avoid session dead 888HSession HdcServerForClient::FindAliveSession(uint32_t sessionId) 889{ 890 HdcServer *ptrServer = (HdcServer *)clsServer; 891 HSession hSession = ptrServer->AdminSession(OP_QUERY, sessionId, nullptr); 892 if (!hSession || hSession->isDead) { 893 WRITE_LOG(LOG_FATAL, "FindAliveSession hSession nullptr or isDead sessionId:%u", sessionId); 894 return nullptr; 895 } else { 896 return hSession; 897 } 898} 899 900bool HdcServerForClient::ChannelSendSessionCtrlMsg(vector<uint8_t> &ctrlMsg, uint32_t sessionId) 901{ 902 HSession hSession = FindAliveSession(sessionId); 903 if (!hSession) { 904 WRITE_LOG(LOG_FATAL, "ChannelSendSessionCtrlMsg hSession nullptr sessionId:%u", sessionId); 905 return false; 906 } 907 int rc = Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrlMsg.data(), ctrlMsg.size()); 908 if (rc <= 0) { 909 WRITE_LOG(LOG_FATAL, "send ctrlmsg failed sessionId:%u rc:%d", sessionId, rc); 910 } 911 return rc > 0; 912} 913} // namespace Hdc 914