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