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.h" 16#include "host_updater.h" 17 18 19namespace Hdc { 20HdcServer::HdcServer(bool serverOrDaemonIn) 21 : HdcSessionBase(serverOrDaemonIn) 22{ 23 clsTCPClt = nullptr; 24 clsUSBClt = nullptr; 25#ifdef HDC_SUPPORT_UART 26 clsUARTClt = nullptr; 27#endif 28 clsServerForClient = nullptr; 29 uv_rwlock_init(&daemonAdmin); 30 uv_rwlock_init(&forwardAdmin); 31} 32 33HdcServer::~HdcServer() 34{ 35 WRITE_LOG(LOG_DEBUG, "~HdcServer"); 36 uv_rwlock_destroy(&daemonAdmin); 37 uv_rwlock_destroy(&forwardAdmin); 38} 39 40void HdcServer::ClearInstanceResource() 41{ 42 TryStopInstance(); 43 Base::TryCloseLoop(&loopMain, "HdcServer::~HdcServer"); 44 if (clsTCPClt) { 45 delete clsTCPClt; 46 } 47 if (clsUSBClt) { 48 delete clsUSBClt; 49 } 50#ifdef HDC_SUPPORT_UART 51 if (clsUARTClt) { 52 delete clsUARTClt; 53 } 54#endif 55 if (clsServerForClient) { 56 delete (static_cast<HdcServerForClient *>(clsServerForClient)); 57 } 58} 59 60void HdcServer::TryStopInstance() 61{ 62 ClearSessions(); 63 if (clsTCPClt) { 64 clsTCPClt->Stop(); 65 } 66 if (clsUSBClt) { 67 clsUSBClt->Stop(); 68 } 69#ifdef HDC_SUPPORT_UART 70 if (clsUARTClt) { 71 clsUARTClt->Stop(); 72 } 73#endif 74 if (clsServerForClient) { 75 ((HdcServerForClient *)clsServerForClient)->Stop(); 76 } 77 ReMainLoopForInstanceClear(); 78 ClearMapDaemonInfo(); 79} 80 81bool HdcServer::Initial(const char *listenString) 82{ 83 if (Base::ProgramMutex(SERVER_NAME.c_str(), false) != 0) { 84 WRITE_LOG(LOG_FATAL, "Other instance already running, program mutex failed"); 85 return false; 86 } 87 Base::RemoveLogFile(); 88 clsServerForClient = new HdcServerForClient(true, listenString, this, &loopMain); 89 int rc = (static_cast<HdcServerForClient *>(clsServerForClient))->Initial(); 90 if (rc != RET_SUCCESS) { 91 WRITE_LOG(LOG_FATAL, "clsServerForClient Initial failed"); 92 return false; 93 } 94 clsUSBClt->InitLogging(ctxUSB); 95 clsTCPClt = new HdcHostTCP(true, this); 96 clsUSBClt = new HdcHostUSB(true, this, ctxUSB); 97 if (clsUSBClt->Initial() != RET_SUCCESS) { 98 WRITE_LOG(LOG_FATAL, "clsUSBClt Initial failed"); 99 return false; 100 } 101 if (!clsServerForClient || !clsTCPClt || !clsUSBClt) { 102 WRITE_LOG(LOG_FATAL, "Class init failed"); 103 return false; 104 } 105 106#ifdef HDC_SUPPORT_UART 107 clsUARTClt = new HdcHostUART(*this); 108 if (!clsUARTClt) { 109 WRITE_LOG(LOG_FATAL, "Class init failed"); 110 return false; 111 } 112 if (clsUARTClt->Initial() != RET_SUCCESS) { 113 WRITE_LOG(LOG_FATAL, "clsUARTClt Class init failed."); 114 return false; 115 } 116#endif 117 return true; 118} 119 120bool HdcServer::PullupServerWin32(const char *path, const char *listenString) 121{ 122 bool retVal = false; 123#ifdef _WIN32 124 char buf[BUF_SIZE_SMALL] = ""; 125 char shortPath[MAX_PATH] = ""; 126 std::string strPath = Base::UnicodeToUtf8(path, true); 127 int ret = GetShortPathName(strPath.c_str(), shortPath, MAX_PATH); 128 std::string runPath = shortPath; 129 if (ret == 0) { 130 int err = GetLastError(); 131 constexpr int bufSize = 1024; 132 char buffer[bufSize] = { 0 }; 133 strerror_s(buffer, bufSize, err); 134 WRITE_LOG(LOG_WARN, "GetShortPath path:[%s] errmsg:%s", path, buffer); 135 string uvPath = path; 136 runPath = uvPath.substr(uvPath.find_last_of("/\\") + 1); 137 } 138 WRITE_LOG(LOG_DEBUG, "server shortpath:[%s] runPath:[%s]", shortPath, runPath.c_str()); 139 // here we give a dummy option first, because getopt will assume the first option is command. it 140 // begin from 2nd args. 141 if (sprintf_s(buf, sizeof(buf), "dummy -l %d -s %s -m", Base::GetLogLevelByEnv(), listenString) < 0) { 142 return retVal; 143 } 144 WRITE_LOG(LOG_DEBUG, "Run server in debug-forground, cmd:%s, args:%s", runPath.c_str(), buf); 145 STARTUPINFO si = {}; 146 si.cb = sizeof(STARTUPINFO); 147 PROCESS_INFORMATION pi = {}; 148#ifndef HDC_DEBUG 149 si.dwFlags = STARTF_USESHOWWINDOW; 150 si.wShowWindow = SW_HIDE; 151#endif 152 if (!CreateProcess(runPath.c_str(), buf, nullptr, nullptr, false, CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi)) { 153 WRITE_LOG(LOG_WARN, "CreateProcess failed with cmd:%s, args:%s, Error Code %d", runPath.c_str(), buf, 154 GetLastError()); 155 retVal = false; 156 } else { 157 retVal = true; 158 } 159 CloseHandle(pi.hThread); 160 CloseHandle(pi.hProcess); 161#endif 162 return retVal; 163} 164 165// Only detects that the default call is in the loop address, the other tubes are not 166bool HdcServer::PullupServer(const char *listenString) 167{ 168 char path[BUF_SIZE_SMALL] = ""; 169 size_t nPathSize = sizeof(path); 170 int ret = uv_exepath(path, &nPathSize); 171 if (ret < 0) { 172 constexpr int bufSize = 1024; 173 char buf[bufSize] = { 0 }; 174 uv_err_name_r(ret, buf, bufSize); 175 WRITE_LOG(LOG_WARN, "uvexepath ret:%d error:%s", ret, buf); 176 return false; 177 } 178 Base::CreateLogDir(); 179 180#ifdef _WIN32 181 if (!PullupServerWin32(path, listenString)) { 182 return false; 183 } 184#else 185 pid_t pc = fork(); // create process as daemon process 186 if (pc < 0) { 187 return false; 188 } else if (!pc) { 189 int i; 190 const int maxFD = 1024; 191 for (i = 0; i < maxFD; ++i) { 192 // close file pipe 193 int fd = i; 194 Base::CloseFd(fd); 195 } 196 execl(path, "hdc", "-m", "-s", listenString, nullptr); 197 exit(0); 198 return true; 199 } 200 // orig process 201#endif 202 // wait little time, util backend-server work ready 203 uv_sleep(TIME_BASE); 204 return true; 205} 206 207void HdcServer::ClearMapDaemonInfo() 208{ 209 map<string, HDaemonInfo>::iterator iter; 210 uv_rwlock_rdlock(&daemonAdmin); 211 for (iter = mapDaemon.begin(); iter != mapDaemon.end();) { 212 string sKey = iter->first; 213 HDaemonInfo hDi = iter->second; 214 delete hDi; 215 ++iter; 216 } 217 uv_rwlock_rdunlock(&daemonAdmin); 218 uv_rwlock_wrlock(&daemonAdmin); 219 mapDaemon.clear(); 220 uv_rwlock_wrunlock(&daemonAdmin); 221} 222 223void HdcServer::BuildDaemonVisableLine(HDaemonInfo hdi, bool fullDisplay, string &out) 224{ 225 if (fullDisplay) { 226 string sConn = conTypeDetail[CONN_UNKNOWN]; 227 if (hdi->connType < CONN_UNKNOWN) { 228 sConn = conTypeDetail[hdi->connType]; 229 } 230 231 string sStatus = conStatusDetail[STATUS_UNKNOW]; 232 if (hdi->connStatus < STATUS_UNAUTH) { 233 if (hdi->connStatus == STATUS_CONNECTED && hdi->daemonAuthStatus == DAEOMN_UNAUTHORIZED) { 234 sStatus = conStatusDetail[STATUS_UNAUTH]; 235 } else { 236 sStatus = conStatusDetail[hdi->connStatus]; 237 } 238 } 239 240 string devname = hdi->devName; 241 if (devname.empty()) { 242 devname = "unknown..."; 243 } 244 out = Base::StringFormat("%s\t\t%s\t%s\t%s\n", hdi->connectKey.c_str(), sConn.c_str(), sStatus.c_str(), 245 devname.c_str()); 246 } else { 247 if (hdi->connStatus == STATUS_CONNECTED) { 248 out = Base::StringFormat("%s", hdi->connectKey.c_str()); 249 if (hdi->daemonAuthStatus == DAEOMN_UNAUTHORIZED) { 250 out.append("\tUnauthorized"); 251 } 252 out.append("\n"); 253 } 254 } 255} 256 257string HdcServer::GetDaemonMapList(uint8_t opType) 258{ 259 string ret; 260 bool fullDisplay = false; 261 if (opType == OP_GET_STRLIST_FULL) { 262 fullDisplay = true; 263 } 264 uv_rwlock_rdlock(&daemonAdmin); 265 map<string, HDaemonInfo>::iterator iter; 266 string echoLine; 267 for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) { 268 HDaemonInfo di = iter->second; 269 if (!di) { 270 continue; 271 } 272 echoLine = ""; 273 BuildDaemonVisableLine(di, fullDisplay, echoLine); 274 ret += echoLine; 275 } 276 uv_rwlock_rdunlock(&daemonAdmin); 277 return ret; 278} 279 280void HdcServer::GetDaemonMapOnlyOne(HDaemonInfo &hDaemonInfoInOut) 281{ 282 uv_rwlock_rdlock(&daemonAdmin); 283 string key; 284 for (auto &i : mapDaemon) { 285 if (i.second->connStatus == STATUS_CONNECTED) { 286 if (key == STRING_EMPTY) { 287 key = i.first; 288 } else { 289 key = STRING_EMPTY; 290 break; 291 } 292 } 293 } 294 if (key.size() > 0) { 295 hDaemonInfoInOut = mapDaemon[key]; 296 } 297 uv_rwlock_rdunlock(&daemonAdmin); 298} 299 300void HdcServer::AdminDaemonMapForWait(const string &connectKey, HDaemonInfo &hDaemonInfoInOut) 301{ 302 map<string, HDaemonInfo>::iterator iter; 303 for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) { 304 HDaemonInfo di = iter->second; 305 if (di->connStatus == STATUS_CONNECTED) { 306 if (!connectKey.empty() && connectKey != di->connectKey) { 307 continue; 308 } 309 hDaemonInfoInOut = di; 310 return; 311 } 312 } 313 return; 314} 315 316string HdcServer::AdminDaemonMap(uint8_t opType, const string &connectKey, HDaemonInfo &hDaemonInfoInOut) 317{ 318 string sRet; 319 switch (opType) { 320 case OP_ADD: { 321 HDaemonInfo pdiNew = new(std::nothrow) HdcDaemonInformation(); 322 if (pdiNew == nullptr) { 323 WRITE_LOG(LOG_FATAL, "AdminDaemonMap new pdiNew failed"); 324 break; 325 } 326 *pdiNew = *hDaemonInfoInOut; 327 uv_rwlock_wrlock(&daemonAdmin); 328 if (!mapDaemon[hDaemonInfoInOut->connectKey]) { 329 mapDaemon[hDaemonInfoInOut->connectKey] = pdiNew; 330 } 331 uv_rwlock_wrunlock(&daemonAdmin); 332 break; 333 } 334 case OP_GET_STRLIST: 335 case OP_GET_STRLIST_FULL: { 336 sRet = GetDaemonMapList(opType); 337 break; 338 } 339 case OP_QUERY: { 340 uv_rwlock_rdlock(&daemonAdmin); 341 if (mapDaemon.count(connectKey)) { 342 hDaemonInfoInOut = mapDaemon[connectKey]; 343 } 344 uv_rwlock_rdunlock(&daemonAdmin); 345 break; 346 } 347 case OP_REMOVE: { 348 uv_rwlock_wrlock(&daemonAdmin); 349 if (mapDaemon.count(connectKey)) { 350 mapDaemon.erase(connectKey); 351 } 352 uv_rwlock_wrunlock(&daemonAdmin); 353 break; 354 } 355 case OP_GET_ANY: { 356 uv_rwlock_rdlock(&daemonAdmin); 357 map<string, HDaemonInfo>::iterator iter; 358 for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) { 359 HDaemonInfo di = iter->second; 360 // usb will be auto connected 361 if (di->connStatus == STATUS_READY || di->connStatus == STATUS_CONNECTED) { 362 hDaemonInfoInOut = di; 363 break; 364 } 365 } 366 uv_rwlock_rdunlock(&daemonAdmin); 367 break; 368 } 369 case OP_WAIT_FOR_ANY: { 370 uv_rwlock_rdlock(&daemonAdmin); 371 AdminDaemonMapForWait(connectKey, hDaemonInfoInOut); 372 uv_rwlock_rdunlock(&daemonAdmin); 373 break; 374 } 375 case OP_GET_ONLY: { 376 GetDaemonMapOnlyOne(hDaemonInfoInOut); 377 break; 378 } 379 case OP_UPDATE: { // Cannot update the Object HDi lower key value by direct value 380 uv_rwlock_wrlock(&daemonAdmin); 381 HDaemonInfo hdi = mapDaemon[hDaemonInfoInOut->connectKey]; 382 if (hdi) { 383 *mapDaemon[hDaemonInfoInOut->connectKey] = *hDaemonInfoInOut; 384 } 385 uv_rwlock_wrunlock(&daemonAdmin); 386 break; 387 } 388 default: 389 break; 390 } 391 return sRet; 392} 393 394void HdcServer::NotifyInstanceSessionFree(HSession hSession, bool freeOrClear) 395{ 396 HDaemonInfo hdiOld = nullptr; 397 AdminDaemonMap(OP_QUERY, hSession->connectKey, hdiOld); 398 if (hdiOld == nullptr) { 399 WRITE_LOG(LOG_FATAL, "NotifyInstanceSessionFree hdiOld nullptr"); 400 return; 401 } 402 if (!freeOrClear) { // step1 403 // update 404 HdcDaemonInformation diNew = *hdiOld; 405 diNew.connStatus = STATUS_OFFLINE; 406 HDaemonInfo hdiNew = &diNew; 407 AdminDaemonMap(OP_UPDATE, hSession->connectKey, hdiNew); 408 CleanForwardMap(hSession->sessionId); 409 } else { // step2 410 string usbMountPoint = hdiOld->usbMountPoint; 411 // The waiting time must be longer than DEVICE_CHECK_INTERVAL. Wait the method WatchUsbNodeChange 412 // to finish execution. Otherwise, the main thread and the session worker thread will conflict 413 constexpr int waitDaemonReconnect = DEVICE_CHECK_INTERVAL + DEVICE_CHECK_INTERVAL; 414 auto funcDelayUsbNotify = [this, usbMountPoint](const uint8_t flag, string &msg, const void *) -> void { 415 string s = usbMountPoint; 416 clsUSBClt->RemoveIgnoreDevice(s); 417 }; 418 if (usbMountPoint.size() > 0) { 419 // wait time for daemon reconnect 420 // If removed from maplist, the USB module will be reconnected, so it needs to wait for a while 421 Base::DelayDoSimple(&loopMain, waitDaemonReconnect, funcDelayUsbNotify); 422 } 423 } 424} 425 426void HdcServer::GetDaemonAuthType(HSession hSession, SessionHandShake &handshake) 427{ 428 /* 429 * check if daemon support RSA_3072_SHA512 for auth 430 * it the value is not RSA_3072_SHA512, we use old auth algorithm 431 * Notice, If deamon is old version 'handshake.buf' will be 'hSession->tokenRSA', 432 * the length of hSession->tokenRSA less than min len(TLV_MIN_LEN), so there no 433 * problem 434 */ 435 std::map<string, string> tlvmap; 436 hSession->verifyType = AuthVerifyType::RSA_ENCRYPT; 437 if (!Base::TlvToStringMap(handshake.buf, tlvmap)) { 438 WRITE_LOG(LOG_INFO, "the deamon maybe old version for %u session, so use rsa encrypt", hSession->sessionId); 439 return; 440 } 441 if (tlvmap.find(TAG_AUTH_TYPE) == tlvmap.end() || 442 tlvmap[TAG_AUTH_TYPE] != std::to_string(AuthVerifyType::RSA_3072_SHA512)) { 443 WRITE_LOG(LOG_FATAL, "the buf is invalid for %u session, so use rsa encrypt", hSession->sessionId); 444 return; 445 } 446 hSession->verifyType = AuthVerifyType::RSA_3072_SHA512; 447 WRITE_LOG(LOG_INFO, "daemon auth type is rsa_3072_sha512 for %u session", hSession->sessionId); 448} 449 450bool HdcServer::HandServerAuth(HSession hSession, SessionHandShake &handshake) 451{ 452 string bufString; 453 switch (handshake.authType) { 454 case AUTH_PUBLICKEY: { 455 WRITE_LOG(LOG_INFO, "recive get publickey cmd"); 456 GetDaemonAuthType(hSession, handshake); 457 if (!HdcAuth::GetPublicKeyinfo(handshake.buf)) { 458 WRITE_LOG(LOG_FATAL, "load public key failed"); 459 return false; 460 } 461 handshake.authType = AUTH_PUBLICKEY; 462 bufString = SerialStruct::SerializeToString(handshake); 463 Send(hSession->sessionId, 0, CMD_KERNEL_HANDSHAKE, 464 reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size()); 465 466 WRITE_LOG(LOG_INFO, "send pubkey over"); 467 return true; 468 } 469 case AUTH_SIGNATURE: { 470 WRITE_LOG(LOG_INFO, "recive auth signture cmd"); 471 if (!HdcAuth::RsaSignAndBase64(handshake.buf, hSession->verifyType)) { 472 WRITE_LOG(LOG_FATAL, "sign failed"); 473 return false; 474 } 475 handshake.authType = AUTH_SIGNATURE; 476 bufString = SerialStruct::SerializeToString(handshake); 477 Send(hSession->sessionId, 0, CMD_KERNEL_HANDSHAKE, 478 reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size()); 479 WRITE_LOG(LOG_INFO, "response auth signture success"); 480 return true; 481 } 482 default: 483 WRITE_LOG(LOG_FATAL, "invalid auth type %d", handshake.authType); 484 return false; 485 } 486} 487 488void HdcServer::UpdateHdiInfo(Hdc::HdcSessionBase::SessionHandShake &handshake, const string &connectKey) 489{ 490 HDaemonInfo hdiOld = nullptr; 491 AdminDaemonMap(OP_QUERY, connectKey, hdiOld); 492 if (!hdiOld) { 493 return; 494 } 495 HdcDaemonInformation diNew = *hdiOld; 496 HDaemonInfo hdiNew = &diNew; 497 // update 498 hdiNew->connStatus = STATUS_CONNECTED; 499 WRITE_LOG(LOG_INFO, "handshake info is : %s", handshake.ToDebugString().c_str()); 500 WRITE_LOG(LOG_INFO, "handshake.buf = %s", handshake.buf.c_str()); 501 if (handshake.version < "Ver: 3.0.0b") { 502 if (!handshake.buf.empty()) { 503 hdiNew->devName = handshake.buf; 504 } 505 } else { 506 std::map<string, string> tlvmap; 507 if (Base::TlvToStringMap(handshake.buf, tlvmap)) { 508 if (tlvmap.find(TAG_DEVNAME) != tlvmap.end()) { 509 hdiNew->devName = tlvmap[TAG_DEVNAME]; 510 WRITE_LOG(LOG_INFO, "devname = %s", hdiNew->devName.c_str()); 511 } 512 if (tlvmap.find(TAG_EMGMSG) != tlvmap.end()) { 513 hdiNew->emgmsg = tlvmap[TAG_EMGMSG]; 514 WRITE_LOG(LOG_INFO, "emgmsg = %s", hdiNew->emgmsg.c_str()); 515 } 516 if (tlvmap.find(TAG_DAEOMN_AUTHSTATUS) != tlvmap.end()) { 517 hdiNew->daemonAuthStatus = tlvmap[TAG_DAEOMN_AUTHSTATUS]; 518 WRITE_LOG(LOG_INFO, "daemonauthstatus = %s", hdiNew->daemonAuthStatus.c_str()); 519 } 520 } else { 521 WRITE_LOG(LOG_FATAL, "TlvToStringMap failed"); 522 } 523 } 524 hdiNew->version = handshake.version; 525 AdminDaemonMap(OP_UPDATE, connectKey, hdiNew); 526} 527 528bool HdcServer::ServerSessionHandshake(HSession hSession, uint8_t *payload, int payloadSize) 529{ 530 // session handshake step3 531 string s = string(reinterpret_cast<char *>(payload), payloadSize); 532 Hdc::HdcSessionBase::SessionHandShake handshake; 533 SerialStruct::ParseFromString(handshake, s); 534#ifdef HDC_DEBUG 535 WRITE_LOG(LOG_DEBUG, "handshake.banner:%s, payload:%s(%d)", handshake.banner.c_str(), s.c_str(), payloadSize); 536#endif 537 538 if (handshake.banner == HANDSHAKE_FAILED.c_str()) { 539 WRITE_LOG(LOG_FATAL, "Handshake failed"); 540 return false; 541 } 542 543 if (handshake.banner != HANDSHAKE_MESSAGE.c_str()) { 544 WRITE_LOG(LOG_DEBUG, "Hello failed"); 545 return false; 546 } 547 if (handshake.authType != AUTH_OK) { 548 if (!HandServerAuth(hSession, handshake)) { 549 WRITE_LOG(LOG_WARN, "Auth failed"); 550 return false; 551 } 552 return true; 553 } 554 // handshake auth OK 555 UpdateHdiInfo(handshake, hSession->connectKey); 556 hSession->handshakeOK = true; 557 return true; 558} 559 560// call in child thread 561bool HdcServer::FetchCommand(HSession hSession, const uint32_t channelId, const uint16_t command, uint8_t *payload, 562 const int payloadSize) 563{ 564 bool ret = true; 565 HdcServerForClient *sfc = static_cast<HdcServerForClient *>(clsServerForClient); 566 if (command == CMD_KERNEL_HANDSHAKE) { 567 ret = ServerSessionHandshake(hSession, payload, payloadSize); 568 WRITE_LOG(LOG_DEBUG, "Session handshake %s connType:%d", ret ? "successful" : "failed", 569 hSession->connType); 570 return ret; 571 } 572 // When you first initialize, ChannelID may be 0 573 HChannel hChannel = sfc->AdminChannel(OP_QUERY_REF, channelId, nullptr); 574 if (!hChannel) { 575 if (command == CMD_KERNEL_CHANNEL_CLOSE) { 576 // Daemon close channel and want to notify server close channel also, but it may has been 577 // closed by herself 578 WRITE_LOG(LOG_WARN, "Die channelId :%lu recv CMD_KERNEL_CHANNEL_CLOSE", channelId); 579 } else { 580 // Client may be ctrl+c and Server remove channel. notify server async 581 WRITE_LOG(LOG_DEBUG, "channelId :%lu die", channelId); 582 } 583 uint8_t flag = 0; 584 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &flag, 1); 585 return ret; 586 } 587 if (hChannel->isDead) { 588 WRITE_LOG(LOG_FATAL, "FetchCommand channelId:%u isDead", channelId); 589 --hChannel->ref; 590 return ret; 591 } 592 switch (command) { 593 case CMD_KERNEL_ECHO_RAW: { // Native shell data output 594 sfc->EchoClientRaw(hChannel, payload, payloadSize); 595 break; 596 } 597 case CMD_KERNEL_ECHO: { 598 MessageLevel level = static_cast<MessageLevel>(*payload); 599 string s(reinterpret_cast<char *>(payload + 1), payloadSize - 1); 600 sfc->EchoClient(hChannel, level, s.c_str()); 601 WRITE_LOG(LOG_INFO, "CMD_KERNEL_ECHO size:%d channelId:%u", payloadSize - 1, channelId); 602 break; 603 } 604 case CMD_KERNEL_CHANNEL_CLOSE: { 605 WRITE_LOG(LOG_DEBUG, "CMD_KERNEL_CHANNEL_CLOSE channelid:%u", channelId); 606 // Forcibly closing the tcp handle here may result in incomplete data reception on the client side 607 ClearOwnTasks(hSession, channelId); 608 // crossthread free 609 sfc->PushAsyncMessage(channelId, ASYNC_FREE_CHANNEL, nullptr, 0); 610 if (*payload != 0) { 611 --(*payload); 612 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, payload, 1); 613 } 614 break; 615 } 616 case CMD_FORWARD_SUCCESS: { 617 // add to local 618 HdcForwardInformation di; 619 HForwardInfo pdiNew = &di; 620 pdiNew->channelId = channelId; 621 pdiNew->sessionId = hSession->sessionId; 622 pdiNew->connectKey = hSession->connectKey; 623 pdiNew->forwardDirection = (reinterpret_cast<char *>(payload))[0] == '1'; 624 pdiNew->taskString = reinterpret_cast<char *>(payload); 625 AdminForwardMap(OP_ADD, STRING_EMPTY, pdiNew); 626 Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP); // detch client channel 627 break; 628 } 629 case CMD_FILE_INIT: 630 case CMD_FILE_CHECK: 631 case CMD_FILE_BEGIN: 632 case CMD_FILE_DATA: 633 case CMD_FILE_FINISH: 634 case CMD_FILE_MODE: 635 case CMD_DIR_MODE: 636 case CMD_APP_INIT: 637 case CMD_APP_CHECK: 638 case CMD_APP_BEGIN: 639 case CMD_APP_DATA: 640 case CMD_APP_FINISH: 641 if (hChannel->fromClient) { 642 // server directly passthrough app command to client if remote file mode, else go default 643 sfc->SendCommandToClient(hChannel, command, payload, payloadSize); 644 break; 645 } 646 default: { 647 HSession hSessionByQuery = AdminSession(OP_QUERY, hChannel->targetSessionId, nullptr); 648 if (!hSessionByQuery) { 649 ret = false; 650 break; 651 } 652 ret = DispatchTaskData(hSessionByQuery, channelId, command, payload, payloadSize); 653 break; 654 } 655 } 656 --hChannel->ref; 657 return ret; 658} 659 660void HdcServer::BuildForwardVisableLine(bool fullOrSimble, HForwardInfo hfi, string &echo) 661{ 662 string buf; 663 if (fullOrSimble) { 664 buf = Base::StringFormat("%s %s %s\n", hfi->connectKey.c_str(), hfi->taskString.substr(OFFSET).c_str(), 665 hfi->forwardDirection ? "[Forward]" : "[Reverse]"); 666 } else { 667 buf = Base::StringFormat("%s\n", hfi->taskString.c_str()); 668 } 669 echo += buf; 670} 671 672string HdcServer::AdminForwardMap(uint8_t opType, const string &taskString, HForwardInfo &hForwardInfoInOut) 673{ 674 string sRet; 675 switch (opType) { 676 case OP_ADD: { 677 HForwardInfo pfiNew = new(std::nothrow) HdcForwardInformation(); 678 if (pfiNew == nullptr) { 679 WRITE_LOG(LOG_FATAL, "AdminForwardMap new pfiNew failed"); 680 break; 681 } 682 *pfiNew = *hForwardInfoInOut; 683 uv_rwlock_wrlock(&forwardAdmin); 684 if (!mapForward[hForwardInfoInOut->taskString]) { 685 mapForward[hForwardInfoInOut->taskString] = pfiNew; 686 } 687 uv_rwlock_wrunlock(&forwardAdmin); 688 break; 689 } 690 case OP_GET_STRLIST: 691 case OP_GET_STRLIST_FULL: { 692 uv_rwlock_rdlock(&forwardAdmin); 693 map<string, HForwardInfo>::iterator iter; 694 for (iter = mapForward.begin(); iter != mapForward.end(); ++iter) { 695 HForwardInfo di = iter->second; 696 if (!di) { 697 continue; 698 } 699 BuildForwardVisableLine(opType == OP_GET_STRLIST_FULL, di, sRet); 700 } 701 uv_rwlock_rdunlock(&forwardAdmin); 702 break; 703 } 704 case OP_QUERY: { 705 uv_rwlock_rdlock(&forwardAdmin); 706 if (mapForward.count(taskString)) { 707 hForwardInfoInOut = mapForward[taskString]; 708 } 709 uv_rwlock_rdunlock(&forwardAdmin); 710 break; 711 } 712 case OP_REMOVE: { 713 uv_rwlock_wrlock(&forwardAdmin); 714 if (mapForward.count(taskString)) { 715 mapForward.erase(taskString); 716 } 717 uv_rwlock_wrunlock(&forwardAdmin); 718 break; 719 } 720 default: 721 break; 722 } 723 return sRet; 724} 725 726void HdcServer::CleanForwardMap(uint32_t sessionId) 727{ 728 uv_rwlock_rdlock(&forwardAdmin); 729 map<string, HForwardInfo>::iterator iter; 730 for (iter = mapForward.begin(); iter != mapForward.end();) { 731 HForwardInfo di = iter->second; 732 if (!di) { 733 continue; 734 } 735 if (sessionId == 0 || sessionId == di->sessionId) { 736 iter = mapForward.erase(iter); 737 } else { 738 iter++; 739 } 740 } 741 uv_rwlock_rdunlock(&forwardAdmin); 742} 743 744void HdcServer::UsbPreConnect(uv_timer_t *handle) 745{ 746 HSession hSession = (HSession)handle->data; 747 bool stopLoop = false; 748 HdcServer *hdcServer = (HdcServer *)hSession->classInstance; 749 while (true) { 750 WRITE_LOG(LOG_DEBUG, "HdcServer::UsbPreConnect"); 751 HDaemonInfo pDi = nullptr; 752 if (hSession->connectKey == "any") { 753 hdcServer->AdminDaemonMap(OP_GET_ANY, hSession->connectKey, pDi); 754 } else { 755 hdcServer->AdminDaemonMap(OP_QUERY, hSession->connectKey, pDi); 756 } 757 if (!pDi || !pDi->usbMountPoint.size()) { 758 break; 759 } 760 HdcHostUSB *hdcHostUSB = (HdcHostUSB *)hSession->classModule; 761 hdcHostUSB->ConnectDetectDaemon(hSession, pDi); 762 stopLoop = true; 763 break; 764 } 765 if (stopLoop && !uv_is_closing((const uv_handle_t *)handle)) { 766 uv_close((uv_handle_t *)handle, Base::CloseTimerCallback); 767 } 768} 769#ifdef HDC_SUPPORT_UART 770void HdcServer::UartPreConnect(uv_timer_t *handle) 771{ 772 WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__); 773 HSession hSession = (HSession)handle->data; 774 bool stopLoop = false; 775 HdcServer *hdcServer = (HdcServer *)hSession->classInstance; 776 const int uartConnectRetryMax = 100; // max 6s 777 while (true) { 778 if (hSession->hUART->retryCount > uartConnectRetryMax) { 779 WRITE_LOG(LOG_DEBUG, "%s failed because max retry limit %d", __FUNCTION__, 780 hSession->hUART->retryCount); 781 hdcServer->FreeSession(hSession->sessionId); 782 stopLoop = true; 783 break; 784 } 785 hSession->hUART->retryCount++; 786 HDaemonInfo pDi = nullptr; 787 788 WRITE_LOG(LOG_DEBUG, "%s query %s", __FUNCTION__, hSession->ToDebugString().c_str()); 789 hdcServer->AdminDaemonMap(OP_QUERY, hSession->connectKey, pDi); 790 if (!pDi) { 791 WRITE_LOG(LOG_DEBUG, "%s not found", __FUNCTION__); 792 break; 793 } 794 HdcHostUART *hdcHostUART = (HdcHostUART *)hSession->classModule; 795 hdcHostUART->ConnectDaemonByUart(hSession, pDi); 796 WRITE_LOG(LOG_DEBUG, "%s ConnectDaemonByUart done", __FUNCTION__); 797 798 stopLoop = true; 799 break; 800 } 801 if (stopLoop) { 802 uv_close((uv_handle_t *)handle, Base::CloseTimerCallback); 803 } 804} 805 806void HdcServer::CreatConnectUart(HSession hSession) 807{ 808 uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t; 809 if (waitTimeDoCmd == nullptr) { 810 WRITE_LOG(LOG_FATAL, "CreatConnectUart new waitTimeDoCmd failed"); 811 return; 812 } 813 uv_timer_init(&loopMain, waitTimeDoCmd); 814 waitTimeDoCmd->data = hSession; 815 uv_timer_start(waitTimeDoCmd, UartPreConnect, UV_TIMEOUT, UV_REPEAT); 816} 817#endif 818// -1,has old,-2 error 819int HdcServer::CreateConnect(const string &connectKey, bool isCheck) 820{ 821 uint8_t connType = 0; 822 if (connectKey.find(":") != std::string::npos) { // TCP 823 connType = CONN_TCP; 824 } 825#ifdef HDC_SUPPORT_UART 826 else if (connectKey.find("COM") == 0 || 827 connectKey.find("/dev/ttyUSB") == 0 || 828 connectKey.find("/dev/cu.") == 0) { // UART 829 connType = CONN_SERIAL; 830 } 831#endif 832 else { // Not support 833 return ERR_NO_SUPPORT; 834 } 835 HDaemonInfo hdi = nullptr; 836 if (connectKey == "any") { 837 return RET_SUCCESS; 838 } 839 AdminDaemonMap(OP_QUERY, connectKey, hdi); 840 if (hdi == nullptr) { 841 HdcDaemonInformation di = {}; 842 di.connectKey = connectKey; 843 di.connType = connType; 844 di.connStatus = STATUS_UNKNOW; 845 HDaemonInfo pDi = reinterpret_cast<HDaemonInfo>(&di); 846 AdminDaemonMap(OP_ADD, "", pDi); 847 AdminDaemonMap(OP_QUERY, connectKey, hdi); 848 } 849 if (!hdi || hdi->connStatus == STATUS_CONNECTED) { 850 WRITE_LOG(LOG_FATAL, "Connected return"); 851 return ERR_GENERIC; 852 } 853 HSession hSession = nullptr; 854 if (connType == CONN_TCP) { 855 hSession = clsTCPClt->ConnectDaemon(connectKey, isCheck); 856 } else if (connType == CONN_SERIAL) { 857#ifdef HDC_SUPPORT_UART 858 clsUARTClt->SetCheckFlag(isCheck); 859 hSession = clsUARTClt->ConnectDaemon(connectKey); 860#endif 861 } else { 862 hSession = MallocSession(true, CONN_USB, clsUSBClt); 863 if (!hSession) { 864 WRITE_LOG(LOG_FATAL, "CreateConnect malloc usb session failed %s", Hdc::MaskString(connectKey).c_str()); 865 return ERR_BUF_ALLOC; 866 } 867 hSession->connectKey = connectKey; 868 uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t; 869 if (waitTimeDoCmd == nullptr) { 870 WRITE_LOG(LOG_FATAL, "CreateConnect new waitTimeDoCmd failed"); 871 FreeSession(hSession->sessionId); 872 return ERR_GENERIC; 873 } 874 uv_timer_init(&loopMain, waitTimeDoCmd); 875 waitTimeDoCmd->data = hSession; 876 uv_timer_start(waitTimeDoCmd, UsbPreConnect, UV_TIMEOUT, UV_REPEAT); 877 } 878 if (!hSession) { 879 WRITE_LOG(LOG_FATAL, "CreateConnect hSession nullptr"); 880 return ERR_BUF_ALLOC; 881 } 882 HDaemonInfo hdiQuery = nullptr; 883 AdminDaemonMap(OP_QUERY, connectKey, hdiQuery); 884 if (hdiQuery) { 885 HdcDaemonInformation diNew = *hdiQuery; 886 diNew.hSession = hSession; 887 HDaemonInfo hdiNew = &diNew; 888 AdminDaemonMap(OP_UPDATE, hdiQuery->connectKey, hdiNew); 889 } 890 return RET_SUCCESS; 891} 892 893void HdcServer::AttachChannel(HSession hSession, const uint32_t channelId) 894{ 895 int ret = 0; 896 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient); 897 HChannel hChannel = hSfc->AdminChannel(OP_QUERY_REF, channelId, nullptr); 898 if (!hChannel) { 899 WRITE_LOG(LOG_DEBUG, "AttachChannel hChannel null channelId:%u", channelId); 900 return; 901 } 902 uv_tcp_init(&hSession->childLoop, &hChannel->hChildWorkTCP); 903 hChannel->hChildWorkTCP.data = hChannel; 904 hChannel->targetSessionId = hSession->sessionId; 905 if ((ret = uv_tcp_open((uv_tcp_t *)&hChannel->hChildWorkTCP, hChannel->fdChildWorkTCP)) < 0) { 906 constexpr int bufSize = 1024; 907 char buf[bufSize] = { 0 }; 908 uv_err_name_r(ret, buf, bufSize); 909 WRITE_LOG(LOG_WARN, "Hdcserver AttachChannel uv_tcp_open failed %s, channelid:%d fdChildWorkTCP:%d", 910 buf, hChannel->channelId, hChannel->fdChildWorkTCP); 911 Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP); 912 --hChannel->ref; 913 return; 914 } 915 Base::SetTcpOptions((uv_tcp_t *)&hChannel->hChildWorkTCP); 916 uv_read_start((uv_stream_t *)&hChannel->hChildWorkTCP, hSfc->AllocCallback, hSfc->ReadStream); 917 --hChannel->ref; 918}; 919 920void HdcServer::DeatchChannel(HSession hSession, const uint32_t channelId) 921{ 922 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient); 923 // childCleared has not set, no need OP_QUERY_REF 924 HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr); 925 if (!hChannel) { 926 ClearOwnTasks(hSession, channelId); 927 uint8_t count = 0; 928 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1); 929 WRITE_LOG(LOG_WARN, "DeatchChannel hChannel null channelId:%u", channelId); 930 return; 931 } 932 if (hChannel->childCleared) { 933 WRITE_LOG(LOG_DEBUG, "Childchannel has already freed, cid:%u", channelId); 934 return; 935 } 936 // The own task for this channel must be clear before free channel 937 ClearOwnTasks(hSession, channelId); 938 uint8_t count = 0; 939 Send(hSession->sessionId, hChannel->channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1); 940 WRITE_LOG(LOG_DEBUG, "Childchannel begin close, cid:%u, sid:%u", hChannel->channelId, hSession->sessionId); 941 if (uv_is_closing((const uv_handle_t *)&hChannel->hChildWorkTCP)) { 942 Base::DoNextLoop(&hSession->childLoop, hChannel, [](const uint8_t flag, string &msg, const void *data) { 943 HChannel hChannel = (HChannel)data; 944 hChannel->childCleared = true; 945 WRITE_LOG(LOG_DEBUG, "Childchannel free direct, cid:%u", hChannel->channelId); 946 }); 947 } else { 948 if (hChannel->hChildWorkTCP.loop == NULL) { 949 WRITE_LOG(LOG_DEBUG, "Childchannel loop is null, cid:%u", hChannel->channelId); 950 } 951 Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP, [](uv_handle_t *handle) -> void { 952 HChannel hChannel = (HChannel)handle->data; 953 hChannel->childCleared = true; 954 WRITE_LOG(LOG_DEBUG, "Childchannel free callback, cid:%u", hChannel->channelId); 955 }); 956 } 957}; 958 959bool HdcServer::ServerCommand(const uint32_t sessionId, const uint32_t channelId, const uint16_t command, 960 uint8_t *bufPtr, const int size) 961{ 962 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient); 963 HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr); 964 HSession hSession = AdminSession(OP_QUERY, sessionId, nullptr); 965 if (!hChannel || !hSession) { 966 return false; 967 } 968 return FetchCommand(hSession, channelId, command, bufPtr, size); 969} 970 971// clang-format off 972bool HdcServer::RedirectToTask(HTaskInfo hTaskInfo, HSession hSession, const uint32_t channelId, 973 const uint16_t command, uint8_t *payload, const int payloadSize) 974// clang-format on 975{ 976 bool ret = true; 977 hTaskInfo->ownerSessionClass = this; 978 switch (command) { 979 case CMD_UNITY_BUGREPORT_INIT: 980 case CMD_UNITY_BUGREPORT_DATA: 981 ret = TaskCommandDispatch<HdcHostUnity>(hTaskInfo, TYPE_UNITY, command, payload, payloadSize); 982 break; 983 case CMD_FILE_INIT: 984 case CMD_FILE_BEGIN: 985 case CMD_FILE_CHECK: 986 case CMD_FILE_DATA: 987 case CMD_FILE_FINISH: 988 case CMD_FILE_MODE: 989 case CMD_DIR_MODE: 990 ret = TaskCommandDispatch<HdcFile>(hTaskInfo, TASK_FILE, command, payload, payloadSize); 991 break; 992 case CMD_FORWARD_INIT: 993 case CMD_FORWARD_CHECK: 994 case CMD_FORWARD_CHECK_RESULT: 995 case CMD_FORWARD_ACTIVE_MASTER: 996 case CMD_FORWARD_ACTIVE_SLAVE: 997 case CMD_FORWARD_DATA: 998 case CMD_FORWARD_FREE_CONTEXT: 999 ret = TaskCommandDispatch<HdcHostForward>(hTaskInfo, TASK_FORWARD, command, payload, payloadSize); 1000 break; 1001 case CMD_APP_INIT: 1002 case CMD_APP_SIDELOAD: 1003 case CMD_APP_BEGIN: 1004 case CMD_APP_FINISH: 1005 case CMD_APP_UNINSTALL: 1006 ret = TaskCommandDispatch<HdcHostApp>(hTaskInfo, TASK_APP, command, payload, payloadSize); 1007 break; 1008 case CMD_FLASHD_UPDATE_INIT: 1009 case CMD_FLASHD_FLASH_INIT: 1010 case CMD_FLASHD_CHECK: 1011 case CMD_FLASHD_BEGIN: 1012 case CMD_FLASHD_DATA: 1013 case CMD_FLASHD_FINISH: 1014 case CMD_FLASHD_ERASE: 1015 case CMD_FLASHD_FORMAT: 1016 case CMD_FLASHD_PROGRESS: 1017 ret = TaskCommandDispatch<HostUpdater>(hTaskInfo, TASK_FLASHD, command, payload, payloadSize); 1018 break; 1019 default: 1020 // ignore unknown command 1021 break; 1022 } 1023 return ret; 1024} 1025 1026bool HdcServer::RemoveInstanceTask(const uint8_t op, HTaskInfo hTask) 1027{ 1028 bool ret = true; 1029 switch (hTask->taskType) { 1030 case TYPE_SHELL: 1031 WRITE_LOG(LOG_DEBUG, "Server not enable unity/shell"); 1032 break; 1033 case TYPE_UNITY: 1034 ret = DoTaskRemove<HdcHostUnity>(hTask, op); 1035 break; 1036 case TASK_FILE: 1037 ret = DoTaskRemove<HdcFile>(hTask, op); 1038 break; 1039 case TASK_FORWARD: 1040 ret = DoTaskRemove<HdcHostForward>(hTask, op); 1041 break; 1042 case TASK_APP: 1043 ret = DoTaskRemove<HdcHostApp>(hTask, op); 1044 break; 1045 case TASK_FLASHD: 1046 ret = DoTaskRemove<HostUpdater>(hTask, op); 1047 break; 1048 default: 1049 ret = false; 1050 break; 1051 } 1052 return ret; 1053} 1054 1055void HdcServer::EchoToClientsForSession(uint32_t targetSessionId, const string &echo) 1056{ 1057 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient); 1058 WRITE_LOG(LOG_INFO, "%s:%u %s", __FUNCTION__, targetSessionId, echo.c_str()); 1059 hSfc->EchoToAllChannelsViaSessionId(targetSessionId, echo); 1060} 1061} // namespace Hdc 1062