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