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