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