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