• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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