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 "session.h" 16#ifndef TEST_HASH 17#include "hdc_hash_gen.h" 18#endif 19#include "serial_struct.h" 20 21namespace Hdc { 22HdcSessionBase::HdcSessionBase(bool serverOrDaemonIn, size_t uvThreadSize) 23{ 24 // print version pid 25 WRITE_LOG(LOG_INFO, "Program running. %s Pid:%u", Base::GetVersion().c_str(), getpid()); 26 // server/daemon common initialization code 27 if (uvThreadSize < SIZE_THREAD_POOL_MIN) { 28 uvThreadSize = SIZE_THREAD_POOL_MIN; 29 } else if (uvThreadSize > SIZE_THREAD_POOL_MAX) { 30 uvThreadSize = SIZE_THREAD_POOL_MAX; 31 } 32 threadPoolCount = uvThreadSize; 33 WRITE_LOG(LOG_INFO, "set UV_THREADPOOL_SIZE:%zu", threadPoolCount); 34 string uvThreadEnv("UV_THREADPOOL_SIZE"); 35 string uvThreadVal = std::to_string(threadPoolCount); 36#ifdef _WIN32 37 uvThreadEnv += "="; 38 uvThreadEnv += uvThreadVal; 39 _putenv(uvThreadEnv.c_str()); 40#else 41 setenv(uvThreadEnv.c_str(), uvThreadVal.c_str(), 1); 42#endif 43 uv_loop_init(&loopMain); 44 WRITE_LOG(LOG_DEBUG, "loopMain init"); 45 uv_rwlock_init(&mainAsync); 46#ifndef FUZZ_TEST 47 uv_async_init(&loopMain, &asyncMainLoop, MainAsyncCallback); 48#endif 49 uv_rwlock_init(&lockMapSession); 50 serverOrDaemon = serverOrDaemonIn; 51 ctxUSB = nullptr; 52 wantRestart = false; 53 threadSessionMain = uv_thread_self(); 54 55#ifdef HDC_HOST 56 if (serverOrDaemon) { 57 if (libusb_init((libusb_context **)&ctxUSB) != 0) { 58 ctxUSB = nullptr; 59 WRITE_LOG(LOG_FATAL, "libusb_init failed ctxUSB is nullptr"); 60 } 61 } 62#endif 63} 64 65HdcSessionBase::~HdcSessionBase() 66{ 67#ifndef FUZZ_TEST 68 Base::TryCloseHandle((uv_handle_t *)&asyncMainLoop); 69#endif 70 uv_loop_close(&loopMain); 71 // clear base 72 uv_rwlock_destroy(&mainAsync); 73 uv_rwlock_destroy(&lockMapSession); 74#ifdef HDC_HOST 75 if (serverOrDaemon and ctxUSB != nullptr) { 76 libusb_exit((libusb_context *)ctxUSB); 77 } 78#endif 79 WRITE_LOG(LOG_WARN, "~HdcSessionBase free sessionRef:%u instance:%s", uint32_t(sessionRef), 80 serverOrDaemon ? "server" : "daemon"); 81} 82 83// remove step2 84bool HdcSessionBase::TryRemoveTask(HTaskInfo hTask) 85{ 86 if (hTask->taskFree) { 87 WRITE_LOG(LOG_WARN, "TryRemoveTask channelId:%u", hTask->channelId); 88 return true; 89 } 90 bool ret = RemoveInstanceTask(OP_REMOVE, hTask); 91 if (ret) { 92 hTask->taskFree = true; 93 } else { 94 // This is used to check that the memory cannot be cleaned up. If the memory cannot be released, break point 95 // here to see which task has not been released 96 // print task clear 97 } 98 return ret; 99} 100 101// remove step1 102void HdcSessionBase::BeginRemoveTask(HTaskInfo hTask) 103{ 104 StartTraceScope("HdcSessionBase::BeginRemoveTask"); 105 if (hTask->taskStop || hTask->taskFree) { 106 WRITE_LOG(LOG_WARN, "BeginRemoveTask channelId:%u taskStop:%d taskFree:%d", 107 hTask->channelId, hTask->taskStop, hTask->taskFree); 108 return; 109 } 110 111 WRITE_LOG(LOG_WARN, "BeginRemoveTask taskType:%d channelId:%u", hTask->taskType, hTask->channelId); 112 auto taskClassDeleteRetry = [](uv_timer_t *handle) -> void { 113 StartTraceScope("HdcSessionBase::BeginRemoveTask taskClassDeleteRetry"); 114 HTaskInfo hTask = (HTaskInfo)handle->data; 115 HdcSessionBase *thisClass = (HdcSessionBase *)hTask->ownerSessionClass; 116 if (hTask->isCleared == false) { 117 hTask->isCleared = true; 118 WRITE_LOG(LOG_WARN, "taskClassDeleteRetry start clear task, taskType:%d cid:%u sid:%u", 119 hTask->taskType, hTask->channelId, hTask->sessionId); 120 bool ret = thisClass->RemoveInstanceTask(OP_CLEAR, hTask); 121 if (!ret) { 122 WRITE_LOG(LOG_WARN, "taskClassDeleteRetry RemoveInstanceTask return false taskType:%d cid:%u sid:%u", 123 hTask->taskType, hTask->channelId, hTask->sessionId); 124 } 125 } 126 127 constexpr uint32_t count = 1000; 128 if (hTask->closeRetryCount == 0 || hTask->closeRetryCount > count) { 129 WRITE_LOG(LOG_DEBUG, "TaskDelay task remove retry count %d/%d, taskType:%d channelId:%u, sessionId:%u", 130 hTask->closeRetryCount, GLOBAL_TIMEOUT, hTask->taskType, hTask->channelId, hTask->sessionId); 131 hTask->closeRetryCount = 1; 132 } 133 hTask->closeRetryCount++; 134 if (!thisClass->TryRemoveTask(hTask)) { 135 WRITE_LOG(LOG_WARN, "TaskDelay TryRemoveTask false channelId:%u", hTask->channelId); 136 return; 137 } 138 WRITE_LOG(LOG_WARN, "TaskDelay task remove finish, channelId:%u", hTask->channelId); 139 if (hTask != nullptr) { 140 delete hTask; 141 hTask = nullptr; 142 } 143 Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseTimerCallback); 144 }; 145 Base::TimerUvTask(hTask->runLoop, hTask, taskClassDeleteRetry, (GLOBAL_TIMEOUT * TIME_BASE) / UV_DEFAULT_INTERVAL); 146 147 hTask->taskStop = true; 148} 149 150// Clear all Task or a single Task, the regular situation is stopped first, and the specific class memory is cleaned up 151// after the end of the LOOP. 152// When ChannelIdinput == 0, at this time, all of the LOOP ends, all runs in the class end, so directly skip STOP, 153// physical memory deletion class trimming 154void HdcSessionBase::ClearOwnTasks(HSession hSession, const uint32_t channelIDInput) 155{ 156 // First case: normal task cleanup process (STOP Remove) 157 // Second: The task is cleaned up, the session ends 158 // Third: The task is cleaned up, and the session is directly over the session. 159 StartTraceScope("HdcSessionBase::ClearOwnTasks"); 160 hSession->mapTaskMutex.lock(); 161 map<uint32_t, HTaskInfo>::iterator iter; 162 for (iter = hSession->mapTask->begin(); iter != hSession->mapTask->end();) { 163 uint32_t channelId = iter->first; 164 HTaskInfo hTask = iter->second; 165 if (channelIDInput != 0) { // single 166 if (channelIDInput != channelId) { 167 ++iter; 168 continue; 169 } 170 BeginRemoveTask(hTask); 171 WRITE_LOG(LOG_WARN, "ClearOwnTasks OP_CLEAR finish, sessionId:%u channelIDInput:%u", 172 hSession->sessionId, channelIDInput); 173 iter = hSession->mapTask->erase(iter); 174 break; 175 } 176 // multi 177 BeginRemoveTask(hTask); 178 iter = hSession->mapTask->erase(iter); 179 } 180 hSession->mapTaskMutex.unlock(); 181} 182 183void HdcSessionBase::ClearSessions() 184{ 185 // no need to lock mapSession 186 // broadcast free signal 187 for (auto v : mapSession) { 188 HSession hSession = (HSession)v.second; 189 if (!hSession->isDead) { 190 FreeSession(hSession->sessionId); 191 } 192 } 193} 194 195void HdcSessionBase::ReMainLoopForInstanceClear() 196{ // reloop 197 StartTraceScope("HdcSessionBase::ReMainLoopForInstanceClear"); 198 auto clearSessionsForFinish = [](uv_idle_t *handle) -> void { 199 HdcSessionBase *thisClass = (HdcSessionBase *)handle->data; 200 if (thisClass->sessionRef > 0) { 201 return; 202 } 203 // all task has been free 204 uv_close((uv_handle_t *)handle, Base::CloseIdleCallback); 205 uv_stop(&thisClass->loopMain); 206 }; 207 Base::IdleUvTask(&loopMain, this, clearSessionsForFinish); 208 uv_run(&loopMain, UV_RUN_DEFAULT); 209}; 210 211#ifdef HDC_SUPPORT_UART 212void HdcSessionBase::EnumUARTDeviceRegister(UartKickoutZombie kickOut) 213{ 214 uv_rwlock_rdlock(&lockMapSession); 215 map<uint32_t, HSession>::iterator i; 216 for (i = mapSession.begin(); i != mapSession.end(); ++i) { 217 HSession hs = i->second; 218 if ((hs->connType != CONN_SERIAL) or (hs->hUART == nullptr)) { 219 continue; 220 } 221 kickOut(hs); 222 break; 223 } 224 uv_rwlock_rdunlock(&lockMapSession); 225} 226#endif 227 228void HdcSessionBase::EnumUSBDeviceRegister(void (*pCallBack)(HSession hSession)) 229{ 230 if (!pCallBack) { 231 return; 232 } 233 uv_rwlock_rdlock(&lockMapSession); 234 map<uint32_t, HSession>::iterator i; 235 for (i = mapSession.begin(); i != mapSession.end(); ++i) { 236 HSession hs = i->second; 237 if (hs->connType != CONN_USB) { 238 continue; 239 } 240 if (hs->hUSB == nullptr) { 241 continue; 242 } 243 if (pCallBack) { 244 pCallBack(hs); 245 } 246 break; 247 } 248 uv_rwlock_rdunlock(&lockMapSession); 249} 250 251// The PC side gives the device information, determines if the USB device is registered 252// PDEV and Busid Devid two choices 253HSession HdcSessionBase::QueryUSBDeviceRegister(void *pDev, uint8_t busIDIn, uint8_t devIDIn) 254{ 255#ifdef HDC_HOST 256 libusb_device *dev = (libusb_device *)pDev; 257 HSession hResult = nullptr; 258 if (!mapSession.size()) { 259 return nullptr; 260 } 261 uint8_t busId = 0; 262 uint8_t devId = 0; 263 if (pDev) { 264 busId = libusb_get_bus_number(dev); 265 devId = libusb_get_device_address(dev); 266 } else { 267 busId = busIDIn; 268 devId = devIDIn; 269 } 270 uv_rwlock_rdlock(&lockMapSession); 271 map<uint32_t, HSession>::iterator i; 272 for (i = mapSession.begin(); i != mapSession.end(); ++i) { 273 HSession hs = i->second; 274 if (hs->connType == CONN_USB) { 275 continue; 276 } 277 if (hs->hUSB == nullptr) { 278 continue; 279 } 280 if (hs->hUSB->devId != devId || hs->hUSB->busId != busId) { 281 continue; 282 } 283 hResult = hs; 284 break; 285 } 286 uv_rwlock_rdunlock(&lockMapSession); 287 return hResult; 288#else 289 return nullptr; 290#endif 291} 292 293void HdcSessionBase::AsyncMainLoopTask(uv_idle_t *handle) 294{ 295 AsyncParam *param = (AsyncParam *)handle->data; 296 HdcSessionBase *thisClass = (HdcSessionBase *)param->thisClass; 297 switch (param->method) { 298 case ASYNC_FREE_SESSION: 299 // Destruction is unified in the main thread 300 thisClass->FreeSession(param->sid); 301 break; 302 case ASYNC_STOP_MAINLOOP: 303 uv_stop(&thisClass->loopMain); 304 break; 305 default: 306 break; 307 } 308 if (param->data) { 309 delete[]((uint8_t *)param->data); 310 } 311 delete param; 312 param = nullptr; 313 Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseIdleCallback); 314} 315 316void HdcSessionBase::MainAsyncCallback(uv_async_t *handle) 317{ 318 HdcSessionBase *thisClass = (HdcSessionBase *)handle->data; 319 list<void *>::iterator i; 320 list<void *> &lst = thisClass->lstMainThreadOP; 321 uv_rwlock_wrlock(&thisClass->mainAsync); 322 for (i = lst.begin(); i != lst.end();) { 323 AsyncParam *param = (AsyncParam *)*i; 324 Base::IdleUvTask(&thisClass->loopMain, param, AsyncMainLoopTask); 325 i = lst.erase(i); 326 } 327 uv_rwlock_wrunlock(&thisClass->mainAsync); 328} 329 330void HdcSessionBase::PushAsyncMessage(const uint32_t sessionId, const uint8_t method, const void *data, 331 const int dataSize) 332{ 333 AsyncParam *param = new AsyncParam(); 334 if (!param) { 335 return; 336 } 337 param->sid = sessionId; 338 param->thisClass = this; 339 param->method = method; 340 if (dataSize > 0) { 341 param->dataSize = dataSize; 342 param->data = new uint8_t[param->dataSize](); 343 if (!param->data) { 344 delete param; 345 return; 346 } 347 if (memcpy_s((uint8_t *)param->data, param->dataSize, data, dataSize)) { 348 delete[]((uint8_t *)param->data); 349 delete param; 350 return; 351 } 352 } 353 354 asyncMainLoop.data = this; 355 uv_rwlock_wrlock(&mainAsync); 356 lstMainThreadOP.push_back(param); 357 uv_rwlock_wrunlock(&mainAsync); 358 uv_async_send(&asyncMainLoop); 359} 360 361void HdcSessionBase::WorkerPendding() 362{ 363 uv_run(&loopMain, UV_RUN_DEFAULT); 364 ClearInstanceResource(); 365} 366 367int HdcSessionBase::MallocSessionByConnectType(HSession hSession) 368{ 369 int ret = 0; 370 switch (hSession->connType) { 371 case CONN_TCP: { 372 uv_tcp_init(&loopMain, &hSession->hWorkTCP); 373 ++hSession->uvHandleRef; 374 hSession->hWorkTCP.data = hSession; 375 break; 376 } 377 case CONN_USB: { 378 // Some members need to be placed at the primary thread 379 HUSB hUSB = new HdcUSB(); 380 if (!hUSB) { 381 ret = -1; 382 break; 383 } 384 hSession->hUSB = hUSB; 385 hSession->hUSB->wMaxPacketSizeSend = MAX_PACKET_SIZE_HISPEED; 386 break; 387 } 388#ifdef HDC_SUPPORT_UART 389 case CONN_SERIAL: { 390 HUART hUART = new HdcUART(); 391 if (!hUART) { 392 ret = -1; 393 break; 394 } 395 hSession->hUART = hUART; 396 break; 397 } 398#endif // HDC_SUPPORT_UART 399 default: 400 ret = -1; 401 break; 402 } 403 return ret; 404} 405 406// Avoid unit test when client\server\daemon on the same host, maybe get the same ID value 407uint32_t HdcSessionBase::GetSessionPseudoUid() 408{ 409 uint32_t uid = 0; 410 do { 411 uid = Base::GetSecureRandom(); 412 } while (AdminSession(OP_QUERY, uid, nullptr) != nullptr); 413 return uid; 414} 415 416// when client 0 to automatic generated,when daemon First place 1 followed by 417HSession HdcSessionBase::MallocSession(bool serverOrDaemon, const ConnType connType, void *classModule, 418 uint32_t sessionId) 419{ 420#ifdef CONFIG_USE_JEMALLOC_DFX_INIF 421 mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE); 422 mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE); 423#endif 424 HSession hSession = new(std::nothrow) HdcSession(); 425 if (!hSession) { 426 WRITE_LOG(LOG_FATAL, "MallocSession new hSession failed"); 427 return nullptr; 428 } 429 int ret = 0; 430 ++sessionRef; 431 hSession->classInstance = this; 432 hSession->connType = connType; 433 hSession->classModule = classModule; 434 hSession->isDead = false; 435 hSession->sessionId = ((sessionId == 0) ? GetSessionPseudoUid() : sessionId); 436 hSession->serverOrDaemon = serverOrDaemon; 437 hSession->hWorkThread = uv_thread_self(); 438 hSession->mapTask = new(std::nothrow) map<uint32_t, HTaskInfo>(); 439 if (hSession->mapTask == nullptr) { 440 WRITE_LOG(LOG_FATAL, "MallocSession new hSession->mapTask failed"); 441 delete hSession; 442 hSession = nullptr; 443 return nullptr; 444 } 445 hSession->listKey = new(std::nothrow) list<void *>; 446 if (hSession->listKey == nullptr) { 447 WRITE_LOG(LOG_FATAL, "MallocSession new hSession->listKey failed"); 448 delete hSession; 449 hSession = nullptr; 450 return nullptr; 451 } 452 uv_loop_init(&hSession->childLoop); 453 hSession->uvHandleRef = 0; 454 // pullup child 455 WRITE_LOG(LOG_INFO, "HdcSessionBase NewSession, sessionId:%u, connType:%d.", 456 hSession->sessionId, hSession->connType); 457 ++hSession->uvHandleRef; 458 Base::CreateSocketPair(hSession->ctrlFd); 459 size_t handleSize = sizeof(uv_poll_t); 460 hSession->pollHandle[STREAM_WORK] = (uv_poll_t *)malloc(handleSize); 461 hSession->pollHandle[STREAM_MAIN] = (uv_poll_t *)malloc(handleSize); 462 uv_poll_t *pollHandleMain = hSession->pollHandle[STREAM_MAIN]; 463 if (pollHandleMain == nullptr || hSession->pollHandle[STREAM_WORK] == nullptr) { 464 WRITE_LOG(LOG_FATAL, "MallocSession malloc hSession->pollHandle failed"); 465 delete hSession; 466 hSession = nullptr; 467 return nullptr; 468 } 469 uv_poll_init_socket(&loopMain, pollHandleMain, hSession->ctrlFd[STREAM_MAIN]); 470 uv_poll_start(pollHandleMain, UV_READABLE, ReadCtrlFromSession); 471 hSession->pollHandle[STREAM_MAIN]->data = hSession; 472 hSession->pollHandle[STREAM_WORK]->data = hSession; 473 // Activate USB DAEMON's data channel, may not for use 474 uv_tcp_init(&loopMain, &hSession->dataPipe[STREAM_MAIN]); 475 (void)memset_s(&hSession->dataPipe[STREAM_WORK], sizeof(hSession->dataPipe[STREAM_WORK]), 476 0, sizeof(uv_tcp_t)); 477 ++hSession->uvHandleRef; 478 Base::CreateSocketPair(hSession->dataFd); 479 uv_tcp_open(&hSession->dataPipe[STREAM_MAIN], hSession->dataFd[STREAM_MAIN]); 480 hSession->dataPipe[STREAM_MAIN].data = hSession; 481 hSession->dataPipe[STREAM_WORK].data = hSession; 482#ifdef HDC_HOST 483 Base::SetTcpOptions(&hSession->dataPipe[STREAM_MAIN], HOST_SOCKETPAIR_SIZE); 484#else 485 Base::SetTcpOptions(&hSession->dataPipe[STREAM_MAIN]); 486#endif 487 ret = MallocSessionByConnectType(hSession); 488 if (ret) { 489 delete hSession; 490 hSession = nullptr; 491 } else { 492 AdminSession(OP_ADD, hSession->sessionId, hSession); 493 } 494 return hSession; 495} 496 497void HdcSessionBase::FreeSessionByConnectType(HSession hSession) 498{ 499 WRITE_LOG(LOG_DEBUG, "FreeSessionByConnectType %s", hSession->ToDebugString().c_str()); 500 501 if (hSession->connType == CONN_USB) { 502 // ibusb All context is applied for sub-threaded, so it needs to be destroyed in the subline 503 if (!hSession->hUSB) { 504 return; 505 } 506 HUSB hUSB = hSession->hUSB; 507 if (!hUSB) { 508 return; 509 } 510#ifdef HDC_HOST 511 if (hUSB->devHandle) { 512 libusb_release_interface(hUSB->devHandle, hUSB->interfaceNumber); 513 libusb_close(hUSB->devHandle); 514 hUSB->devHandle = nullptr; 515 } 516#else 517 Base::CloseFd(hUSB->bulkIn); 518 Base::CloseFd(hUSB->bulkOut); 519#endif 520 delete hSession->hUSB; 521 hSession->hUSB = nullptr; 522 } 523#ifdef HDC_SUPPORT_UART 524 if (CONN_SERIAL == hSession->connType) { 525 if (!hSession->hUART) { 526 return; 527 } 528 HUART hUART = hSession->hUART; 529 if (!hUART) { 530 return; 531 } 532 HdcUARTBase *uartBase = (HdcUARTBase *)hSession->classModule; 533 // tell uart session will be free 534 uartBase->StopSession(hSession); 535#ifdef HDC_HOST 536#ifdef HOST_MINGW 537 if (hUART->devUartHandle != INVALID_HANDLE_VALUE) { 538 CloseHandle(hUART->devUartHandle); 539 hUART->devUartHandle = INVALID_HANDLE_VALUE; 540 } 541#elif defined(HOST_LINUX) 542 Base::CloseFd(hUART->devUartHandle); 543#endif // _WIN32 544#endif 545 delete hSession->hUART; 546 hSession->hUART = nullptr; 547 } 548#endif 549} 550 551// work when libuv-handle at struct of HdcSession has all callback finished 552void HdcSessionBase::FreeSessionFinally(uv_idle_t *handle) 553{ 554 HSession hSession = (HSession)handle->data; 555 HdcSessionBase *thisClass = (HdcSessionBase *)hSession->classInstance; 556 if (hSession->uvHandleRef > 0) { 557 WRITE_LOG(LOG_INFO, "FreeSessionFinally uvHandleRef:%d sessionId:%u", 558 hSession->uvHandleRef, hSession->sessionId); 559 return; 560 } 561 // Notify Server or Daemon, just UI or display commandline 562 thisClass->NotifyInstanceSessionFree(hSession, true); 563 // all hsession uv handle has been clear 564 thisClass->AdminSession(OP_REMOVE, hSession->sessionId, nullptr); 565 WRITE_LOG(LOG_INFO, "!!!FreeSessionFinally sessionId:%u finish", hSession->sessionId); 566 HdcAuth::FreeKey(!hSession->serverOrDaemon, hSession->listKey); 567 delete hSession; 568 hSession = nullptr; // fix CodeMars SetNullAfterFree issue 569 Base::TryCloseHandle((const uv_handle_t *)handle, Base::CloseIdleCallback); 570 --thisClass->sessionRef; 571} 572 573// work when child-work thread finish 574void HdcSessionBase::FreeSessionContinue(HSession hSession) 575{ 576 auto closeSessionTCPHandle = [](uv_handle_t *handle) -> void { 577 HSession hSession = (HSession)handle->data; 578 --hSession->uvHandleRef; 579 Base::TryCloseHandle((uv_handle_t *)handle); 580 if (handle == reinterpret_cast<uv_handle_t *>(hSession->pollHandle[STREAM_MAIN])) { 581 Base::CloseFd(hSession->ctrlFd[STREAM_MAIN]); 582 Base::CloseFd(hSession->ctrlFd[STREAM_WORK]); 583 free(hSession->pollHandle[STREAM_MAIN]); 584 } 585 }; 586 if (hSession->connType == CONN_TCP) { 587 // Turn off TCP to prevent continuing writing 588 Base::TryCloseHandle((uv_handle_t *)&hSession->hWorkTCP, true, closeSessionTCPHandle); 589 Base::CloseFd(hSession->dataFd[STREAM_WORK]); 590 } 591 hSession->availTailIndex = 0; 592 if (hSession->ioBuf) { 593 delete[] hSession->ioBuf; 594 hSession->ioBuf = nullptr; 595 } 596 Base::TryCloseHandle((uv_handle_t *)hSession->pollHandle[STREAM_MAIN], true, closeSessionTCPHandle); 597 Base::TryCloseHandle((uv_handle_t *)&hSession->dataPipe[STREAM_MAIN], true, closeSessionTCPHandle); 598 FreeSessionByConnectType(hSession); 599 // finish 600 Base::IdleUvTask(&loopMain, hSession, FreeSessionFinally); 601} 602 603void HdcSessionBase::FreeSessionOpeate(uv_timer_t *handle) 604{ 605 StartTraceScope("HdcSessionBase::FreeSessionOpeate"); 606 HSession hSession = (HSession)handle->data; 607#ifdef HDC_HOST 608 if (hSession->hUSB != nullptr 609 && (!hSession->hUSB->hostBulkIn.isShutdown || !hSession->hUSB->hostBulkOut.isShutdown)) { 610 HdcUSBBase *pUSB = ((HdcUSBBase *)hSession->classModule); 611 pUSB->CancelUsbIo(hSession); 612 return; 613 } 614#endif 615 HdcSessionBase *thisClass = (HdcSessionBase *)hSession->classInstance; 616 if (hSession->ref > 0) { 617 WRITE_LOG(LOG_WARN, "FreeSessionOpeate sid:%u ref:%u > 0", hSession->sessionId, uint32_t(hSession->ref)); 618 return; 619 } 620 WRITE_LOG(LOG_INFO, "FreeSessionOpeate sid:%u ref:%u", hSession->sessionId, uint32_t(hSession->ref)); 621 // wait workthread to free 622 if (hSession->pollHandle[STREAM_WORK]->loop) { 623 auto ctrl = BuildCtrlString(SP_STOP_SESSION, 0, nullptr, 0); 624 Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size()); 625 WRITE_LOG(LOG_INFO, "FreeSessionOpeate, send workthread for free. sessionId:%u", hSession->sessionId); 626 auto callbackCheckFreeSessionContinue = [](uv_timer_t *handle) -> void { 627 HSession hSession = (HSession)handle->data; 628 HdcSessionBase *thisClass = (HdcSessionBase *)hSession->classInstance; 629 if (!hSession->childCleared) { 630 WRITE_LOG(LOG_INFO, "FreeSessionOpeate childCleared:%d sessionId:%u", 631 hSession->childCleared, hSession->sessionId); 632 return; 633 } 634 Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseTimerCallback); 635 thisClass->FreeSessionContinue(hSession); 636 }; 637 Base::TimerUvTask(&thisClass->loopMain, hSession, callbackCheckFreeSessionContinue); 638 } else { 639 thisClass->FreeSessionContinue(hSession); 640 } 641 Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseTimerCallback); 642} 643 644void HdcSessionBase::FreeSession(const uint32_t sessionId) 645{ 646 StartTraceScope("HdcSessionBase::FreeSession"); 647 Base::AddDeletedSessionId(sessionId); 648 if (threadSessionMain != uv_thread_self()) { 649 PushAsyncMessage(sessionId, ASYNC_FREE_SESSION, nullptr, 0); 650 return; 651 } 652 HSession hSession = AdminSession(OP_QUERY, sessionId, nullptr); 653 WRITE_LOG(LOG_INFO, "Begin to free session, sessionid:%u", sessionId); 654 do { 655 if (!hSession || hSession->isDead) { 656 WRITE_LOG(LOG_WARN, "FreeSession hSession nullptr or isDead sessionId:%u", sessionId); 657 break; 658 } 659 WRITE_LOG(LOG_INFO, "dataFdSend:%llu, dataFdRecv:%llu", 660 uint64_t(hSession->stat.dataSendBytes), 661 uint64_t(hSession->stat.dataRecvBytes)); 662 hSession->isDead = true; 663 Base::TimerUvTask(&loopMain, hSession, FreeSessionOpeate); 664 NotifyInstanceSessionFree(hSession, false); 665 WRITE_LOG(LOG_INFO, "FreeSession sessionId:%u ref:%u", hSession->sessionId, uint32_t(hSession->ref)); 666 } while (false); 667} 668 669HSession HdcSessionBase::AdminSession(const uint8_t op, const uint32_t sessionId, HSession hInput) 670{ 671 HSession hRet = nullptr; 672 switch (op) { 673 case OP_ADD: 674 uv_rwlock_wrlock(&lockMapSession); 675 mapSession[sessionId] = hInput; 676 uv_rwlock_wrunlock(&lockMapSession); 677 break; 678 case OP_REMOVE: 679 uv_rwlock_wrlock(&lockMapSession); 680 mapSession.erase(sessionId); 681 uv_rwlock_wrunlock(&lockMapSession); 682 break; 683 case OP_QUERY: 684 uv_rwlock_rdlock(&lockMapSession); 685 if (mapSession.count(sessionId)) { 686 hRet = mapSession[sessionId]; 687 } 688 uv_rwlock_rdunlock(&lockMapSession); 689 break; 690 case OP_QUERY_REF: 691 uv_rwlock_wrlock(&lockMapSession); 692 if (mapSession.count(sessionId)) { 693 hRet = mapSession[sessionId]; 694 ++hRet->ref; 695 } 696 uv_rwlock_wrunlock(&lockMapSession); 697 break; 698 case OP_UPDATE: 699 uv_rwlock_wrlock(&lockMapSession); 700 // remove old 701 mapSession.erase(sessionId); 702 mapSession[hInput->sessionId] = hInput; 703 uv_rwlock_wrunlock(&lockMapSession); 704 break; 705 case OP_VOTE_RESET: 706 if (mapSession.count(sessionId) == 0) { 707 break; 708 } 709 bool needReset; 710 if (serverOrDaemon) { 711 uv_rwlock_wrlock(&lockMapSession); 712 hRet = mapSession[sessionId]; 713 hRet->voteReset = true; 714 needReset = true; 715 for (auto &kv : mapSession) { 716 if (sessionId == kv.first) { 717 continue; 718 } 719 WRITE_LOG(LOG_DEBUG, "session:%u vote reset, session %u is %s", 720 sessionId, kv.first, kv.second->voteReset ? "YES" : "NO"); 721 if (!kv.second->voteReset) { 722 needReset = false; 723 } 724 } 725 uv_rwlock_wrunlock(&lockMapSession); 726 } else { 727 needReset = true; 728 } 729 if (needReset) { 730 WRITE_LOG(LOG_FATAL, "!! session:%u vote reset, passed unanimously !!", sessionId); 731 abort(); 732 } 733 break; 734 default: 735 break; 736 } 737 return hRet; 738} 739 740void HdcSessionBase::DumpTasksInfo(map<uint32_t, HTaskInfo> &mapTask) 741{ 742 int idx = 1; 743 for (auto t : mapTask) { 744 HTaskInfo ti = t.second; 745 WRITE_LOG(LOG_WARN, "%d: channelId: %lu, type: %d, closeRetry: %d\n", 746 idx++, ti->channelId, ti->taskType, ti->closeRetryCount); 747 } 748} 749 750// All in the corresponding sub-thread, no need locks 751HTaskInfo HdcSessionBase::AdminTask(const uint8_t op, HSession hSession, const uint32_t channelId, HTaskInfo hInput) 752{ 753 HTaskInfo hRet = nullptr; 754 map<uint32_t, HTaskInfo> &mapTask = *hSession->mapTask; 755 756 switch (op) { 757 case OP_ADD: 758 hRet = mapTask[channelId]; 759 if (hRet != nullptr) { 760 delete hRet; 761 } 762 mapTask[channelId] = hInput; 763 hRet = hInput; 764 765 WRITE_LOG(LOG_WARN, "AdminTask add session %u, channelId %u, mapTask size: %zu", 766 hSession->sessionId, channelId, mapTask.size()); 767 768 break; 769 case OP_REMOVE: 770 mapTask.erase(channelId); 771 WRITE_LOG(LOG_DEBUG, "AdminTask rm session %u, channelId %u, mapTask size: %zu", 772 hSession->sessionId, channelId, mapTask.size()); 773 break; 774 case OP_QUERY: 775 if (mapTask.count(channelId)) { 776 hRet = mapTask[channelId]; 777 } 778 break; 779 case OP_VOTE_RESET: 780 AdminSession(op, hSession->sessionId, nullptr); 781 break; 782 default: 783 break; 784 } 785 return hRet; 786} 787 788int HdcSessionBase::SendByProtocol(HSession hSession, uint8_t *bufPtr, const int bufLen, bool echo) 789{ 790 StartTraceScope("HdcSessionBase::SendByProtocol"); 791 if (hSession->isDead) { 792 delete[] bufPtr; 793 WRITE_LOG(LOG_WARN, "SendByProtocol session dead error"); 794 return ERR_SESSION_NOFOUND; 795 } 796 int ret = 0; 797 switch (hSession->connType) { 798 case CONN_TCP: { 799 HdcTCPBase *pTCP = ((HdcTCPBase *)hSession->classModule); 800 if (echo && !hSession->serverOrDaemon) { 801 ret = pTCP->WriteUvTcpFd(&hSession->hChildWorkTCP, bufPtr, bufLen); 802 } else { 803 if (hSession->hWorkThread == uv_thread_self()) { 804 ret = pTCP->WriteUvTcpFd(&hSession->hWorkTCP, bufPtr, bufLen); 805 } else { 806 ret = pTCP->WriteUvTcpFd(&hSession->hChildWorkTCP, bufPtr, bufLen); 807 } 808 } 809 break; 810 } 811 case CONN_USB: { 812 HdcUSBBase *pUSB = ((HdcUSBBase *)hSession->classModule); 813 ret = pUSB->SendUSBBlock(hSession, bufPtr, bufLen); 814 delete[] bufPtr; 815 break; 816 } 817#ifdef HDC_SUPPORT_UART 818 case CONN_SERIAL: { 819 HdcUARTBase *pUART = ((HdcUARTBase *)hSession->classModule); 820 ret = pUART->SendUARTData(hSession, bufPtr, bufLen); 821 delete[] bufPtr; 822 break; 823 } 824#endif 825 default: 826 break; 827 } 828 return ret; 829} 830 831int HdcSessionBase::Send(const uint32_t sessionId, const uint32_t channelId, const uint16_t commandFlag, 832 const uint8_t *data, const int dataSize) 833{ 834 StartTraceScope("HdcSessionBase::Send"); 835 HSession hSession = AdminSession(OP_QUERY, sessionId, nullptr); 836 if (!hSession) { 837 WRITE_LOG(LOG_WARN, "Send to offline device, drop it, sessionId:%u", sessionId); 838 return ERR_SESSION_NOFOUND; 839 } 840 PayloadProtect protectBuf; // noneed convert to big-endian 841 protectBuf.channelId = channelId; 842 protectBuf.commandFlag = commandFlag; 843 protectBuf.checkSum = (ENABLE_IO_CHECKSUM && dataSize > 0) ? Base::CalcCheckSum(data, dataSize) : 0; 844 protectBuf.vCode = payloadProtectStaticVcode; 845 string s = SerialStruct::SerializeToString(protectBuf); 846 // reserve for encrypt here 847 // xx-encrypt 848 849 PayloadHead payloadHead = {}; // need convert to big-endian 850 payloadHead.flag[0] = PACKET_FLAG.at(0); 851 payloadHead.flag[1] = PACKET_FLAG.at(1); 852 payloadHead.protocolVer = VER_PROTOCOL; 853 payloadHead.headSize = htons(s.size()); 854 payloadHead.dataSize = htonl(dataSize); 855 int finalBufSize = sizeof(PayloadHead) + s.size() + dataSize; 856 uint8_t *finayBuf = new(std::nothrow) uint8_t[finalBufSize](); 857 if (finayBuf == nullptr) { 858 WRITE_LOG(LOG_WARN, "send allocmem err"); 859 return ERR_BUF_ALLOC; 860 } 861 bool bufRet = false; 862 do { 863 if (memcpy_s(finayBuf, sizeof(PayloadHead), reinterpret_cast<uint8_t *>(&payloadHead), sizeof(PayloadHead))) { 864 WRITE_LOG(LOG_WARN, "send copyhead err for dataSize:%d", dataSize); 865 break; 866 } 867 if (memcpy_s(finayBuf + sizeof(PayloadHead), s.size(), 868 reinterpret_cast<uint8_t *>(const_cast<char *>(s.c_str())), s.size())) { 869 WRITE_LOG(LOG_WARN, "send copyProtbuf err for dataSize:%d", dataSize); 870 break; 871 } 872 if (dataSize > 0 && memcpy_s(finayBuf + sizeof(PayloadHead) + s.size(), dataSize, data, dataSize)) { 873 WRITE_LOG(LOG_WARN, "send copyDatabuf err for dataSize:%d", dataSize); 874 break; 875 } 876 bufRet = true; 877 } while (false); 878 if (!bufRet) { 879 delete[] finayBuf; 880 WRITE_LOG(LOG_WARN, "send copywholedata err for dataSize:%d", dataSize); 881 return ERR_BUF_COPY; 882 } 883 if (CMD_KERNEL_ECHO == commandFlag) { 884 return SendByProtocol(hSession, finayBuf, finalBufSize, true); 885 } else { 886 return SendByProtocol(hSession, finayBuf, finalBufSize); 887 } 888} 889 890int HdcSessionBase::DecryptPayload(HSession hSession, PayloadHead *payloadHeadBe, uint8_t *encBuf) 891{ 892 StartTraceScope("HdcSessionBase::DecryptPayload"); 893 PayloadProtect protectBuf = {}; 894 uint16_t headSize = ntohs(payloadHeadBe->headSize); 895 int dataSize = ntohl(payloadHeadBe->dataSize); 896 string encString(reinterpret_cast<char *>(encBuf), headSize); 897 SerialStruct::ParseFromString(protectBuf, encString); 898 if (protectBuf.vCode != payloadProtectStaticVcode) { 899 WRITE_LOG(LOG_FATAL, "Session recv static vcode failed"); 900 return ERR_BUF_CHECK; 901 } 902 uint8_t *data = encBuf + headSize; 903 if (ENABLE_IO_CHECKSUM && protectBuf.checkSum != 0 && (protectBuf.checkSum != Base::CalcCheckSum(data, dataSize))) { 904 WRITE_LOG(LOG_FATAL, "Session recv CalcCheckSum failed"); 905 return ERR_BUF_CHECK; 906 } 907 if (!FetchCommand(hSession, protectBuf.channelId, protectBuf.commandFlag, data, dataSize)) { 908 WRITE_LOG(LOG_WARN, "FetchCommand failed: channelId %x commandFlag %x", 909 protectBuf.channelId, protectBuf.commandFlag); 910 return ERR_GENERIC; 911 } 912 return RET_SUCCESS; 913} 914 915int HdcSessionBase::OnRead(HSession hSession, uint8_t *bufPtr, const int bufLen) 916{ 917 int ret = ERR_GENERIC; 918 StartTraceScope("HdcSessionBase::OnRead"); 919 if (memcmp(bufPtr, PACKET_FLAG.c_str(), PACKET_FLAG.size())) { 920 WRITE_LOG(LOG_FATAL, "PACKET_FLAG incorrect %x %x", bufPtr[0], bufPtr[1]); 921 return ERR_BUF_CHECK; 922 } 923 struct PayloadHead *payloadHead = reinterpret_cast<struct PayloadHead *>(bufPtr); 924 // to prevent integer overflow caused by the add operation of two input num 925 uint64_t payloadHeadSize = static_cast<uint64_t>(ntohl(payloadHead->dataSize)) + 926 static_cast<uint64_t>(ntohs(payloadHead->headSize)); 927 int packetHeadSize = sizeof(struct PayloadHead); 928 if (payloadHeadSize == 0 || payloadHeadSize > static_cast<uint64_t>(HDC_BUF_MAX_BYTES)) { 929 WRITE_LOG(LOG_FATAL, "Packet size incorrect"); 930 return ERR_BUF_CHECK; 931 } 932 933 // 0 < payloadHeadSize < HDC_BUF_MAX_BYTES 934 int tobeReadLen = static_cast<int>(payloadHeadSize); 935 if (bufLen - packetHeadSize < tobeReadLen) { 936 return 0; 937 } 938 if (DecryptPayload(hSession, payloadHead, bufPtr + packetHeadSize)) { 939 WRITE_LOG(LOG_WARN, "decrypt plhead error"); 940 return ERR_BUF_CHECK; 941 } 942 ret = packetHeadSize + tobeReadLen; 943 return ret; 944} 945 946// Returns <0 error;> 0 receives the number of bytes; 0 untreated 947int HdcSessionBase::FetchIOBuf(HSession hSession, uint8_t *ioBuf, int read) 948{ 949 HdcSessionBase *ptrConnect = (HdcSessionBase *)hSession->classInstance; 950 int indexBuf = 0; 951 int childRet = 0; 952 StartTraceScope("HdcSessionBase::FetchIOBuf"); 953 if (read < 0) { 954 constexpr int bufSize = 1024; 955 char buf[bufSize] = { 0 }; 956 uv_strerror_r(read, buf, bufSize); 957 WRITE_LOG(LOG_FATAL, "FetchIOBuf read io failed,%s", buf); 958 return ERR_IO_FAIL; 959 } 960 hSession->stat.dataRecvBytes += read; 961 hSession->availTailIndex += read; 962 while (!hSession->isDead && hSession->availTailIndex > static_cast<int>(sizeof(PayloadHead))) { 963 childRet = ptrConnect->OnRead(hSession, ioBuf + indexBuf, hSession->availTailIndex); 964 if (childRet > 0) { 965 hSession->availTailIndex -= childRet; 966 indexBuf += childRet; 967 } else if (childRet == 0) { 968 // Not enough a IO 969 break; 970 } else { // <0 971 WRITE_LOG(LOG_FATAL, "FetchIOBuf error childRet:%d sessionId:%u", childRet, hSession->sessionId); 972 hSession->availTailIndex = 0; // Preventing malicious data packages 973 indexBuf = ERR_BUF_SIZE; 974 break; 975 } 976 // It may be multi-time IO to merge in a BUF, need to loop processing 977 } 978 if (indexBuf > 0 && hSession->availTailIndex > 0) { 979 if (memmove_s(hSession->ioBuf, hSession->bufSize, hSession->ioBuf + indexBuf, hSession->availTailIndex) 980 != EOK) { 981 return ERR_BUF_COPY; 982 }; 983 uint8_t *bufToZero = reinterpret_cast<uint8_t *>(hSession->ioBuf + hSession->availTailIndex); 984 Base::ZeroBuf(bufToZero, hSession->bufSize - hSession->availTailIndex); 985 } 986 return indexBuf; 987} 988 989void HdcSessionBase::AllocCallback(uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf) 990{ 991 HSession context = (HSession)handle->data; 992 Base::ReallocBuf(&context->ioBuf, &context->bufSize, HDC_SOCKETPAIR_SIZE); 993 buf->base = (char *)context->ioBuf + context->availTailIndex; 994 int size = context->bufSize - context->availTailIndex; 995 buf->len = std::min(size, static_cast<int>(sizeWanted)); 996} 997 998void HdcSessionBase::FinishWriteSessionTCP(uv_write_t *req, int status) 999{ 1000 HSession hSession = (HSession)req->handle->data; 1001 --hSession->ref; 1002 HdcSessionBase *thisClass = (HdcSessionBase *)hSession->classInstance; 1003 if (status < 0) { 1004 WRITE_LOG(LOG_WARN, "FinishWriteSessionTCP status:%d sessionId:%u isDead:%d ref:%u", 1005 status, hSession->sessionId, hSession->isDead, uint32_t(hSession->ref)); 1006 Base::TryCloseHandle((uv_handle_t *)req->handle); 1007 if (!hSession->isDead && !hSession->ref) { 1008 WRITE_LOG(LOG_DEBUG, "FinishWriteSessionTCP freesession :%u", hSession->sessionId); 1009 thisClass->FreeSession(hSession->sessionId); 1010 } 1011 } 1012 delete[]((uint8_t *)req->data); 1013 delete req; 1014} 1015 1016bool HdcSessionBase::DispatchSessionThreadCommand(HSession hSession, const uint8_t *baseBuf, 1017 const int bytesIO) 1018{ 1019 bool ret = true; 1020 uint8_t flag = *const_cast<uint8_t *>(baseBuf); 1021 1022 switch (flag) { 1023 case SP_JDWP_NEWFD: 1024 case SP_ARK_NEWFD: { 1025 JdwpNewFileDescriptor(baseBuf, bytesIO); 1026 break; 1027 } 1028 default: 1029 WRITE_LOG(LOG_WARN, "Not support session command"); 1030 break; 1031 } 1032 return ret; 1033} 1034 1035void HdcSessionBase::ReadCtrlFromSession(uv_poll_t *poll, int status, int events) 1036{ 1037 HSession hSession = (HSession)poll->data; 1038 HdcSessionBase *hSessionBase = (HdcSessionBase *)hSession->classInstance; 1039 const int size = Base::GetMaxBufSizeStable(); 1040 char *buf = reinterpret_cast<char *>(new uint8_t[size]()); 1041 ssize_t nread = Base::ReadFromFd(hSession->ctrlFd[STREAM_MAIN], buf, size); 1042 while (true) { 1043 if (nread < 0) { 1044 constexpr int bufSize = 1024; 1045 char buffer[bufSize] = { 0 }; 1046 uv_strerror_r(static_cast<int>(nread), buffer, bufSize); 1047 WRITE_LOG(LOG_WARN, "ReadCtrlFromSession failed,%s", buffer); 1048 uv_poll_stop(poll); 1049 break; 1050 } 1051 if (nread == 0) { 1052 WRITE_LOG(LOG_FATAL, "ReadCtrlFromSession read data zero byte"); 1053 break; 1054 } 1055 // only one command, no need to split command from stream 1056 // if add more commands, consider the format command 1057 hSessionBase->DispatchSessionThreadCommand(hSession, reinterpret_cast<uint8_t *>(buf), nread); 1058 break; 1059 } 1060 delete[] buf; 1061} 1062 1063void HdcSessionBase::WorkThreadInitSession(HSession hSession, SessionHandShake &handshake) 1064{ 1065 handshake.banner = HANDSHAKE_MESSAGE; 1066 handshake.sessionId = hSession->sessionId; 1067 handshake.connectKey = hSession->connectKey; 1068 if (!hSession->isCheck) { 1069 handshake.version = Base::GetVersion() + HDC_MSG_HASH; 1070 WRITE_LOG(LOG_INFO, "set version = %s", handshake.version.c_str()); 1071 } 1072 handshake.authType = AUTH_NONE; 1073 // told daemon, we support RSA_3072_SHA512 auth 1074 Base::TlvAppend(handshake.buf, TAG_AUTH_TYPE, std::to_string(AuthVerifyType::RSA_3072_SHA512)); 1075} 1076 1077bool HdcSessionBase::WorkThreadStartSession(HSession hSession) 1078{ 1079 bool regOK = false; 1080 int childRet = 0; 1081 if (hSession->connType == CONN_TCP) { 1082 HdcTCPBase *pTCPBase = (HdcTCPBase *)hSession->classModule; 1083 hSession->hChildWorkTCP.data = hSession; 1084 if (uv_tcp_init(&hSession->childLoop, &hSession->hChildWorkTCP) < 0) { 1085 WRITE_LOG(LOG_WARN, "HdcSessionBase SessionCtrl failed 1"); 1086 return false; 1087 } 1088 if ((childRet = uv_tcp_open(&hSession->hChildWorkTCP, hSession->fdChildWorkTCP)) < 0) { 1089 constexpr int bufSize = 1024; 1090 char buf[bufSize] = { 0 }; 1091 uv_strerror_r(childRet, buf, bufSize); 1092 WRITE_LOG(LOG_WARN, "SessionCtrl failed 2,fd:%d,str:%s", hSession->fdChildWorkTCP, buf); 1093 return false; 1094 } 1095 Base::SetTcpOptions((uv_tcp_t *)&hSession->hChildWorkTCP); 1096 uv_read_start((uv_stream_t *)&hSession->hChildWorkTCP, AllocCallback, pTCPBase->ReadStream); 1097 regOK = true; 1098#ifdef HDC_SUPPORT_UART 1099 } else if (hSession->connType == CONN_SERIAL) { // UART 1100 HdcUARTBase *pUARTBase = (HdcUARTBase *)hSession->classModule; 1101 WRITE_LOG(LOG_DEBUG, "UART ReadyForWorkThread"); 1102 regOK = pUARTBase->ReadyForWorkThread(hSession); 1103#endif 1104 } else { // USB 1105 HdcUSBBase *pUSBBase = (HdcUSBBase *)hSession->classModule; 1106 WRITE_LOG(LOG_DEBUG, "USB ReadyForWorkThread"); 1107 regOK = pUSBBase->ReadyForWorkThread(hSession); 1108 } 1109 1110 if (regOK && hSession->serverOrDaemon) { 1111 // session handshake step1 1112 SessionHandShake handshake = {}; 1113 WorkThreadInitSession(hSession, handshake); 1114 string hs = SerialStruct::SerializeToString(handshake); 1115#ifdef HDC_SUPPORT_UART 1116 WRITE_LOG(LOG_DEBUG, "WorkThreadStartSession session %u auth %u send handshake hs: %s", 1117 hSession->sessionId, handshake.authType, hs.c_str()); 1118#endif 1119 Send(hSession->sessionId, 0, CMD_KERNEL_HANDSHAKE, 1120 reinterpret_cast<uint8_t *>(const_cast<char *>(hs.c_str())), hs.size()); 1121 } 1122 return regOK; 1123} 1124 1125vector<uint8_t> HdcSessionBase::BuildCtrlString(InnerCtrlCommand command, uint32_t channelId, uint8_t *data, 1126 int dataSize) 1127{ 1128 vector<uint8_t> ret; 1129 while (true) { 1130 if (dataSize > BUF_SIZE_MICRO) { 1131 WRITE_LOG(LOG_WARN, "BuildCtrlString dataSize:%d", dataSize); 1132 break; 1133 } 1134 CtrlStruct ctrl = {}; 1135 ctrl.command = command; 1136 ctrl.channelId = channelId; 1137 ctrl.dataSize = dataSize; 1138 if (dataSize > 0 && data != nullptr && memcpy_s(ctrl.data, sizeof(ctrl.data), data, dataSize) != EOK) { 1139 break; 1140 } 1141 uint8_t *buf = reinterpret_cast<uint8_t *>(&ctrl); 1142 ret.insert(ret.end(), buf, buf + sizeof(CtrlStruct)); 1143 break; 1144 } 1145 return ret; 1146} 1147 1148bool HdcSessionBase::DispatchMainThreadCommand(HSession hSession, const CtrlStruct *ctrl) 1149{ 1150 bool ret = true; 1151 uint32_t channelId = ctrl->channelId; // if send not set, it is zero 1152 switch (ctrl->command) { 1153 case SP_START_SESSION: { 1154 WRITE_LOG(LOG_WARN, "Dispatch MainThreadCommand START_SESSION sessionId:%u instance:%s", 1155 hSession->sessionId, hSession->serverOrDaemon ? "server" : "daemon"); 1156 ret = WorkThreadStartSession(hSession); 1157 break; 1158 } 1159 case SP_STOP_SESSION: { 1160 WRITE_LOG(LOG_WARN, "Dispatch MainThreadCommand STOP_SESSION sessionId:%u", hSession->sessionId); 1161 auto closeSessionChildThreadTCPHandle = [](uv_handle_t *handle) -> void { 1162 HSession hSession = (HSession)handle->data; 1163 Base::TryCloseHandle((uv_handle_t *)handle); 1164 if (handle == (uv_handle_t *)hSession->pollHandle[STREAM_WORK]) { 1165 free(hSession->pollHandle[STREAM_WORK]); 1166 } 1167 if (--hSession->uvChildRef == 0) { 1168 uv_stop(&hSession->childLoop); 1169 }; 1170 }; 1171 constexpr int uvChildRefOffset = 2; 1172 hSession->uvChildRef += uvChildRefOffset; 1173 if (hSession->connType == CONN_TCP && hSession->hChildWorkTCP.loop) { // maybe not use it 1174 ++hSession->uvChildRef; 1175 Base::TryCloseHandle((uv_handle_t *)&hSession->hChildWorkTCP, true, closeSessionChildThreadTCPHandle); 1176 } 1177 Base::TryCloseHandle((uv_handle_t *)hSession->pollHandle[STREAM_WORK], true, 1178 closeSessionChildThreadTCPHandle); 1179 Base::TryCloseHandle((uv_handle_t *)&hSession->dataPipe[STREAM_WORK], true, 1180 closeSessionChildThreadTCPHandle); 1181 break; 1182 } 1183 case SP_ATTACH_CHANNEL: { 1184 if (!serverOrDaemon) { 1185 break; // Only Server has this feature 1186 } 1187 AttachChannel(hSession, channelId); 1188 break; 1189 } 1190 case SP_DEATCH_CHANNEL: { 1191 if (!serverOrDaemon) { 1192 break; // Only Server has this feature 1193 } 1194 DeatchChannel(hSession, channelId); 1195 break; 1196 } 1197 default: 1198 WRITE_LOG(LOG_WARN, "Not support main command"); 1199 ret = false; 1200 break; 1201 } 1202 return ret; 1203} 1204 1205// Several bytes of control instructions, generally do not stick 1206void HdcSessionBase::ReadCtrlFromMain(uv_poll_t *poll, int status, int events) 1207{ 1208 HSession hSession = (HSession)poll->data; 1209 HdcSessionBase *hSessionBase = (HdcSessionBase *)hSession->classInstance; 1210 int formatCommandSize = sizeof(CtrlStruct); 1211 int index = 0; 1212 const int size = Base::GetMaxBufSizeStable(); 1213 char *buf = reinterpret_cast<char *>(new uint8_t[size]()); 1214 ssize_t nread = Base::ReadFromFd(hSession->ctrlFd[STREAM_WORK], buf, size); 1215 while (true) { 1216 if (nread < 0) { 1217 constexpr int bufSize = 1024; 1218 char buffer[bufSize] = { 0 }; 1219 uv_strerror_r(static_cast<int>(nread), buffer, bufSize); 1220 WRITE_LOG(LOG_WARN, "SessionCtrl failed,%s", buffer); 1221 break; 1222 } 1223 if (nread % formatCommandSize != 0) { 1224 WRITE_LOG(LOG_FATAL, "ReadCtrlFromMain size failed, nread == %d", nread); 1225 break; 1226 } 1227 CtrlStruct *ctrl = reinterpret_cast<CtrlStruct *>(buf + index); 1228 if (!hSessionBase->DispatchMainThreadCommand(hSession, ctrl)) { 1229 WRITE_LOG(LOG_FATAL, "ReadCtrlFromMain failed sessionId:%u channelId:%u command:%u", 1230 hSession->sessionId, ctrl->channelId, ctrl->command); 1231 break; 1232 } 1233 index += sizeof(CtrlStruct); 1234 if (index >= nread) { 1235 break; 1236 } 1237 } 1238 delete[] buf; 1239} 1240 1241void HdcSessionBase::ReChildLoopForSessionClear(HSession hSession) 1242{ 1243 // Restart loop close task 1244 ClearOwnTasks(hSession, 0); 1245 WRITE_LOG(LOG_INFO, "ReChildLoopForSessionClear sessionId:%u", hSession->sessionId); 1246 auto clearTaskForSessionFinish = [](uv_timer_t *handle) -> void { 1247 HSession hSession = (HSession)handle->data; 1248 for (auto v : *hSession->mapTask) { 1249 HTaskInfo hTask = (HTaskInfo)v.second; 1250 uint8_t level; 1251 if (hTask->closeRetryCount < GLOBAL_TIMEOUT / 2) { 1252 level = LOG_DEBUG; 1253 } else { 1254 level = LOG_WARN; 1255 } 1256 WRITE_LOG(level, "wait task free retry %d/%d, channelId:%u, sessionId:%u", 1257 hTask->closeRetryCount, GLOBAL_TIMEOUT, hTask->channelId, hTask->sessionId); 1258 if (hTask->closeRetryCount++ >= GLOBAL_TIMEOUT) { 1259 HdcSessionBase *thisClass = (HdcSessionBase *)hTask->ownerSessionClass; 1260 hSession = thisClass->AdminSession(OP_QUERY, hTask->sessionId, nullptr); 1261 thisClass->AdminTask(OP_VOTE_RESET, hSession, hTask->channelId, nullptr); 1262 } 1263 if (!hTask->taskFree) 1264 return; 1265 } 1266 // all task has been free 1267 uv_close((uv_handle_t *)handle, Base::CloseTimerCallback); 1268 uv_stop(&hSession->childLoop); // stop ReChildLoopForSessionClear pendding 1269 }; 1270 Base::TimerUvTask( 1271 &hSession->childLoop, hSession, clearTaskForSessionFinish, (GLOBAL_TIMEOUT * TIME_BASE) / UV_DEFAULT_INTERVAL); 1272 uv_run(&hSession->childLoop, UV_RUN_DEFAULT); 1273 // clear 1274 Base::TryCloseChildLoop(&hSession->childLoop, "Session childUV"); 1275} 1276 1277void HdcSessionBase::SessionWorkThread(uv_work_t *arg) 1278{ 1279 HSession hSession = (HSession)arg->data; 1280 HdcSessionBase *thisClass = (HdcSessionBase *)hSession->classInstance; 1281 hSession->hWorkChildThread = uv_thread_self(); 1282 1283 uv_poll_t *pollHandle = hSession->pollHandle[STREAM_WORK]; 1284 pollHandle->data = hSession; 1285 uv_poll_init_socket(&hSession->childLoop, pollHandle, hSession->ctrlFd[STREAM_WORK]); 1286 uv_poll_start(pollHandle, UV_READABLE, ReadCtrlFromMain); 1287 WRITE_LOG(LOG_DEBUG, "!!!Workthread run begin, sessionId:%u instance:%s", hSession->sessionId, 1288 thisClass->serverOrDaemon ? "server" : "daemon"); 1289 uv_run(&hSession->childLoop, UV_RUN_DEFAULT); // work pendding 1290 WRITE_LOG(LOG_DEBUG, "!!!Workthread run again, sessionId:%u", hSession->sessionId); 1291 // main loop has exit 1292 thisClass->ReChildLoopForSessionClear(hSession); // work pending again 1293 hSession->childCleared = true; 1294 WRITE_LOG(LOG_WARN, "!!!Workthread run finish, sessionId:%u", hSession->sessionId); 1295} 1296 1297// clang-format off 1298void HdcSessionBase::LogMsg(const uint32_t sessionId, const uint32_t channelId, 1299 MessageLevel level, const char *msg, ...) 1300// clang-format on 1301{ 1302 va_list vaArgs; 1303 va_start(vaArgs, msg); 1304 string log = Base::StringFormat(msg, vaArgs); 1305 va_end(vaArgs); 1306 vector<uint8_t> buf; 1307 buf.push_back(level); 1308 buf.insert(buf.end(), log.c_str(), log.c_str() + log.size()); 1309 ServerCommand(sessionId, channelId, CMD_KERNEL_ECHO, buf.data(), buf.size()); 1310} 1311 1312bool HdcSessionBase::NeedNewTaskInfo(const uint16_t command, bool &masterTask) 1313{ 1314 // referer from HdcServerForClient::DoCommandRemote 1315 bool ret = false; 1316 bool taskMasterInit = false; 1317 masterTask = false; 1318 switch (command) { 1319 case CMD_FILE_INIT: 1320 case CMD_FLASHD_FLASH_INIT: 1321 case CMD_FLASHD_UPDATE_INIT: 1322 case CMD_FLASHD_ERASE: 1323 case CMD_FLASHD_FORMAT: 1324 case CMD_FORWARD_INIT: 1325 case CMD_APP_INIT: 1326 case CMD_APP_UNINSTALL: 1327 case CMD_APP_SIDELOAD: 1328 taskMasterInit = true; 1329 break; 1330 default: 1331 break; 1332 } 1333 if (!serverOrDaemon 1334 && (command == CMD_SHELL_INIT || (command > CMD_UNITY_COMMAND_HEAD && command < CMD_UNITY_COMMAND_TAIL))) { 1335 // daemon's single side command 1336 ret = true; 1337 } else if (command == CMD_KERNEL_WAKEUP_SLAVETASK) { 1338 // slave tasks 1339 ret = true; 1340 } else if (command == CMD_UNITY_BUGREPORT_INIT) { 1341 ret = true; 1342 } else if (taskMasterInit) { 1343 // task init command 1344 masterTask = true; 1345 ret = true; 1346 } 1347 return ret; 1348} 1349// Heavy and time-consuming work was putted in the new thread to do, and does 1350// not occupy the main thread 1351bool HdcSessionBase::DispatchTaskData(HSession hSession, const uint32_t channelId, const uint16_t command, 1352 uint8_t *payload, int payloadSize) 1353{ 1354 StartTraceScope("HdcSessionBase::DispatchTaskData"); 1355 bool ret = true; 1356 HTaskInfo hTaskInfo = nullptr; 1357 bool masterTask = false; 1358 while (true) { 1359 // Some basic commands do not have a local task constructor. example: Interactive shell, some uinty commands 1360 if (NeedNewTaskInfo(command, masterTask)) { 1361 WRITE_LOG(LOG_DEBUG, "New HTaskInfo channelId:%u command:%u", channelId, command); 1362 hTaskInfo = new(std::nothrow) TaskInformation(); 1363 if (hTaskInfo == nullptr) { 1364 WRITE_LOG(LOG_FATAL, "DispatchTaskData new hTaskInfo failed"); 1365 break; 1366 } 1367 hTaskInfo->channelId = channelId; 1368 hTaskInfo->sessionId = hSession->sessionId; 1369 hTaskInfo->runLoop = &hSession->childLoop; 1370 hTaskInfo->serverOrDaemon = serverOrDaemon; 1371 hTaskInfo->masterSlave = masterTask; 1372 hTaskInfo->closeRetryCount = 0; 1373 hTaskInfo->channelTask = false; 1374 hTaskInfo->isCleared = false; 1375 1376 int addTaskRetry = 3; // try 3 time 1377 while (addTaskRetry > 0) { 1378 if (AdminTask(OP_ADD, hSession, channelId, hTaskInfo)) { 1379 break; 1380 } 1381 sleep(1); 1382 --addTaskRetry; 1383 } 1384 1385 if (addTaskRetry == 0) { 1386#ifndef HDC_HOST 1387 LogMsg(hTaskInfo->sessionId, hTaskInfo->channelId, 1388 MSG_FAIL, "hdc thread pool busy, may cause reset later"); 1389#endif 1390 delete hTaskInfo; 1391 hTaskInfo = nullptr; 1392 ret = false; 1393 break; 1394 } 1395 } else { 1396 hTaskInfo = AdminTask(OP_QUERY, hSession, channelId, nullptr); 1397 } 1398 if (!hTaskInfo || hTaskInfo->taskStop || hTaskInfo->taskFree) { 1399 WRITE_LOG(LOG_ALL, "Dead HTaskInfo, ignore, channelId:%u command:%u", channelId, command); 1400 break; 1401 } 1402 ret = RedirectToTask(hTaskInfo, hSession, channelId, command, payload, payloadSize); 1403 break; 1404 } 1405 return ret; 1406} 1407 1408void HdcSessionBase::PostStopInstanceMessage(bool restart) 1409{ 1410 PushAsyncMessage(0, ASYNC_STOP_MAINLOOP, nullptr, 0); 1411 WRITE_LOG(LOG_DEBUG, "StopDaemon has sended restart %d", restart); 1412 wantRestart = restart; 1413} 1414} // namespace Hdc 1415