• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "server_for_client.h"
16 
17 #include "flash_define.h"
18 #include "server.h"
19 
20 namespace Hdc {
HdcServerForClient(const bool serverOrClient,const string & addrString,void * pClsServer,uv_loop_t * loopMainIn)21 HdcServerForClient::HdcServerForClient(const bool serverOrClient, const string &addrString, void *pClsServer,
22                                        uv_loop_t *loopMainIn)
23     : HdcChannelBase(serverOrClient, addrString, loopMainIn)
24 {
25     clsServer = pClsServer;
26 }
27 
~HdcServerForClient()28 HdcServerForClient::~HdcServerForClient()
29 {
30     WRITE_LOG(LOG_DEBUG, "~HdcServerForClient");
31 }
32 
Stop()33 void HdcServerForClient::Stop()
34 {
35     Base::TryCloseHandle((uv_handle_t *)&tcpListen);
36 }
37 
GetTCPListenPort()38 uint16_t HdcServerForClient::GetTCPListenPort()
39 {
40     return channelPort;
41 }
42 
AcceptClient(uv_stream_t * server,int status)43 void HdcServerForClient::AcceptClient(uv_stream_t *server, int status)
44 {
45     uv_tcp_t *pServTCP = (uv_tcp_t *)server;
46     HdcServerForClient *thisClass = (HdcServerForClient *)pServTCP->data;
47     HChannel hChannel = nullptr;
48     uint32_t uid = thisClass->MallocChannel(&hChannel);
49     if (!hChannel) {
50         return;
51     }
52     if (uv_accept(server, (uv_stream_t *)&hChannel->hWorkTCP) < 0) {
53         thisClass->FreeChannel(uid);
54         return;
55     }
56     WRITE_LOG(LOG_DEBUG, "HdcServerForClient acceptClient");
57     // limit first recv
58     int bufMaxSize = 0;
59     uv_recv_buffer_size((uv_handle_t *)&hChannel->hWorkTCP, &bufMaxSize);
60     auto funcChannelHeaderAlloc = [](uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf) -> void {
61         HChannel context = (HChannel)handle->data;
62         Base::ReallocBuf(&context->ioBuf, &context->bufSize, context->availTailIndex, sizeWanted);
63         buf->base = (char *)context->ioBuf + context->availTailIndex;
64         buf->len = sizeof(struct ChannelHandShake) + DWORD_SERIALIZE_SIZE;  // only recv static size
65     };
66     // first packet static size, after this packet will be dup for normal recv
67     uv_read_start((uv_stream_t *)&hChannel->hWorkTCP, funcChannelHeaderAlloc, ReadStream);
68     // channel handshake step1
69     struct ChannelHandShake handShake;
70     Base::ZeroStruct(handShake);
71     if (EOK == strcpy_s(handShake.banner, sizeof(handShake.banner), HANDSHAKE_MESSAGE.c_str())) {
72         handShake.channelId = htonl(hChannel->channelId);
73         thisClass->Send(hChannel->channelId, (uint8_t *)&handShake, sizeof(struct ChannelHandShake));
74     }
75 }
76 
SetTCPListen()77 void HdcServerForClient::SetTCPListen()
78 {
79     tcpListen.data = this;
80     struct sockaddr_in addr;
81     uv_tcp_init(loopMain, &tcpListen);
82     uv_ip4_addr(channelHost.c_str(), channelPort, &addr);
83     uv_tcp_bind(&tcpListen, (const struct sockaddr *)&addr, 0);
84     uv_listen((uv_stream_t *)&tcpListen, 128, (uv_connection_cb)AcceptClient); // 128 client
85 }
86 
Initial()87 int HdcServerForClient::Initial()
88 {
89     if (!clsServer) {
90         WRITE_LOG(LOG_FATAL, "Module client initial failed");
91         return -1;
92     }
93     if (!channelHostPort.size() || !channelHost.size() || !channelPort) {
94         WRITE_LOG(LOG_FATAL, "Listen string initial failed");
95         return -2; // 2 error code
96     }
97     SetTCPListen();
98     return 0;
99 }
100 
EchoClient(HChannel hChannel,MessageLevel level,const char * msg,...)101 void HdcServerForClient::EchoClient(HChannel hChannel, MessageLevel level, const char *msg, ...)
102 {
103     string logInfo = "";
104     switch (level) {
105         case MSG_FAIL:
106             logInfo = MESSAGE_FAIL;
107             break;
108         case MSG_INFO:
109             logInfo = MESSAGE_INFO;
110             break;
111         default:  // successful, not append extra info
112             break;
113     }
114     va_list vaArgs;
115     va_start(vaArgs, msg);
116     string log = logInfo + Base::StringFormat(msg, vaArgs);
117     va_end(vaArgs);
118     if (log.back() != '\n') {
119         log += "\r\n";
120     }
121     Send(hChannel->channelId, (uint8_t *)log.c_str(), log.size());
122 }
123 
EchoClientRaw(const uint32_t channelId,uint8_t * payload,const int payloadSize)124 void HdcServerForClient::EchoClientRaw(const uint32_t channelId, uint8_t *payload, const int payloadSize)
125 {
126     Send(channelId, payload, payloadSize);
127 }
128 
SendToDaemon(HChannel hChannel,const uint16_t commandFlag,uint8_t * bufPtr,const int bufSize)129 bool HdcServerForClient::SendToDaemon(HChannel hChannel, const uint16_t commandFlag, uint8_t *bufPtr, const int bufSize)
130 {
131     HDaemonInfo hdi = nullptr;
132     bool ret = false;
133     HdcServer *ptrServer = (HdcServer *)clsServer;
134     while (true) {
135         ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi);
136         if (hdi == nullptr) {
137             break;
138         }
139         if (hdi->connStatus != STATUS_CONNECTED) {
140             break;
141         }
142         if (!hdi->hSession) {
143             break;
144         }
145         if (ptrServer->Send(hdi->hSession->sessionId, hChannel->channelId, commandFlag, bufPtr, bufSize) < 0) {
146             break;
147         }
148         ret = true;
149         break;
150     }
151     return ret;
152 }
153 
OrderFindTargets(HChannel hChannel)154 void HdcServerForClient::OrderFindTargets(HChannel hChannel)
155 {
156     int count = 0;
157     EchoClient(hChannel, MSG_INFO, "Please add HDC server's firewall ruler to allow udp incoming, udpport:%d",
158                DEFAULT_PORT);
159     HdcServer *ptrServer = (HdcServer *)clsServer;
160     ptrServer->clsTCPClt->FindLanDaemon();
161     list<string> &lst = ptrServer->clsTCPClt->lstDaemonResult;
162     // refresh main list
163     HdcDaemonInformation di;
164     while (!lst.empty()) {
165         Base::ZeroStruct(di);
166         ++count;
167         di.connectKey = lst.front();
168         di.connType = CONN_TCP;
169         di.connStatus = STATUS_READY;
170         HDaemonInfo pDi = (HDaemonInfo)&di;
171         ptrServer->AdminDaemonMap(OP_ADD, STRING_EMPTY, pDi);
172         lst.pop_front();
173     }
174     EchoClient(hChannel, MSG_INFO, "Broadcast find daemon, total:%d", count);
175 #ifdef UNIT_TEST
176     string bufString = std::to_string(count);
177     Base::WriteBinFile((UT_TMP_PATH + "/base-discover.result").c_str(), (uint8_t *)bufString.c_str(), bufString.size(),
178                        true);
179 #endif
180 }
181 
OrderConnecTargetResult(uv_timer_t * req)182 void HdcServerForClient::OrderConnecTargetResult(uv_timer_t *req)
183 {
184     HChannel hChannel = (HChannel)req->data;
185     HdcServerForClient *thisClass = (HdcServerForClient *)hChannel->clsChannel;
186     HdcServer *ptrServer = (HdcServer *)thisClass->clsServer;
187     bool bConnectOK = false;
188     bool bExitRepet = false;
189     HDaemonInfo hdi = nullptr;
190     string sRet;
191     string target = std::string(hChannel->bufStd + 2); // 2 len
192     if (target == "any") {
193         ptrServer->AdminDaemonMap(OP_GET_ANY, target, hdi);
194     } else {
195         ptrServer->AdminDaemonMap(OP_QUERY, target, hdi);
196     }
197     if (hdi && STATUS_CONNECTED == hdi->connStatus) {
198         bConnectOK = true;
199     }
200     while (true) {
201         if (bConnectOK) {
202             bExitRepet = true;
203             sRet = "Connect OK";
204             thisClass->EchoClient(hChannel, MSG_OK, (char *)sRet.c_str());
205             break;
206         } else {
207             uint16_t *bRetryCount = (uint16_t *)hChannel->bufStd;
208             ++(*bRetryCount);
209             if (*bRetryCount > 500) { // 500 ms
210                 bExitRepet = true;
211                 sRet = "Connect failed";
212                 thisClass->EchoClient(hChannel, MSG_FAIL, (char *)sRet.c_str());
213                 break;
214             }
215         }
216         break;
217     }
218     if (bExitRepet) {
219         thisClass->FreeChannel(hChannel->channelId);
220         Base::TryCloseHandle((const uv_handle_t *)req, Base::CloseTimerCallback);
221     }
222 }
223 
NewConnectTry(void * ptrServer,HChannel hChannel,const string & connectKey)224 bool HdcServerForClient::NewConnectTry(void *ptrServer, HChannel hChannel, const string &connectKey)
225 {
226     int childRet = ((HdcServer *)ptrServer)->CreateConnect(connectKey);
227     bool ret = false;
228     if (-1 == childRet) {
229         EchoClient(hChannel, MSG_INFO, "Target is connected, repeat operation");
230     } else if (-2 == childRet) { // 2 error code
231         EchoClient(hChannel, MSG_FAIL, "CreateConnect failed");
232         WRITE_LOG(LOG_FATAL, "CreateConnect failed");
233     } else {
234         Base::ZeroBuf(hChannel->bufStd, 2); // 2 len
235         childRet = snprintf_s(hChannel->bufStd + 2, sizeof(hChannel->bufStd) - 2, // 2 len
236             sizeof(hChannel->bufStd) - 3, "%s", (char *)connectKey.c_str()); // 3 len
237         if (childRet > 0) {
238             Base::TimerUvTask(loopMain, hChannel, OrderConnecTargetResult, 10); // 10 repeat
239             ret = true;
240         }
241     }
242     return ret;
243 }
244 
CommandRemoveSession(HChannel hChannel,const char * connectKey)245 bool HdcServerForClient::CommandRemoveSession(HChannel hChannel, const char *connectKey)
246 {
247     HdcServer *ptrServer = (HdcServer *)clsServer;
248     HDaemonInfo hdiOld = nullptr;
249     ((HdcServer *)ptrServer)->AdminDaemonMap(OP_QUERY, connectKey, hdiOld);
250     if (!hdiOld) {
251         EchoClient(hChannel, MSG_FAIL, "No target available");
252         return false;
253     }
254     ((HdcServer *)ptrServer)->FreeSession(hdiOld->hSession->sessionId);
255     return true;
256 }
257 
CommandRemoveForward(const string & forwardKey)258 bool HdcServerForClient::CommandRemoveForward(const string &forwardKey)
259 {
260     HdcServer *ptrServer = (HdcServer *)clsServer;
261     HForwardInfo hfi = nullptr;
262     ptrServer->AdminForwardMap(OP_QUERY, forwardKey, hfi);
263     if (!hfi) {
264         return false;
265     }
266     HSession hSession = ptrServer->AdminSession(OP_QUERY, hfi->sessionId, nullptr);
267     if (!hSession) {
268         return false;
269     }
270     ptrServer->ClearOwnTasks(hSession, hfi->channelId);
271     FreeChannel(hfi->channelId);
272     hfi = nullptr;
273     ptrServer->AdminForwardMap(OP_REMOVE, forwardKey, hfi);
274     return true;
275 }
276 
GetTargetList(HChannel hChannel,void * formatCommandInput)277 void HdcServerForClient::GetTargetList(HChannel hChannel, void *formatCommandInput)
278 {
279     TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
280     HdcServer *ptrServer = (HdcServer *)clsServer;
281     uint16_t cmd = OP_GET_STRLIST;
282     if (formatCommand->parameters == "v") {
283         cmd = OP_GET_STRLIST_FULL;
284     }
285     HDaemonInfo hdi = nullptr;
286     string sRet = ptrServer->AdminDaemonMap(cmd, STRING_EMPTY, hdi);
287     if (!sRet.length()) {
288         sRet = EMPTY_ECHO;
289     }
290     EchoClient(hChannel, MSG_OK, (char *)sRet.c_str());
291 #ifdef UNIT_TEST
292     Base::WriteBinFile((UT_TMP_PATH + "/base-list.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(),
293                        MESSAGE_SUCCESS.size(), true);
294 #endif
295 }
296 
GetAnyTarget(HChannel hChannel)297 bool HdcServerForClient::GetAnyTarget(HChannel hChannel)
298 {
299     HdcServer *ptrServer = (HdcServer *)clsServer;
300     HDaemonInfo hdi = nullptr;
301     ptrServer->AdminDaemonMap(OP_GET_ANY, STRING_EMPTY, hdi);
302     if (!hdi) {
303         EchoClient(hChannel, MSG_FAIL, "No target available");
304         return false;
305     }
306     // can not use hdi->connectKey.This memory may be released to re-Malloc
307     string connectKey = hdi->connectKey;
308     bool ret = NewConnectTry(ptrServer, hChannel, connectKey);
309 #ifdef UNIT_TEST
310     Base::WriteBinFile((UT_TMP_PATH + "/base-any.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(),
311                        MESSAGE_SUCCESS.size(), true);
312 #endif
313     return ret;
314 }
315 
RemoveForward(HChannel hChannel,const char * parameterString)316 bool HdcServerForClient::RemoveForward(HChannel hChannel, const char *parameterString)
317 {
318     HdcServer *ptrServer = (HdcServer *)clsServer;
319     if (parameterString == nullptr) {  // remove all
320         HForwardInfo hfi = nullptr;    // dummy
321         string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST, "", hfi);
322         if (!echo.length()) {
323             return false;
324         }
325         vector<string> filterStrings;
326         Base::SplitString(echo, string("\n"), filterStrings);
327         for (auto &&s : filterStrings) {
328             if (!CommandRemoveForward(s.c_str())) {
329                 EchoClient(hChannel, MSG_FAIL, "Remove forward ruler failed,ruler:%s", s.c_str());
330             }
331         }
332     } else {  // remove single
333         if (!CommandRemoveForward(parameterString)) {
334             EchoClient(hChannel, MSG_FAIL, "Remove forward ruler failed,ruler:%s", parameterString);
335         }
336     }
337     return true;
338 }
339 
DoCommandLocal(HChannel hChannel,void * formatCommandInput)340 bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandInput)
341 {
342     TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
343     HdcServer *ptrServer = (HdcServer *)clsServer;
344     const char *parameterString = formatCommand->parameters.c_str();
345     bool ret = false;
346     // Main thread command, direct Listen main thread
347     switch (formatCommand->cmdFlag) {
348         case CMD_KERNEL_TARGET_DISCOVER: {
349             OrderFindTargets(hChannel);
350             ret = false;
351             break;
352         }
353         case CMD_KERNEL_TARGET_LIST: {
354             GetTargetList(hChannel, formatCommandInput);
355             ret = false;
356             break;
357         }
358         case CMD_KERNEL_TARGET_ANY: {
359             ret = GetAnyTarget(hChannel);
360             break;
361         }
362         case CMD_KERNEL_TARGET_CONNECT: {
363             ret = NewConnectTry(ptrServer, hChannel, parameterString);
364             break;
365         }
366         case CMD_KERNEL_TARGET_DISCONNECT: {
367             CommandRemoveSession(hChannel, parameterString);
368             break;
369         }
370         case CMD_KERNEL_SERVER_KILL: {
371             WRITE_LOG(LOG_DEBUG, "Recv server kill command");
372             uv_stop(loopMain);
373             ret = true;
374             break;
375         }
376         // task will be global task,Therefore, it can only be controlled in the global session.
377         case CMD_FORWARD_LIST: {
378             HForwardInfo hfi = nullptr;  // dummy
379             string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST_FULL, "", hfi);
380             if (!echo.length()) {
381                 echo = EMPTY_ECHO;
382             }
383             EchoClient(hChannel, MSG_OK, (char *)echo.c_str());
384             break;
385         }
386         case CMD_FORWARD_REMOVE: {
387             RemoveForward(hChannel, parameterString);
388             break;
389         }
390         case CMD_KERNEL_ENABLE_KEEPALIVE: {
391             // just use for 'list targets' now
392             hChannel->keepAlive = true;
393             ret = true;
394             break;
395         }
396         default: {
397             EchoClient(hChannel, MSG_FAIL, "ExecuteCommand need connect-key?");
398             break;
399         }
400     }
401     return ret;
402 }
403 
TaskCommand(HChannel hChannel,void * formatCommandInput)404 bool HdcServerForClient::TaskCommand(HChannel hChannel, void *formatCommandInput)
405 {
406     TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
407     HdcServer *ptrServer = (HdcServer *)clsServer;
408     int sizeSend = formatCommand->parameters.size();
409     string cmdFlag;
410     uint8_t sizeCmdFlag = 0;
411     if (CMD_FILE_INIT == formatCommand->cmdFlag) {
412         cmdFlag = "send ";
413         sizeCmdFlag = 5;  // 5: cmdFlag send size
414     } else if (CMD_FORWARD_INIT == formatCommand->cmdFlag) {
415         cmdFlag = "fport ";
416         sizeCmdFlag = 6;  // 6: cmdFlag fport size
417     } else if (CMD_APP_INIT == formatCommand->cmdFlag) {
418         cmdFlag = "install ";
419         sizeCmdFlag = 8;  // 8: cmdFlag install size
420     } else if (CMD_APP_UNINSTALL == formatCommand->cmdFlag) {
421         cmdFlag = "uninstall ";
422         sizeCmdFlag = 10;  // 10: cmdFlag uninstall size
423     } else if (CMD_UNITY_BUGREPORT_INIT == formatCommand->cmdFlag) {
424         cmdFlag = "bugreport ";
425         sizeCmdFlag = 10;  // 10: cmdFlag bugreport size
426     } else if (CMD_APP_SIDELOAD == formatCommand->cmdFlag) {
427         cmdFlag = "sideload ";
428         sizeCmdFlag = 9; // 9: cmdFlag sideload size
429     } else if (CMD_UPDATER_UPDATE_INIT == formatCommand->cmdFlag) {
430         cmdFlag = "update ";
431         sizeCmdFlag = 7; // 7: cmdFlag update size
432     } else if (CMD_UPDATER_FLASH_INIT == formatCommand->cmdFlag) {
433         cmdFlag = "flash ";
434         sizeCmdFlag = 6; // 6: cmdFlag flash size
435     }
436     uint8_t *payload = reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag;
437     if (!strncmp(formatCommand->parameters.c_str(), cmdFlag.c_str(), sizeCmdFlag)) {  // local do
438         HSession hSession = FindAliveSession(hChannel->targetSessionId);
439         if (!hSession) {
440             return false;
441         }
442         ptrServer->DispatchTaskData(hSession, hChannel->channelId, formatCommand->cmdFlag, payload,
443                                     sizeSend - sizeCmdFlag);
444     } else {  // Send to Daemon-side to do
445         SendToDaemon(hChannel, formatCommand->cmdFlag, payload, sizeSend - sizeCmdFlag);
446     }
447     return true;
448 }
449 
DoCommandRemote(HChannel hChannel,void * formatCommandInput)450 bool HdcServerForClient::DoCommandRemote(HChannel hChannel, void *formatCommandInput)
451 {
452     TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
453     bool ret = false;
454     int sizeSend = formatCommand->parameters.size();
455     string cmdFlag;
456     switch (formatCommand->cmdFlag) {
457         // Some simple commands only need to forward the instruction, no need to start Task
458         case CMD_SHELL_INIT:
459         case CMD_SHELL_DATA:
460         case CMD_UNITY_EXECUTE:
461         case CMD_UNITY_TERMINATE:
462         case CMD_UNITY_REMOUNT:
463         case CMD_UNITY_REBOOT:
464         case CMD_UNITY_RUNMODE:
465         case CMD_UNITY_HILOG:
466         case CMD_UNITY_ROOTRUN:
467         case CMD_UNITY_JPID: {
468             if (!SendToDaemon(hChannel, formatCommand->cmdFlag,
469                 reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())), sizeSend)) {
470                 break;
471             }
472             ret = true;
473             if (CMD_SHELL_INIT == formatCommand->cmdFlag) {
474                 hChannel->interactiveShellMode = true;
475             }
476             break;
477         }
478         case CMD_FILE_INIT:
479         case CMD_FORWARD_INIT:
480         case CMD_APP_INIT:
481         case CMD_APP_UNINSTALL:
482         case CMD_UNITY_BUGREPORT_INIT:
483         case CMD_APP_SIDELOAD:
484         case CMD_UPDATER_UPDATE_INIT:
485         case CMD_UPDATER_FLASH_INIT:
486         case CMD_UPDATER_ERASE:
487         case CMD_UPDATER_FORMAT: {
488             TaskCommand(hChannel, formatCommandInput);
489             ret = true;
490             break;
491         }
492         default:
493             break;
494     }
495     if (!ret) {
496         EchoClient(hChannel, MSG_FAIL, "Failed to communicate with daemon");
497     }
498     return ret;
499 }
500 // Do not specify Target's operations no longer need to put it in the thread.
DoCommand(HChannel hChannel,void * formatCommandInput)501 bool HdcServerForClient::DoCommand(HChannel hChannel, void *formatCommandInput)
502 {
503     bool ret = false;
504     if (!hChannel->hChildWorkTCP.loop) {
505         // Main thread command, direct Listen main thread
506         ret = DoCommandLocal(hChannel, formatCommandInput);
507     } else {  // CONNECT DAEMON's work thread command, non-primary thread
508         ret = DoCommandRemote(hChannel, formatCommandInput);
509     }
510     return ret;
511 }
512 
513 // just call from BindChannelToSession
FindAliveSessionFromDaemonMap(const HChannel hChannel)514 HSession HdcServerForClient::FindAliveSessionFromDaemonMap(const HChannel hChannel)
515 {
516     HSession hSession = nullptr;
517     HDaemonInfo hdi = nullptr;
518     HdcServer *ptrServer = (HdcServer *)clsServer;
519     ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi);
520     if (!hdi) {
521         EchoClient(hChannel, MSG_FAIL, "Not match target founded, check connect-key please");
522         return nullptr;
523     }
524     if (hdi->connStatus != STATUS_CONNECTED) {
525         EchoClient(hChannel, MSG_FAIL, "Device not founded or connected");
526         return nullptr;
527     }
528     if (hdi->hSession->isDead) {
529         EchoClient(hChannel, MSG_FAIL, "Bind tartget session is dead");
530         return nullptr;
531     }
532     hSession = (HSession)hdi->hSession;
533     return hSession;
534 }
535 
BindChannelToSession(HChannel hChannel,uint8_t * bufPtr,const int bytesIO)536 int HdcServerForClient::BindChannelToSession(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
537 {
538     HSession hSession = nullptr;
539     if ((hSession = FindAliveSessionFromDaemonMap(hChannel)) == nullptr) {
540         return ERR_SESSION_NOFOUND;
541     }
542     bool isClosing = uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP);
543     if (!isClosing && (hChannel->fdChildWorkTCP = Base::DuplicateUvSocket(&hChannel->hWorkTCP)) < 0) {
544         WRITE_LOG(LOG_FATAL, "Duplicate socket failed, cid:%d", hChannel->channelId);
545         return ERR_SOCKET_DUPLICATE;
546     }
547     uv_close_cb funcWorkTcpClose = [](uv_handle_t *handle) -> void {
548         HChannel hChannel = (HChannel)handle->data;
549         --hChannel->sendRef;
550     };
551     ++hChannel->sendRef;
552     if (!isClosing) {
553         uv_close((uv_handle_t *)&hChannel->hWorkTCP, funcWorkTcpClose);
554     }
555     Base::DoNextLoop(loopMain, hChannel, [](const uint8_t flag, string &msg, const void *data) {
556         // Thread message can avoid using thread lock and improve program efficiency
557         // If not next loop call, ReadStream will thread conflict
558         HChannel hChannel = (HChannel)data;
559         auto thisClass = (HdcServerForClient *)hChannel->clsChannel;
560         HSession hSession = nullptr;
561         if ((hSession = thisClass->FindAliveSessionFromDaemonMap(hChannel)) == nullptr) {
562             return;
563         }
564         auto ctrl = HdcSessionBase::BuildCtrlString(SP_ATTACH_CHANNEL, hChannel->channelId, nullptr, 0);
565         Base::SendToStream((uv_stream_t *)&hSession->ctrlPipe[STREAM_MAIN], ctrl.data(), ctrl.size());
566     });
567     return RET_SUCCESS;
568 }
569 
CheckAutoFillTarget(HChannel hChannel)570 bool HdcServerForClient::CheckAutoFillTarget(HChannel hChannel)
571 {
572     HdcServer *ptrServer = (HdcServer *)clsServer;
573     if (!hChannel->connectKey.size()) {
574         return false;  // Operation of non-bound destination of scanning
575     }
576     if (hChannel->connectKey == CMDSTR_CONNECT_ANY) {
577         HDaemonInfo hdiOld = nullptr;
578         ptrServer->AdminDaemonMap(OP_GET_ONLY, "", hdiOld);
579         if (!hdiOld) {
580             return false;
581         }
582         hChannel->connectKey = hdiOld->connectKey;
583         return true;
584     }
585     return true;
586 }
587 
ChannelHandShake(HChannel hChannel,uint8_t * bufPtr,const int bytesIO)588 int HdcServerForClient::ChannelHandShake(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
589 {
590     vector<uint8_t> rebuildHandshake;
591     rebuildHandshake.insert(rebuildHandshake.end(), bufPtr, bufPtr + bytesIO);
592     rebuildHandshake.push_back(0x00);
593     struct ChannelHandShake *handShake = reinterpret_cast<struct ChannelHandShake *>(rebuildHandshake.data());
594     if (strncmp(handShake->banner, HANDSHAKE_MESSAGE.c_str(), HANDSHAKE_MESSAGE.size())) {
595         hChannel->availTailIndex = 0;
596         WRITE_LOG(LOG_DEBUG, "Channel Hello failed");
597         return ERR_HANDSHAKE_NOTMATCH;
598     }
599     if (strlen(handShake->connectKey) > sizeof(handShake->connectKey)) {
600         hChannel->availTailIndex = 0;
601         WRITE_LOG(LOG_DEBUG, "Connectkey's size incorrect");
602         return ERR_HANDSHAKE_CONNECTKEY_FAILED;
603     }
604     // channel handshake step3
605     WRITE_LOG(LOG_DEBUG, "ServerForClient channel handshake finished");
606     hChannel->connectKey = handShake->connectKey;
607     hChannel->handshakeOK = true;
608     if (!CheckAutoFillTarget(hChannel)) {
609         return 0;
610     }
611     // channel handshake stBindChannelToSession
612     if (BindChannelToSession(hChannel, nullptr, 0)) {
613         hChannel->availTailIndex = 0;
614         WRITE_LOG(LOG_FATAL, "BindChannelToSession failed");
615         return ERR_GENERIC;
616     }
617     return 0;
618 }
619 
620 // Here is Server to get data, the source is the SERVER's ChildWork to send data
ReadChannel(HChannel hChannel,uint8_t * bufPtr,const int bytesIO)621 int HdcServerForClient::ReadChannel(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
622 {
623     int ret = 0;
624     if (!hChannel->handshakeOK) {
625         return ChannelHandShake(hChannel, bufPtr, bytesIO);
626     }
627     struct TranslateCommand::FormatCommand formatCommand = { 0 };
628     if (!hChannel->interactiveShellMode) {
629         string retEcho = String2FormatCommand((char *)bufPtr, bytesIO, &formatCommand);
630         if (retEcho.length()) {
631             if (!strcmp((char *)bufPtr, CMDSTR_SOFTWARE_HELP.c_str()) ||
632                 !strcmp((char *)bufPtr, CMDSTR_SOFTWARE_VERSION.c_str()) ||
633                 !strcmp((char *)bufPtr, "flash")) {
634                 EchoClient(hChannel, MSG_OK, retEcho.c_str());
635             } else {
636                 EchoClient(hChannel, MSG_FAIL, retEcho.c_str());
637             }
638         }
639         if (formatCommand.bJumpDo) {
640             ret = -10; // 10 error code
641             return ret;
642         }
643     } else {
644         formatCommand.parameters = string(reinterpret_cast<char *>(bufPtr), bytesIO);
645         formatCommand.cmdFlag = CMD_SHELL_DATA;
646     }
647     if (!DoCommand(hChannel, &formatCommand)) {
648         return -3;  // -3: error or want close
649     }
650     ret = bytesIO;
651     return ret;
652 };
653 
654 // avoid session dead
FindAliveSession(uint32_t sessionId)655 HSession HdcServerForClient::FindAliveSession(uint32_t sessionId)
656 {
657     HdcServer *ptrServer = (HdcServer *)clsServer;
658     HSession hSession = ptrServer->AdminSession(OP_QUERY, sessionId, nullptr);
659     if (!hSession || hSession->isDead) {
660         return nullptr;
661     } else {
662         return hSession;
663     }
664 }
665 
ChannelSendSessionCtrlMsg(vector<uint8_t> & ctrlMsg,uint32_t sessionId)666 bool HdcServerForClient::ChannelSendSessionCtrlMsg(vector<uint8_t> &ctrlMsg, uint32_t sessionId)
667 {
668     HSession hSession = FindAliveSession(sessionId);
669     if (!hSession) {
670         return false;
671     }
672     return Base::SendToStream((uv_stream_t *)&hSession->ctrlPipe[STREAM_MAIN], ctrlMsg.data(), ctrlMsg.size()) > 0;
673 }
674 }  // namespace Hdc
675