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