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