xref: /developtools/hdc/src/host/server.cpp (revision cc290419)
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
19namespace Hdc {
20HdcServer::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
33HdcServer::~HdcServer()
34{
35    WRITE_LOG(LOG_DEBUG, "~HdcServer");
36    uv_rwlock_destroy(&daemonAdmin);
37    uv_rwlock_destroy(&forwardAdmin);
38}
39
40void 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
60void 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
81bool 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
120bool 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
166bool 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
207void 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
223void 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
257string 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
280void 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
300void 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
316string 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
394void 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
426void 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
450bool 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
488void 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
528bool 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
561bool 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
660void 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
672string 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
726void 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
744void 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
770void 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
806void 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
819int 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
893void 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
920void 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
959bool 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
972bool 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
1026bool 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
1055void 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