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_for_client.h"
16#ifndef TEST_HASH
17#include "hdc_hash_gen.h"
18#endif
19#include "server.h"
20
21namespace Hdc {
22static const int MAX_RETRY_COUNT = 500;
23static const int MAX_CONNECT_DEVICE_RETRY_COUNT = 100;
24
25HdcServerForClient::HdcServerForClient(const bool serverOrClient, const string &addrString, void *pClsServer,
26                                       uv_loop_t *loopMainIn)
27    : HdcChannelBase(serverOrClient, addrString, loopMainIn)
28{
29    clsServer = pClsServer;
30}
31
32HdcServerForClient::~HdcServerForClient()
33{
34    WRITE_LOG(LOG_DEBUG, "~HdcServerForClient");
35}
36
37void HdcServerForClient::Stop()
38{
39    Base::TryCloseHandle((uv_handle_t *)&tcpListen);
40}
41
42uint16_t HdcServerForClient::GetTCPListenPort()
43{
44    return channelPort;
45}
46
47void HdcServerForClient::AcceptClient(uv_stream_t *server, int status)
48{
49    uv_tcp_t *pServTCP = (uv_tcp_t *)server;
50    HdcServerForClient *thisClass = (HdcServerForClient *)pServTCP->data;
51    HChannel hChannel = nullptr;
52    uint32_t uid = thisClass->MallocChannel(&hChannel);
53    if (!hChannel) {
54        WRITE_LOG(LOG_FATAL, "AcceptClient hChannel is nullptr");
55        return;
56    }
57    int rc = uv_accept(server, (uv_stream_t *)&hChannel->hWorkTCP);
58    if (rc < 0) {
59        WRITE_LOG(LOG_FATAL, "AcceptClient uv_accept error rc:%d uid:%u", rc, uid);
60        thisClass->FreeChannel(uid);
61        return;
62    }
63    WRITE_LOG(LOG_DEBUG, "AcceptClient uid:%u", uid);
64    // limit first recv
65    int bufMaxSize = 0;
66    uv_recv_buffer_size((uv_handle_t *)&hChannel->hWorkTCP, &bufMaxSize);
67    auto funcChannelHeaderAlloc = [](uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf) -> void {
68        HChannel context = (HChannel)handle->data;
69        Base::ReallocBuf(&context->ioBuf, &context->bufSize, Base::GetMaxBufSize() * BUF_EXTEND_SIZE);
70        buf->base = (char *)context->ioBuf + context->availTailIndex;
71#ifdef HDC_VERSION_CHECK
72        buf->len = sizeof(struct ChannelHandShake) + DWORD_SERIALIZE_SIZE;  // only recv static size
73#else
74        buf->len = offsetof(struct ChannelHandShake, version) + DWORD_SERIALIZE_SIZE;
75#endif
76    };
77    // first packet static size, after this packet will be dup for normal recv
78    uv_read_start((uv_stream_t *)&hChannel->hWorkTCP, funcChannelHeaderAlloc, ReadStream);
79    // channel handshake step1
80    struct ChannelHandShake handShake = {};
81    if (EOK == strcpy_s(handShake.banner, sizeof(handShake.banner), HANDSHAKE_MESSAGE.c_str())) {
82        handShake.banner[BANNER_FEATURE_TAG_OFFSET] = HUGE_BUF_TAG; // set feature tag for huge buf size
83        handShake.channelId = htonl(hChannel->channelId);
84        string ver = Base::GetVersion() + HDC_MSG_HASH;
85        WRITE_LOG(LOG_DEBUG, "Server ver:%s", ver.c_str());
86        if (EOK != strcpy_s(handShake.version, sizeof(handShake.version), ver.c_str())) {
87            WRITE_LOG(LOG_FATAL, "strcpy_s failed");
88            return;
89        }
90#ifdef HDC_VERSION_CHECK
91    thisClass->Send(hChannel->channelId, (uint8_t *)&handShake, sizeof(struct ChannelHandShake));
92#else
93    // do not send version message if check feature disable
94    thisClass->Send(hChannel->channelId, reinterpret_cast<uint8_t *>(&handShake),
95                    offsetof(struct ChannelHandShake, version));
96#endif
97    }
98}
99
100bool HdcServerForClient::SetTCPListen()
101{
102    char buffer[BUF_SIZE_DEFAULT] = { 0 };
103    tcpListen.data = this;
104    struct sockaddr_in6 addr;
105    uv_tcp_init(loopMain, &tcpListen);
106
107    WRITE_LOG(LOG_DEBUG, "channelHost %s, port: %d", channelHost.c_str(), channelPort);
108    int rc = uv_ip6_addr(channelHost.c_str(), channelPort, &addr);
109    if (rc != 0) {
110        uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT);
111        WRITE_LOG(LOG_FATAL, "uv_ip6_addr %d %s", rc, buffer);
112        return false;
113    }
114    rc = uv_tcp_bind(&tcpListen, (const struct sockaddr *)&addr, 0);
115    if (rc != 0) {
116        WRITE_LOG(LOG_WARN, "uv_tcp_bind ipv6 %d", rc);
117        if (rc == -EAFNOSUPPORT) {
118            size_t index = channelHost.find(IPV4_MAPPING_PREFIX);
119            size_t size = IPV4_MAPPING_PREFIX.size();
120            if (index != std::string::npos) {
121                struct sockaddr_in addr4v;
122                std::string ipv4 = channelHost.substr(index + size);
123                uv_ip4_addr(ipv4.c_str(), channelPort, &addr4v);
124                rc = uv_tcp_bind(&tcpListen, (const struct sockaddr *)&addr4v, 0);
125                if (rc != 0) {
126                    uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT);
127                    WRITE_LOG(LOG_FATAL, "uv_tcp_bind ipv4 %s failed %d %s",
128                        ipv4.c_str(), rc, buffer);
129                    return false;
130                }
131            }
132        } else {
133            uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT);
134            WRITE_LOG(LOG_FATAL, "uv_tcp_bind %d %s", rc, buffer);
135            return false;
136        }
137    }
138    int backLog = 128;
139    rc = uv_listen((uv_stream_t *)&tcpListen, backLog, (uv_connection_cb)AcceptClient);
140    if (rc != 0) {
141        uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT);
142        WRITE_LOG(LOG_FATAL, "uv_listen %d %s", rc, buffer);
143        return false;
144    }
145    return true;
146}
147
148int HdcServerForClient::Initial()
149{
150    if (!clsServer) {
151        WRITE_LOG(LOG_FATAL, "Module client initial failed");
152        return -1;
153    }
154    if (!channelHostPort.size() || !channelHost.size() || !channelPort) {
155        WRITE_LOG(LOG_FATAL, "Listen string initial failed");
156        return -2;  // -2:err for Listen initial failed
157    }
158    bool b = SetTCPListen();
159    if (!b) {
160        WRITE_LOG(LOG_FATAL, "SetTCPListen failed");
161        int listenError = -3;  // -3:error for SetTCPListen failed
162        return listenError;
163    }
164    return 0;
165}
166
167void HdcServerForClient::EchoClient(HChannel hChannel, MessageLevel level, const char *msg, ...)
168{
169    string logInfo = "";
170    switch (level) {
171        case MSG_FAIL:
172            logInfo = MESSAGE_FAIL;
173            break;
174        case MSG_INFO:
175            logInfo = MESSAGE_INFO;
176            break;
177        default:  // successful, not append extra info
178            break;
179    }
180    va_list vaArgs;
181    va_start(vaArgs, msg);
182    string log = logInfo + Base::StringFormat(msg, vaArgs);
183    va_end(vaArgs);
184    if (log.back() != '\n') {
185        log += "\r\n";
186    }
187    SendChannel(hChannel, const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(log.c_str())), log.size());
188}
189
190void HdcServerForClient::EchoClientRaw(const HChannel hChannel, uint8_t *payload, const int payloadSize)
191{
192    SendChannel(hChannel, payload, payloadSize);
193}
194
195// HdcServerForClient passthrough file command to client
196void HdcServerForClient::SendCommandToClient(const HChannel hChannel, const uint16_t commandFlag,
197                                             uint8_t *payload, const int payloadSize)
198{
199    SendChannelWithCmd(hChannel, commandFlag, payload, payloadSize);
200}
201
202bool HdcServerForClient::SendToDaemon(HChannel hChannel, const uint16_t commandFlag, uint8_t *bufPtr, const int bufSize)
203{
204    HDaemonInfo hdi = nullptr;
205    bool ret = false;
206    HdcServer *ptrServer = (HdcServer *)clsServer;
207    while (true) {
208        ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi);
209        if (hdi == nullptr) {
210            WRITE_LOG(LOG_FATAL, "SendToDaemon hdi nullptr");
211            break;
212        }
213        if (hdi->connStatus != STATUS_CONNECTED) {
214            WRITE_LOG(LOG_FATAL, "SendToDaemon not connected");
215            break;
216        }
217        if (!hdi->hSession) {
218            WRITE_LOG(LOG_FATAL, "SendToDaemon hdi->hSession nullptr");
219            break;
220        }
221        if (ptrServer->Send(hdi->hSession->sessionId, hChannel->channelId, commandFlag, bufPtr, bufSize) < 0) {
222            WRITE_LOG(LOG_FATAL, "SendToDaemon Send failed channelId:%u", hChannel->channelId);
223            break;
224        }
225        ret = true;
226        break;
227    }
228    return ret;
229}
230
231void HdcServerForClient::OrderFindTargets(HChannel hChannel)
232{
233    int count = 0;
234    EchoClient(hChannel, MSG_INFO, "Please add HDC server's firewall ruler to allow udp incoming, udpport:%d",
235               DEFAULT_PORT);
236    HdcServer *ptrServer = (HdcServer *)clsServer;
237    ptrServer->clsTCPClt->FindLanDaemon();
238    list<string> &lst = ptrServer->clsTCPClt->lstDaemonResult;
239    // refresh main list
240    HdcDaemonInformation di;
241    while (!lst.empty()) {
242        di = {};
243        ++count;
244        di.connectKey = lst.front();
245        di.connType = CONN_TCP;
246        di.connStatus = STATUS_READY;
247        HDaemonInfo pDi = reinterpret_cast<HDaemonInfo>(&di);
248        ptrServer->AdminDaemonMap(OP_ADD, STRING_EMPTY, pDi);
249        lst.pop_front();
250    }
251    EchoClient(hChannel, MSG_INFO, "Broadcast find daemon, total:%d", count);
252#ifdef UNIT_TEST
253    string bufString = std::to_string(count);
254    Base::WriteBinFile((UT_TMP_PATH + "/base-discover.result").c_str(), (uint8_t *)bufString.c_str(), bufString.size(),
255                       true);
256#endif
257}
258
259void HdcServerForClient::OrderConnecTargetResult(uv_timer_t *req)
260{
261    HChannel hChannel = (HChannel)req->data;
262    HdcServerForClient *thisClass = (HdcServerForClient *)hChannel->clsChannel;
263    HdcServer *ptrServer = (HdcServer *)thisClass->clsServer;
264    bool bConnectOK = false;
265    bool bExitRepet = false;
266    HDaemonInfo hdi = nullptr;
267    string sRet;
268    string target = std::string(hChannel->bufStd + 2);
269    if (target == "any") {
270        ptrServer->AdminDaemonMap(OP_GET_ANY, target, hdi);
271    } else {
272        ptrServer->AdminDaemonMap(OP_QUERY, target, hdi);
273    }
274    if (hdi && hdi->connStatus == STATUS_CONNECTED) {
275        bConnectOK = true;
276    }
277    while (true) {
278        if (bConnectOK) {
279            bExitRepet = true;
280            if (hChannel->isCheck) {
281                WRITE_LOG(LOG_INFO, "%s check device success and remove %s", __FUNCTION__, hChannel->key.c_str());
282                thisClass->CommandRemoveSession(hChannel, hChannel->key.c_str());
283                thisClass->EchoClient(hChannel, MSG_OK, const_cast<char *>(hdi->version.c_str()));
284            } else {
285                sRet = "Connect OK";
286                thisClass->EchoClient(hChannel, MSG_OK, const_cast<char *>(sRet.c_str()));
287            }
288            break;
289        } else {
290            uint16_t *bRetryCount = reinterpret_cast<uint16_t *>(hChannel->bufStd);
291            ++(*bRetryCount);
292            if (*bRetryCount > MAX_RETRY_COUNT ||
293                (hChannel->connectLocalDevice && *bRetryCount > MAX_CONNECT_DEVICE_RETRY_COUNT)) {
294                // 5s or localDevice 1s
295                bExitRepet = true;
296                sRet = "Connect failed";
297                thisClass->EchoClient(hChannel, MSG_FAIL, const_cast<char *>(sRet.c_str()));
298                break;
299            }
300        }
301        break;
302    }
303    if (bExitRepet) {
304        thisClass->FreeChannel(hChannel->channelId);
305        Base::TryCloseHandle((const uv_handle_t *)req, Base::CloseTimerCallback);
306    }
307}
308
309bool HdcServerForClient::NewConnectTry(void *ptrServer, HChannel hChannel, const string &connectKey, bool isCheck)
310{
311#ifdef HDC_DEBUG
312    WRITE_LOG(LOG_ALL, "%s %s", __FUNCTION__, Hdc::MaskString(connectKey).c_str());
313#endif
314    int childRet = ((HdcServer *)ptrServer)->CreateConnect(connectKey, isCheck);
315    bool ret = false;
316    int connectError = -2;
317    constexpr uint8_t bufOffsetTwo = 2;
318    constexpr uint8_t bufOffsetThree = 3;
319    if (childRet == -1) {
320        EchoClient(hChannel, MSG_INFO, "Target is connected, repeat operation");
321    } else if (childRet == connectError) {
322        EchoClient(hChannel, MSG_FAIL, "CreateConnect failed");
323        WRITE_LOG(LOG_FATAL, "CreateConnect failed");
324    } else {
325        size_t pos = connectKey.find(":");
326        if (pos != std::string::npos) {
327            string ip = connectKey.substr(0, pos);
328            if (ip == "127.0.0.1") {
329                hChannel->connectLocalDevice = true;
330            }
331        }
332        Base::ZeroBuf(hChannel->bufStd, bufOffsetTwo);
333        childRet = snprintf_s(hChannel->bufStd + bufOffsetTwo, sizeof(hChannel->bufStd) - bufOffsetTwo,
334                              sizeof(hChannel->bufStd) - bufOffsetThree, "%s",
335                              const_cast<char *>(connectKey.c_str()));
336        if (childRet > 0) {
337            Base::TimerUvTask(loopMain, hChannel, OrderConnecTargetResult, UV_START_REPEAT);
338            ret = true;
339        }
340    }
341    return ret;
342}
343
344bool HdcServerForClient::CommandRemoveSession(HChannel hChannel, const char *connectKey)
345{
346    HdcServer *ptrServer = (HdcServer *)clsServer;
347    HDaemonInfo hdiOld = nullptr;
348    (reinterpret_cast<HdcServer *>(ptrServer))->AdminDaemonMap(OP_QUERY, connectKey, hdiOld);
349    if (!hdiOld) {
350        EchoClient(hChannel, MSG_FAIL, "No target available");
351        return false;
352    }
353    (reinterpret_cast<HdcServer *>(ptrServer))->FreeSession(hdiOld->hSession->sessionId);
354    return true;
355}
356
357bool HdcServerForClient::CommandRemoveForward(const string &forwardKey)
358{
359    bool ret = RemoveFportkey("0|" + forwardKey);
360    ret |= RemoveFportkey("1|" + forwardKey);
361    return ret;
362}
363
364bool HdcServerForClient::RemoveFportkey(const string &forwardKey)
365{
366    HdcServer *ptrServer = (HdcServer *)clsServer;
367    HForwardInfo hfi = nullptr;
368    ptrServer->AdminForwardMap(OP_QUERY, forwardKey, hfi);
369    if (!hfi) {
370        WRITE_LOG(LOG_FATAL, "CommandRemoveForward hfi nullptr forwardKey:%s", forwardKey.c_str());
371        return false;
372    }
373    HSession hSession = ptrServer->AdminSession(OP_QUERY, hfi->sessionId, nullptr);
374    if (!hSession) {
375        WRITE_LOG(LOG_FATAL, "CommandRemoveForward hSession nullptr sessionId:%u", hfi->sessionId);
376        ptrServer->AdminForwardMap(OP_REMOVE, forwardKey, hfi);
377        return true;
378    }
379    ptrServer->ClearOwnTasks(hSession, hfi->channelId);
380    FreeChannel(hfi->channelId);
381    hfi = nullptr;
382    ptrServer->AdminForwardMap(OP_REMOVE, forwardKey, hfi);
383    return true;
384}
385
386void HdcServerForClient::GetTargetList(HChannel hChannel, void *formatCommandInput)
387{
388    TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
389    HdcServer *ptrServer = (HdcServer *)clsServer;
390    uint16_t cmd = OP_GET_STRLIST;
391    if (formatCommand->parameters == "v") {
392        cmd = OP_GET_STRLIST_FULL;
393    }
394    HDaemonInfo hdi = nullptr;
395    string sRet = ptrServer->AdminDaemonMap(cmd, STRING_EMPTY, hdi);
396    if (!sRet.length()) {
397        sRet = EMPTY_ECHO;
398    }
399    EchoClient(hChannel, MSG_OK, const_cast<char *>(sRet.c_str()));
400#ifdef UNIT_TEST
401    Base::WriteBinFile((UT_TMP_PATH + "/base-list.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(),
402                       MESSAGE_SUCCESS.size(), true);
403#endif
404}
405
406bool HdcServerForClient::GetAnyTarget(HChannel hChannel)
407{
408    HdcServer *ptrServer = (HdcServer *)clsServer;
409    HDaemonInfo hdi = nullptr;
410    ptrServer->AdminDaemonMap(OP_GET_ANY, STRING_EMPTY, hdi);
411    if (!hdi) {
412        EchoClient(hChannel, MSG_FAIL, "No target available");
413        return false;
414    }
415    // can not use hdi->connectKey.This memory may be released to re-Malloc
416    string connectKey = hdi->connectKey;
417    bool ret = NewConnectTry(ptrServer, hChannel, connectKey);
418#ifdef UNIT_TEST
419    Base::WriteBinFile((UT_TMP_PATH + "/base-any.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(),
420                       MESSAGE_SUCCESS.size(), true);
421#endif
422    return ret;
423}
424
425bool HdcServerForClient::WaitForAny(HChannel hChannel)
426{
427    HdcServer *ptrServer = (HdcServer *)clsServer;
428    HDaemonInfo hdi = nullptr;
429    if (!hChannel->connectKey.empty()) {
430        ptrServer->AdminDaemonMap(OP_WAIT_FOR_ANY, hChannel->connectKey, hdi);
431    } else {
432        ptrServer->AdminDaemonMap(OP_WAIT_FOR_ANY, STRING_EMPTY, hdi);
433    }
434    if (!hdi) {
435        EchoClient(hChannel, MSG_FAIL, "No any connected target");
436        return false;
437    }
438    string key = hdi->connectKey;
439    EchoClient(hChannel, MSG_OK, "Wait for connected target is %s", key.c_str());
440    return true;
441}
442
443bool HdcServerForClient::RemoveForward(HChannel hChannel, const char *parameterString)
444{
445    HdcServer *ptrServer = (HdcServer *)clsServer;
446    if (parameterString == nullptr) {  // remove all
447        HForwardInfo hfi = nullptr;    // dummy
448        string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST, "", hfi);
449        if (!echo.length()) {
450            return false;
451        }
452        vector<string> filterStrings;
453        Base::SplitString(echo, string("\n"), filterStrings);
454        for (auto &&s : filterStrings) {
455            if (CommandRemoveForward(s.c_str())) {
456                EchoClient(hChannel, MSG_OK, "Remove forward ruler success, ruler:%s", s.c_str());
457            } else {
458                EchoClient(hChannel, MSG_FAIL, "Remove forward ruler failed, ruler is not exist %s", s.c_str());
459            }
460        }
461    } else {  // remove single
462        if (CommandRemoveForward(parameterString)) {
463            EchoClient(hChannel, MSG_OK, "Remove forward ruler success, ruler:%s", parameterString);
464        } else {
465            EchoClient(hChannel, MSG_FAIL, "Remove forward ruler failed, ruler is not exist %s", parameterString);
466        }
467    }
468    return true;
469}
470
471bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandInput)
472{
473    TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
474    HdcServer *ptrServer = (HdcServer *)clsServer;
475    bool ret = false;
476    // Main thread command, direct Listen main thread
477    switch (formatCommand->cmdFlag) {
478        case CMD_KERNEL_TARGET_DISCOVER: {
479            OrderFindTargets(hChannel);
480            ret = false;
481            break;
482        }
483        case CMD_KERNEL_TARGET_LIST: {
484            GetTargetList(hChannel, formatCommandInput);
485            ret = false;
486            break;
487        }
488        case CMD_CHECK_SERVER: {
489            WRITE_LOG(LOG_DEBUG, "CMD_CHECK_SERVER command");
490            ReportServerVersion(hChannel);
491            ret = false;
492            break;
493        }
494        case CMD_WAIT_FOR: {
495            WRITE_LOG(LOG_DEBUG, "CMD_WAIT_FOR command");
496            ret = !WaitForAny(hChannel);
497            break;
498        }
499        case CMD_KERNEL_TARGET_ANY: {
500#ifdef HDC_DEBUG
501            WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_ANY %s", __FUNCTION__, formatCommand->parameters.c_str());
502#endif
503            ret = GetAnyTarget(hChannel);
504            break;
505        }
506        case CMD_KERNEL_TARGET_CONNECT: {
507#ifdef HDC_DEBUG
508            WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_CONNECT %s", __FUNCTION__, formatCommand->parameters.c_str());
509#endif
510            ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str());
511            break;
512        }
513        case CMD_CHECK_DEVICE: {
514            WRITE_LOG(LOG_INFO, "%s CMD_CHECK_DEVICE %s", __FUNCTION__, formatCommand->parameters.c_str());
515            hChannel->isCheck = true;
516            hChannel->key = formatCommand->parameters.c_str();
517            ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str(), true);
518            break;
519        }
520        case CMD_KERNEL_TARGET_DISCONNECT: {
521            CommandRemoveSession(hChannel, formatCommand->parameters.c_str());
522            break;
523        }
524        // task will be global task,Therefore, it can only be controlled in the global session.
525        case CMD_FORWARD_LIST: {
526            HForwardInfo hfi = nullptr;  // dummy
527            string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST_FULL, "", hfi);
528            if (!echo.length()) {
529                echo = EMPTY_ECHO;
530            }
531            EchoClient(hChannel, MSG_OK, const_cast<char *>(echo.c_str()));
532            break;
533        }
534        case CMD_FORWARD_REMOVE: {
535            RemoveForward(hChannel, formatCommand->parameters.c_str());
536            break;
537        }
538        case CMD_KERNEL_ENABLE_KEEPALIVE: {
539            // just use for 'list targets' now
540            hChannel->keepAlive = true;
541            ret = true;
542            break;
543        }
544        default: {
545            EchoClient(hChannel, MSG_FAIL, "ExecuteCommand need connect-key? please confirm a device by help info");
546            break;
547        }
548    }
549    return ret;
550}
551
552bool HdcServerForClient::TaskCommand(HChannel hChannel, void *formatCommandInput)
553{
554    TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
555    HdcServer *ptrServer = (HdcServer *)clsServer;
556    string cmdFlag;
557    uint8_t sizeCmdFlag = 0;
558    if (formatCommand->cmdFlag == CMD_FILE_INIT) {
559        cmdFlag = "send ";
560        sizeCmdFlag = 5;  // 5: cmdFlag send size
561        HandleRemote(hChannel, formatCommand->parameters, RemoteType::REMOTE_FILE);
562    } else if (formatCommand->cmdFlag == CMD_FORWARD_INIT) {
563        cmdFlag = "fport ";
564        sizeCmdFlag = 6;  // 6: cmdFlag fport size
565    } else if (formatCommand->cmdFlag == CMD_APP_INIT) {
566        cmdFlag = "install ";
567        sizeCmdFlag = 8;  // 8: cmdFlag install size
568        HandleRemote(hChannel, formatCommand->parameters, RemoteType::REMOTE_APP);
569    } else if (formatCommand->cmdFlag == CMD_APP_UNINSTALL) {
570        cmdFlag = "uninstall ";
571        sizeCmdFlag = 10;  // 10: cmdFlag uninstall size
572    } else if (formatCommand->cmdFlag == CMD_UNITY_BUGREPORT_INIT) {
573        cmdFlag = "bugreport ";
574        sizeCmdFlag = 10;  // 10: cmdFlag bugreport size
575    } else if (formatCommand->cmdFlag == CMD_APP_SIDELOAD) {
576        cmdFlag = "sideload ";
577        sizeCmdFlag = 9; // 9: cmdFlag sideload size
578    } else if (formatCommand->cmdFlag == CMD_FLASHD_UPDATE_INIT) {
579        cmdFlag = "update ";
580        sizeCmdFlag = 7; // 7: cmdFlag update size
581    } else if (formatCommand->cmdFlag == CMD_FLASHD_FLASH_INIT) {
582        cmdFlag = "flash ";
583        sizeCmdFlag = 6; // 6: cmdFlag flash size
584    }
585    int sizeSend = formatCommand->parameters.size();
586    if (!strncmp(formatCommand->parameters.c_str(), cmdFlag.c_str(), sizeCmdFlag)) {  // local do
587        HSession hSession = FindAliveSession(hChannel->targetSessionId);
588        if (!hSession) {
589            return false;
590        }
591        if ((formatCommand->cmdFlag == CMD_FILE_INIT || formatCommand->cmdFlag == CMD_APP_INIT) &&
592            hChannel->fromClient) {
593            // remote client mode, CMD_FILE_INIT and CMD_APP_INIT command send back to client
594            WRITE_LOG(LOG_DEBUG, "command send back to remote client channelId:%u", hChannel->channelId);
595            SendChannelWithCmd(hChannel, formatCommand->cmdFlag,
596                reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
597                sizeSend - sizeCmdFlag);
598            return false;
599        }
600        ptrServer->DispatchTaskData(hSession, hChannel->channelId, formatCommand->cmdFlag,
601            reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
602            sizeSend - sizeCmdFlag);
603    } else {  // Send to Daemon-side to do
604        SendToDaemon(hChannel, formatCommand->cmdFlag,
605            reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
606            sizeSend - sizeCmdFlag);
607    }
608    return true;
609}
610
611void HdcServerForClient::HandleRemote(HChannel hChannel, string &parameters, RemoteType flag)
612{
613    hChannel->remote = flag;
614    int argc = 0;
615    char **argv = Base::SplitCommandToArgs(parameters.c_str(), &argc);
616    for (int i = 0; i < argc; i++) {
617        if (argv[i] == CMDSTR_REMOTE_PARAMETER) {
618            hChannel->fromClient = true;
619            WRITE_LOG(LOG_DEBUG, "remote client mode channelId:%u", hChannel->channelId);
620            break;
621        }
622    }
623    if (hChannel->fromClient) {
624        string remote = CMDSTR_REMOTE_PARAMETER + " ";
625        if (parameters.find(remote) != std::string::npos) {
626            parameters.replace(parameters.find(remote), remote.size(), "");
627            WRITE_LOG(LOG_DEBUG, "parameters: %s", parameters.c_str());
628        }
629    }
630}
631
632bool HdcServerForClient::DoCommandRemote(HChannel hChannel, void *formatCommandInput)
633{
634    TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
635    bool ret = false;
636    int sizeSend = formatCommand->parameters.size();
637    string cmdFlag;
638    switch (formatCommand->cmdFlag) {
639        // Some simple commands only need to forward the instruction, no need to start Task
640        case CMD_SHELL_INIT:
641        case CMD_SHELL_DATA:
642        case CMD_UNITY_EXECUTE:
643        case CMD_UNITY_REMOUNT:
644        case CMD_UNITY_REBOOT:
645        case CMD_UNITY_RUNMODE:
646        case CMD_UNITY_HILOG:
647        case CMD_UNITY_ROOTRUN:
648        case CMD_JDWP_TRACK:
649        case CMD_JDWP_LIST: {
650            if (!SendToDaemon(hChannel, formatCommand->cmdFlag,
651                              reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())),
652                              sizeSend)) {
653                break;
654            }
655            ret = true;
656            if (formatCommand->cmdFlag == CMD_SHELL_INIT) {
657                hChannel->interactiveShellMode = true;
658            }
659            break;
660        }
661        case CMD_FILE_INIT:
662        case CMD_FORWARD_INIT:
663        case CMD_APP_INIT:
664        case CMD_APP_UNINSTALL:
665        case CMD_UNITY_BUGREPORT_INIT:
666        case CMD_APP_SIDELOAD:
667        case CMD_FLASHD_UPDATE_INIT:
668        case CMD_FLASHD_FLASH_INIT:
669        case CMD_FLASHD_ERASE:
670        case CMD_FLASHD_FORMAT: {
671            TaskCommand(hChannel, formatCommandInput);
672            ret = true;
673            break;
674        }
675        default:
676            break;
677    }
678    if (!ret) {
679        EchoClient(hChannel, MSG_FAIL, "Failed to communicate with daemon");
680    }
681    return ret;
682}
683// Do not specify Target's operations no longer need to put it in the thread.
684bool HdcServerForClient::DoCommand(HChannel hChannel, void *formatCommandInput)
685{
686    bool ret = false;
687    TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
688    if (!hChannel->hChildWorkTCP.loop || formatCommand->cmdFlag == CMD_FORWARD_REMOVE) {
689        // Main thread command, direct Listen main thread
690        ret = DoCommandLocal(hChannel, formatCommandInput);
691    } else {  // CONNECT DAEMON's work thread command, non-primary thread
692        ret = DoCommandRemote(hChannel, formatCommandInput);
693    }
694    return ret;
695}
696
697// just call from BindChannelToSession
698HSession HdcServerForClient::FindAliveSessionFromDaemonMap(const HChannel hChannel)
699{
700    HSession hSession = nullptr;
701    HDaemonInfo hdi = nullptr;
702    HdcServer *ptrServer = (HdcServer *)clsServer;
703    ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi);
704    if (!hdi) {
705        EchoClient(hChannel, MSG_FAIL, "Not match target founded, check connect-key please");
706        return nullptr;
707    }
708    if (hdi->connStatus != STATUS_CONNECTED) {
709        EchoClient(hChannel, MSG_FAIL, "Device not founded or connected");
710        return nullptr;
711    }
712    if (hdi->hSession->isDead) {
713        EchoClient(hChannel, MSG_FAIL, "Bind tartget session is dead");
714        return nullptr;
715    }
716    if (!hdi->hSession->handshakeOK) {
717        WRITE_LOG(LOG_WARN, "hSession handShake is false sid:%u cid:%u",
718            hdi->hSession->sessionId, hChannel->channelId);
719        const string errMsg = "[E000004]:The communication channel is being established.\r\n"\
720            "Please wait for several seconds and try again.";
721        EchoClient(hChannel, MSG_FAIL, errMsg.c_str());
722        return nullptr;
723    }
724    hSession = reinterpret_cast<HSession>(hdi->hSession);
725    return hSession;
726}
727
728int HdcServerForClient::BindChannelToSession(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
729{
730    if (FindAliveSessionFromDaemonMap(hChannel) == nullptr) {
731        WRITE_LOG(LOG_FATAL, "Find no alive session channelId:%u", hChannel->channelId);
732        return ERR_SESSION_NOFOUND;
733    }
734    bool isClosing = uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP);
735    if (!isClosing && (hChannel->fdChildWorkTCP = Base::DuplicateUvSocket(&hChannel->hWorkTCP)) < 0) {
736        WRITE_LOG(LOG_FATAL, "Duplicate socket failed channelId:%u", hChannel->channelId);
737        return ERR_SOCKET_DUPLICATE;
738    }
739    uv_close_cb funcWorkTcpClose = [](uv_handle_t *handle) -> void {
740        HChannel hChannel = (HChannel)handle->data;
741        --hChannel->ref;
742    };
743    ++hChannel->ref;
744    if (!isClosing) {
745        uv_close((uv_handle_t *)&hChannel->hWorkTCP, funcWorkTcpClose);
746    }
747    Base::DoNextLoop(loopMain, hChannel, [](const uint8_t flag, string &msg, const void *data) {
748        // Thread message can avoid using thread lock and improve program efficiency
749        // If not next loop call, ReadStream will thread conflict
750        HChannel hChannel = (HChannel)data;
751        auto thisClass = (HdcServerForClient *)hChannel->clsChannel;
752        HSession hSession = nullptr;
753        if ((hSession = thisClass->FindAliveSessionFromDaemonMap(hChannel)) == nullptr) {
754            WRITE_LOG(LOG_FATAL, "hSession nullptr channelId:%u", hChannel->channelId);
755            return;
756        }
757        auto ctrl = HdcSessionBase::BuildCtrlString(SP_ATTACH_CHANNEL, hChannel->channelId, nullptr, 0);
758        Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
759    });
760    return RET_SUCCESS;
761}
762
763bool HdcServerForClient::CheckAutoFillTarget(HChannel hChannel)
764{
765    HdcServer *ptrServer = (HdcServer *)clsServer;
766    if (!hChannel->connectKey.size()) {
767        WRITE_LOG(LOG_FATAL, "connectKey.size 0 channelId:%u", hChannel->channelId);
768        return false;  // Operation of non-bound destination of scanning
769    }
770    if (hChannel->connectKey == CMDSTR_CONNECT_ANY) {
771        HDaemonInfo hdiOld = nullptr;
772        ptrServer->AdminDaemonMap(OP_GET_ONLY, "", hdiOld);
773        if (!hdiOld) {
774            WRITE_LOG(LOG_WARN, "No any key found channelId:%u", hChannel->channelId);
775            return false;
776        }
777        if (!hdiOld->hSession) {
778            WRITE_LOG(LOG_WARN, "hSession is null. channelId:%u", hChannel->channelId);
779            return false;
780        }
781        if (!hdiOld->hSession->handshakeOK) {
782            WRITE_LOG(LOG_WARN, "hSession handShake is false SessionId:%u", hdiOld->hSession->sessionId);
783            return false;
784        }
785        hChannel->connectKey = hdiOld->connectKey;
786        return true;
787    }
788    return true;
789}
790
791int HdcServerForClient::ChannelHandShake(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
792{
793    vector<uint8_t> rebuildHandshake;
794    rebuildHandshake.insert(rebuildHandshake.end(), bufPtr, bufPtr + bytesIO);
795    rebuildHandshake.push_back(0x00);
796    struct ChannelHandShake *handShake = reinterpret_cast<struct ChannelHandShake *>(rebuildHandshake.data());
797    if (strncmp(handShake->banner, HANDSHAKE_MESSAGE.c_str(), HANDSHAKE_MESSAGE.size())) {
798        hChannel->availTailIndex = 0;
799        WRITE_LOG(LOG_DEBUG, "Channel Hello failed");
800        return ERR_HANDSHAKE_NOTMATCH;
801    }
802    if (strlen(handShake->connectKey) > sizeof(handShake->connectKey)) {
803        hChannel->availTailIndex = 0;
804        WRITE_LOG(LOG_DEBUG, "Connectkey's size incorrect");
805        return ERR_HANDSHAKE_CONNECTKEY_FAILED;
806    }
807    // channel handshake step3
808    WRITE_LOG(LOG_DEBUG, "ServerForClient cid:%u sid:%u handshake finished",
809        hChannel->channelId, hChannel->targetSessionId);
810    hChannel->connectKey = handShake->connectKey;
811    hChannel->handshakeOK = true;
812    if (handShake->banner[WAIT_TAG_OFFSET] == WAIT_DEVICE_TAG || !CheckAutoFillTarget(hChannel)) {
813        WRITE_LOG(LOG_WARN, "No target channelId:%u", hChannel->channelId);
814        return 0;
815    }
816    // channel handshake stBindChannelToSession
817    if (BindChannelToSession(hChannel, nullptr, 0)) {
818        hChannel->availTailIndex = 0;
819        WRITE_LOG(LOG_FATAL, "BindChannelToSession failed channelId:%u sid:%u",
820            hChannel->channelId, hChannel->targetSessionId);
821        return ERR_GENERIC;
822    }
823    return 0;
824}
825
826void HdcServerForClient::ReportServerVersion(HChannel hChannel)
827{
828    string version = Base::GetVersion();
829    SendChannelWithCmd(hChannel, CMD_CHECK_SERVER,
830                       const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(version.c_str())),
831                       version.size());
832}
833
834// Here is Server to get data, the source is the SERVER's ChildWork to send data
835int HdcServerForClient::ReadChannel(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
836{
837    int ret = 0;
838    if (!hChannel->handshakeOK) {
839        return ChannelHandShake(hChannel, bufPtr, bytesIO);
840    }
841    HDaemonInfo hdi = nullptr;
842    HdcServer *ptrServer = (HdcServer *)clsServer;
843    ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi);
844    if (hdi && !hdi->emgmsg.empty()) {
845        EchoClient(hChannel, MSG_FAIL, hdi->emgmsg.c_str());
846        return ERR_GENERIC;
847    }
848    uint16_t command = *reinterpret_cast<uint16_t *>(bufPtr);
849    if (command != 0 && (hChannel->remote > RemoteType::REMOTE_NONE)) {
850        // server directly passthrough file command to daemon
851        if (!SendToDaemon(hChannel, command, bufPtr + sizeof(uint16_t), bytesIO - sizeof(uint16_t))) {
852            WRITE_LOG(LOG_FATAL, "Client ReadChannel : direct send to daemon failed");
853        }
854        return ret;
855    }
856    struct TranslateCommand::FormatCommand formatCommand = { 0 };
857    if (!hChannel->interactiveShellMode) {
858        string retEcho = String2FormatCommand(reinterpret_cast<char *>(bufPtr), bytesIO, &formatCommand);
859        if (retEcho.length()) {
860            if (!strncmp(reinterpret_cast<char *>(bufPtr), CMDSTR_SOFTWARE_HELP.c_str(),
861                CMDSTR_SOFTWARE_HELP.size()) ||
862                !strcmp(reinterpret_cast<char *>(bufPtr), CMDSTR_SOFTWARE_VERSION.c_str()) ||
863                !strcmp(reinterpret_cast<char *>(bufPtr), "flash")) {
864                EchoClient(hChannel, MSG_OK, retEcho.c_str());
865            } else {
866                EchoClient(hChannel, MSG_FAIL, retEcho.c_str());
867            }
868        }
869        WRITE_LOG(LOG_DEBUG, "ReadChannel cid:%u sid:%u key:%s command: %s",
870            hChannel->channelId, hChannel->targetSessionId, Hdc::MaskString(hChannel->connectKey).c_str(), bufPtr);
871        if (formatCommand.bJumpDo) {
872            WRITE_LOG(LOG_FATAL, "ReadChannel bJumpDo true");
873            return -10;  //  -10 error formatCommand
874        }
875    } else {
876        formatCommand.parameters = string(reinterpret_cast<char *>(bufPtr), bytesIO);
877        formatCommand.cmdFlag = CMD_SHELL_DATA;
878    }
879
880    if (!DoCommand(hChannel, &formatCommand)) {
881        return -3;  // -3: error or want close
882    }
883    ret = bytesIO;
884    return ret;
885};
886
887// avoid session dead
888HSession HdcServerForClient::FindAliveSession(uint32_t sessionId)
889{
890    HdcServer *ptrServer = (HdcServer *)clsServer;
891    HSession hSession = ptrServer->AdminSession(OP_QUERY, sessionId, nullptr);
892    if (!hSession || hSession->isDead) {
893        WRITE_LOG(LOG_FATAL, "FindAliveSession hSession nullptr or isDead sessionId:%u", sessionId);
894        return nullptr;
895    } else {
896        return hSession;
897    }
898}
899
900bool HdcServerForClient::ChannelSendSessionCtrlMsg(vector<uint8_t> &ctrlMsg, uint32_t sessionId)
901{
902    HSession hSession = FindAliveSession(sessionId);
903    if (!hSession) {
904        WRITE_LOG(LOG_FATAL, "ChannelSendSessionCtrlMsg hSession nullptr sessionId:%u", sessionId);
905        return false;
906    }
907    int rc = Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrlMsg.data(), ctrlMsg.size());
908    if (rc <= 0) {
909        WRITE_LOG(LOG_FATAL, "send ctrlmsg failed sessionId:%u rc:%d", sessionId, rc);
910    }
911    return rc > 0;
912}
913}  // namespace Hdc
914