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