• 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;
156     }
157     bool b = SetTCPListen();
158     if (!b) {
159         WRITE_LOG(LOG_FATAL, "SetTCPListen failed");
160         int listenError = -3;
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     if (childRet == -1) {
317         EchoClient(hChannel, MSG_INFO, "Target is connected, repeat operation");
318     } else if (childRet == connectError) {
319         EchoClient(hChannel, MSG_FAIL, "CreateConnect failed");
320         WRITE_LOG(LOG_FATAL, "CreateConnect failed");
321     } else {
322         size_t pos = connectKey.find(":");
323         if (pos != std::string::npos) {
324             string ip = connectKey.substr(0, pos);
325             if (ip == "127.0.0.1") {
326                 hChannel->connectLocalDevice = true;
327             }
328         }
329         Base::ZeroBuf(hChannel->bufStd, 2);
330         childRet = snprintf_s(hChannel->bufStd + 2, sizeof(hChannel->bufStd) - 2, sizeof(hChannel->bufStd) - 3, "%s",
331                               const_cast<char *>(connectKey.c_str()));
332         if (childRet > 0) {
333             Base::TimerUvTask(loopMain, hChannel, OrderConnecTargetResult, 10);
334             ret = true;
335         }
336     }
337     return ret;
338 }
339 
CommandRemoveSession(HChannel hChannel,const char * connectKey)340 bool HdcServerForClient::CommandRemoveSession(HChannel hChannel, const char *connectKey)
341 {
342     HdcServer *ptrServer = (HdcServer *)clsServer;
343     HDaemonInfo hdiOld = nullptr;
344     (reinterpret_cast<HdcServer *>(ptrServer))->AdminDaemonMap(OP_QUERY, connectKey, hdiOld);
345     if (!hdiOld) {
346         EchoClient(hChannel, MSG_FAIL, "No target available");
347         return false;
348     }
349     (reinterpret_cast<HdcServer *>(ptrServer))->FreeSession(hdiOld->hSession->sessionId);
350     return true;
351 }
352 
CommandRemoveForward(const string & forwardKey)353 bool HdcServerForClient::CommandRemoveForward(const string &forwardKey)
354 {
355     HdcServer *ptrServer = (HdcServer *)clsServer;
356     HForwardInfo hfi = nullptr;
357     ptrServer->AdminForwardMap(OP_QUERY, forwardKey, hfi);
358     if (!hfi) {
359         WRITE_LOG(LOG_FATAL, "CommandRemoveForward hfi nullptr forwardKey:%s", forwardKey.c_str());
360         return false;
361     }
362     HSession hSession = ptrServer->AdminSession(OP_QUERY, hfi->sessionId, nullptr);
363     if (!hSession) {
364         WRITE_LOG(LOG_FATAL, "CommandRemoveForward hSession nullptr sessionId:%u", hfi->sessionId);
365         ptrServer->AdminForwardMap(OP_REMOVE, forwardKey, hfi);
366         return true;
367     }
368     ptrServer->ClearOwnTasks(hSession, hfi->channelId);
369     FreeChannel(hfi->channelId);
370     hfi = nullptr;
371     ptrServer->AdminForwardMap(OP_REMOVE, forwardKey, hfi);
372     return true;
373 }
374 
GetTargetList(HChannel hChannel,void * formatCommandInput)375 void HdcServerForClient::GetTargetList(HChannel hChannel, void *formatCommandInput)
376 {
377     TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
378     HdcServer *ptrServer = (HdcServer *)clsServer;
379     uint16_t cmd = OP_GET_STRLIST;
380     if (formatCommand->parameters == "v") {
381         cmd = OP_GET_STRLIST_FULL;
382     }
383     HDaemonInfo hdi = nullptr;
384     string sRet = ptrServer->AdminDaemonMap(cmd, STRING_EMPTY, hdi);
385     if (!sRet.length()) {
386         sRet = EMPTY_ECHO;
387     }
388     EchoClient(hChannel, MSG_OK, const_cast<char *>(sRet.c_str()));
389 #ifdef UNIT_TEST
390     Base::WriteBinFile((UT_TMP_PATH + "/base-list.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(),
391                        MESSAGE_SUCCESS.size(), true);
392 #endif
393 }
394 
GetAnyTarget(HChannel hChannel)395 bool HdcServerForClient::GetAnyTarget(HChannel hChannel)
396 {
397     HdcServer *ptrServer = (HdcServer *)clsServer;
398     HDaemonInfo hdi = nullptr;
399     ptrServer->AdminDaemonMap(OP_GET_ANY, STRING_EMPTY, hdi);
400     if (!hdi) {
401         EchoClient(hChannel, MSG_FAIL, "No target available");
402         return false;
403     }
404     // can not use hdi->connectKey.This memory may be released to re-Malloc
405     string connectKey = hdi->connectKey;
406     bool ret = NewConnectTry(ptrServer, hChannel, connectKey);
407 #ifdef UNIT_TEST
408     Base::WriteBinFile((UT_TMP_PATH + "/base-any.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(),
409                        MESSAGE_SUCCESS.size(), true);
410 #endif
411     return ret;
412 }
413 
WaitForAny(HChannel hChannel)414 bool HdcServerForClient::WaitForAny(HChannel hChannel)
415 {
416     HdcServer *ptrServer = (HdcServer *)clsServer;
417     HDaemonInfo hdi = nullptr;
418     ptrServer->AdminDaemonMap(OP_WAIT_FOR_ANY, STRING_EMPTY, hdi);
419     if (!hdi) {
420         EchoClient(hChannel, MSG_FAIL, "No any connected target");
421         return false;
422     }
423     string key = hdi->connectKey;
424     EchoClient(hChannel, MSG_OK, "Wait for connected target is %s", key.c_str());
425     return true;
426 }
427 
RemoveForward(HChannel hChannel,const char * parameterString)428 bool HdcServerForClient::RemoveForward(HChannel hChannel, const char *parameterString)
429 {
430     HdcServer *ptrServer = (HdcServer *)clsServer;
431     if (parameterString == nullptr) {  // remove all
432         HForwardInfo hfi = nullptr;    // dummy
433         string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST, "", hfi);
434         if (!echo.length()) {
435             return false;
436         }
437         vector<string> filterStrings;
438         Base::SplitString(echo, string("\n"), filterStrings);
439         for (auto &&s : filterStrings) {
440             if (CommandRemoveForward(s.c_str())) {
441                 EchoClient(hChannel, MSG_OK, "Remove forward ruler success, ruler:%s", s.c_str());
442             } else {
443                 EchoClient(hChannel, MSG_FAIL, "Remove forward ruler failed, ruler is not exist %s", s.c_str());
444             }
445         }
446     } else {  // remove single
447         if (CommandRemoveForward(parameterString)) {
448             EchoClient(hChannel, MSG_OK, "Remove forward ruler success, ruler:%s", parameterString);
449         } else {
450             EchoClient(hChannel, MSG_FAIL, "Remove forward ruler failed, ruler is not exist %s", parameterString);
451         }
452     }
453     return true;
454 }
455 
DoCommandLocal(HChannel hChannel,void * formatCommandInput)456 bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandInput)
457 {
458     TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
459     HdcServer *ptrServer = (HdcServer *)clsServer;
460     bool ret = false;
461     // Main thread command, direct Listen main thread
462     switch (formatCommand->cmdFlag) {
463         case CMD_KERNEL_TARGET_DISCOVER: {
464             OrderFindTargets(hChannel);
465             ret = false;
466             break;
467         }
468         case CMD_KERNEL_TARGET_LIST: {
469             GetTargetList(hChannel, formatCommandInput);
470             ret = false;
471             break;
472         }
473         case CMD_CHECK_SERVER: {
474             WRITE_LOG(LOG_DEBUG, "CMD_CHECK_SERVER command");
475             ReportServerVersion(hChannel);
476             ret = false;
477             break;
478         }
479         case CMD_WAIT_FOR: {
480             WRITE_LOG(LOG_DEBUG, "CMD_WAIT_FOR command");
481             ret = !WaitForAny(hChannel);
482             break;
483         }
484         case CMD_KERNEL_TARGET_ANY: {
485 #ifdef HDC_DEBUG
486             WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_ANY %s", __FUNCTION__, formatCommand->parameters.c_str());
487 #endif
488             ret = GetAnyTarget(hChannel);
489             break;
490         }
491         case CMD_KERNEL_TARGET_CONNECT: {
492 #ifdef HDC_DEBUG
493             WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_CONNECT %s", __FUNCTION__, formatCommand->parameters.c_str());
494 #endif
495             ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str());
496             break;
497         }
498         case CMD_CHECK_DEVICE: {
499             WRITE_LOG(LOG_INFO, "%s CMD_CHECK_DEVICE %s", __FUNCTION__, formatCommand->parameters.c_str());
500             hChannel->isCheck = true;
501             hChannel->key = formatCommand->parameters.c_str();
502             ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str(), true);
503             break;
504         }
505         case CMD_KERNEL_TARGET_DISCONNECT: {
506             CommandRemoveSession(hChannel, formatCommand->parameters.c_str());
507             break;
508         }
509         case CMD_KERNEL_SERVER_KILL: {
510             WRITE_LOG(LOG_DEBUG, "Recv server kill command");
511             uv_stop(loopMain);
512             ret = true;
513             break;
514         }
515         // task will be global task,Therefore, it can only be controlled in the global session.
516         case CMD_FORWARD_LIST: {
517             HForwardInfo hfi = nullptr;  // dummy
518             string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST_FULL, "", hfi);
519             if (!echo.length()) {
520                 echo = EMPTY_ECHO;
521             }
522             EchoClient(hChannel, MSG_OK, const_cast<char *>(echo.c_str()));
523             break;
524         }
525         case CMD_FORWARD_REMOVE: {
526             RemoveForward(hChannel, formatCommand->parameters.c_str());
527             break;
528         }
529         case CMD_KERNEL_ENABLE_KEEPALIVE: {
530             // just use for 'list targets' now
531             hChannel->keepAlive = true;
532             ret = true;
533             break;
534         }
535         default: {
536             EchoClient(hChannel, MSG_FAIL, "ExecuteCommand need connect-key?");
537             break;
538         }
539     }
540     return ret;
541 }
542 
TaskCommand(HChannel hChannel,void * formatCommandInput)543 bool HdcServerForClient::TaskCommand(HChannel hChannel, void *formatCommandInput)
544 {
545     TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
546     HdcServer *ptrServer = (HdcServer *)clsServer;
547     string cmdFlag;
548     uint8_t sizeCmdFlag = 0;
549     if (formatCommand->cmdFlag == CMD_FILE_INIT) {
550         cmdFlag = "send ";
551         sizeCmdFlag = 5;  // 5: cmdFlag send size
552         HandleRemote(hChannel, formatCommand->parameters, RemoteType::REMOTE_FILE);
553     } else if (formatCommand->cmdFlag == CMD_FORWARD_INIT) {
554         cmdFlag = "fport ";
555         sizeCmdFlag = 6;  // 6: cmdFlag fport size
556     } else if (formatCommand->cmdFlag == CMD_APP_INIT) {
557         cmdFlag = "install ";
558         sizeCmdFlag = 8;  // 8: cmdFlag install size
559         HandleRemote(hChannel, formatCommand->parameters, RemoteType::REMOTE_APP);
560     } else if (formatCommand->cmdFlag == CMD_APP_UNINSTALL) {
561         cmdFlag = "uninstall ";
562         sizeCmdFlag = 10;  // 10: cmdFlag uninstall size
563     } else if (formatCommand->cmdFlag == CMD_UNITY_BUGREPORT_INIT) {
564         cmdFlag = "bugreport ";
565         sizeCmdFlag = 10;  // 10: cmdFlag bugreport size
566     } else if (formatCommand->cmdFlag == CMD_APP_SIDELOAD) {
567         cmdFlag = "sideload ";
568         sizeCmdFlag = 9; // 9: cmdFlag sideload size
569     } else if (formatCommand->cmdFlag == CMD_FLASHD_UPDATE_INIT) {
570         cmdFlag = "update ";
571         sizeCmdFlag = 7; // 7: cmdFlag update size
572     } else if (formatCommand->cmdFlag == CMD_FLASHD_FLASH_INIT) {
573         cmdFlag = "flash ";
574         sizeCmdFlag = 6; // 6: cmdFlag flash size
575     }
576     int sizeSend = formatCommand->parameters.size();
577     if (!strncmp(formatCommand->parameters.c_str(), cmdFlag.c_str(), sizeCmdFlag)) {  // local do
578         HSession hSession = FindAliveSession(hChannel->targetSessionId);
579         if (!hSession) {
580             return false;
581         }
582         if ((formatCommand->cmdFlag == CMD_FILE_INIT || formatCommand->cmdFlag == CMD_APP_INIT) &&
583             hChannel->fromClient) {
584             // remote client mode, CMD_FILE_INIT and CMD_APP_INIT command send back to client
585             WRITE_LOG(LOG_DEBUG, "command send back to remote client channelId:%u", hChannel->channelId);
586             SendChannelWithCmd(hChannel, formatCommand->cmdFlag,
587                 reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
588                 sizeSend - sizeCmdFlag);
589             return false;
590         }
591         ptrServer->DispatchTaskData(hSession, hChannel->channelId, formatCommand->cmdFlag,
592             reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
593             sizeSend - sizeCmdFlag);
594     } else {  // Send to Daemon-side to do
595         SendToDaemon(hChannel, formatCommand->cmdFlag,
596             reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
597             sizeSend - sizeCmdFlag);
598     }
599     return true;
600 }
601 
HandleRemote(HChannel hChannel,string & parameters,RemoteType flag)602 void HdcServerForClient::HandleRemote(HChannel hChannel, string &parameters, RemoteType flag)
603 {
604     hChannel->remote = flag;
605     int argc = 0;
606     char **argv = Base::SplitCommandToArgs(parameters.c_str(), &argc);
607     for (int i = 0; i < argc; i++) {
608         if (argv[i] == CMDSTR_REMOTE_PARAMETER) {
609             hChannel->fromClient = true;
610             WRITE_LOG(LOG_DEBUG, "remote client mode channelId:%u", hChannel->channelId);
611             break;
612         }
613     }
614     if (hChannel->fromClient) {
615         string remote = CMDSTR_REMOTE_PARAMETER + " ";
616         if (parameters.find(remote) != std::string::npos) {
617             parameters.replace(parameters.find(remote), remote.size(), "");
618             WRITE_LOG(LOG_DEBUG, "parameters: %s", parameters.c_str());
619         }
620     }
621 }
622 
DoCommandRemote(HChannel hChannel,void * formatCommandInput)623 bool HdcServerForClient::DoCommandRemote(HChannel hChannel, void *formatCommandInput)
624 {
625     TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
626     bool ret = false;
627     int sizeSend = formatCommand->parameters.size();
628     string cmdFlag;
629     switch (formatCommand->cmdFlag) {
630         // Some simple commands only need to forward the instruction, no need to start Task
631         case CMD_SHELL_INIT:
632         case CMD_SHELL_DATA:
633         case CMD_UNITY_EXECUTE:
634         case CMD_UNITY_TERMINATE:
635         case CMD_UNITY_REMOUNT:
636         case CMD_UNITY_REBOOT:
637         case CMD_UNITY_RUNMODE:
638         case CMD_UNITY_HILOG:
639         case CMD_UNITY_ROOTRUN:
640         case CMD_JDWP_TRACK:
641         case CMD_JDWP_LIST: {
642             if (!SendToDaemon(hChannel, formatCommand->cmdFlag,
643                               reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())),
644                               sizeSend)) {
645                 break;
646             }
647             ret = true;
648             if (formatCommand->cmdFlag == CMD_SHELL_INIT) {
649                 hChannel->interactiveShellMode = true;
650             }
651             break;
652         }
653         case CMD_FILE_INIT:
654         case CMD_FORWARD_INIT:
655         case CMD_APP_INIT:
656         case CMD_APP_UNINSTALL:
657         case CMD_UNITY_BUGREPORT_INIT:
658         case CMD_APP_SIDELOAD:
659         case CMD_FLASHD_UPDATE_INIT:
660         case CMD_FLASHD_FLASH_INIT:
661         case CMD_FLASHD_ERASE:
662         case CMD_FLASHD_FORMAT: {
663             TaskCommand(hChannel, formatCommandInput);
664             ret = true;
665             break;
666         }
667         default:
668             break;
669     }
670     if (!ret) {
671         EchoClient(hChannel, MSG_FAIL, "Failed to communicate with daemon");
672     }
673     return ret;
674 }
675 // Do not specify Target's operations no longer need to put it in the thread.
DoCommand(HChannel hChannel,void * formatCommandInput)676 bool HdcServerForClient::DoCommand(HChannel hChannel, void *formatCommandInput)
677 {
678     bool ret = false;
679     TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
680     if (!hChannel->hChildWorkTCP.loop || formatCommand->cmdFlag == CMD_FORWARD_REMOVE) {
681         // Main thread command, direct Listen main thread
682         ret = DoCommandLocal(hChannel, formatCommandInput);
683     } else {  // CONNECT DAEMON's work thread command, non-primary thread
684         ret = DoCommandRemote(hChannel, formatCommandInput);
685     }
686     return ret;
687 }
688 
689 // just call from BindChannelToSession
FindAliveSessionFromDaemonMap(const HChannel hChannel)690 HSession HdcServerForClient::FindAliveSessionFromDaemonMap(const HChannel hChannel)
691 {
692     HSession hSession = nullptr;
693     HDaemonInfo hdi = nullptr;
694     HdcServer *ptrServer = (HdcServer *)clsServer;
695     ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi);
696     if (!hdi) {
697         EchoClient(hChannel, MSG_FAIL, "Not match target founded, check connect-key please");
698         return nullptr;
699     }
700     if (hdi->connStatus != STATUS_CONNECTED) {
701         EchoClient(hChannel, MSG_FAIL, "Device not founded or connected");
702         return nullptr;
703     }
704     if (hdi->hSession->isDead) {
705         EchoClient(hChannel, MSG_FAIL, "Bind tartget session is dead");
706         return nullptr;
707     }
708     hSession = reinterpret_cast<HSession>(hdi->hSession);
709     return hSession;
710 }
711 
BindChannelToSession(HChannel hChannel,uint8_t * bufPtr,const int bytesIO)712 int HdcServerForClient::BindChannelToSession(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
713 {
714     if (FindAliveSessionFromDaemonMap(hChannel) == nullptr) {
715         WRITE_LOG(LOG_FATAL, "Find no alive session channelId:%u", hChannel->channelId);
716         return ERR_SESSION_NOFOUND;
717     }
718     bool isClosing = uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP);
719     if (!isClosing && (hChannel->fdChildWorkTCP = Base::DuplicateUvSocket(&hChannel->hWorkTCP)) < 0) {
720         WRITE_LOG(LOG_FATAL, "Duplicate socket failed channelId:%u", hChannel->channelId);
721         return ERR_SOCKET_DUPLICATE;
722     }
723     uv_close_cb funcWorkTcpClose = [](uv_handle_t *handle) -> void {
724         HChannel hChannel = (HChannel)handle->data;
725         --hChannel->ref;
726     };
727     ++hChannel->ref;
728     if (!isClosing) {
729         uv_close((uv_handle_t *)&hChannel->hWorkTCP, funcWorkTcpClose);
730     }
731     Base::DoNextLoop(loopMain, hChannel, [](const uint8_t flag, string &msg, const void *data) {
732         // Thread message can avoid using thread lock and improve program efficiency
733         // If not next loop call, ReadStream will thread conflict
734         HChannel hChannel = (HChannel)data;
735         auto thisClass = (HdcServerForClient *)hChannel->clsChannel;
736         HSession hSession = nullptr;
737         if ((hSession = thisClass->FindAliveSessionFromDaemonMap(hChannel)) == nullptr) {
738             WRITE_LOG(LOG_FATAL, "hSession nullptr channelId:%u", hChannel->channelId);
739             return;
740         }
741         auto ctrl = HdcSessionBase::BuildCtrlString(SP_ATTACH_CHANNEL, hChannel->channelId, nullptr, 0);
742         Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
743     });
744     return RET_SUCCESS;
745 }
746 
CheckAutoFillTarget(HChannel hChannel)747 bool HdcServerForClient::CheckAutoFillTarget(HChannel hChannel)
748 {
749     HdcServer *ptrServer = (HdcServer *)clsServer;
750     if (!hChannel->connectKey.size()) {
751         WRITE_LOG(LOG_FATAL, "connectKey.size 0 channelId:%u", hChannel->channelId);
752         return false;  // Operation of non-bound destination of scanning
753     }
754     if (hChannel->connectKey == CMDSTR_CONNECT_ANY) {
755         HDaemonInfo hdiOld = nullptr;
756         ptrServer->AdminDaemonMap(OP_GET_ONLY, "", hdiOld);
757         if (!hdiOld) {
758             WRITE_LOG(LOG_WARN, "No any key found channelId:%u", hChannel->channelId);
759             return false;
760         }
761         hChannel->connectKey = hdiOld->connectKey;
762         return true;
763     }
764     return true;
765 }
766 
ChannelHandShake(HChannel hChannel,uint8_t * bufPtr,const int bytesIO)767 int HdcServerForClient::ChannelHandShake(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
768 {
769     vector<uint8_t> rebuildHandshake;
770     rebuildHandshake.insert(rebuildHandshake.end(), bufPtr, bufPtr + bytesIO);
771     rebuildHandshake.push_back(0x00);
772     struct ChannelHandShake *handShake = reinterpret_cast<struct ChannelHandShake *>(rebuildHandshake.data());
773     if (strncmp(handShake->banner, HANDSHAKE_MESSAGE.c_str(), HANDSHAKE_MESSAGE.size())) {
774         hChannel->availTailIndex = 0;
775         WRITE_LOG(LOG_DEBUG, "Channel Hello failed");
776         return ERR_HANDSHAKE_NOTMATCH;
777     }
778     if (strlen(handShake->connectKey) > sizeof(handShake->connectKey)) {
779         hChannel->availTailIndex = 0;
780         WRITE_LOG(LOG_DEBUG, "Connectkey's size incorrect");
781         return ERR_HANDSHAKE_CONNECTKEY_FAILED;
782     }
783     // channel handshake step3
784     WRITE_LOG(LOG_DEBUG, "ServerForClient channel handshake finished");
785     hChannel->connectKey = handShake->connectKey;
786     hChannel->handshakeOK = true;
787     if (!CheckAutoFillTarget(hChannel)) {
788         WRITE_LOG(LOG_WARN, "No target channelId:%u", hChannel->channelId);
789         return 0;
790     }
791     // channel handshake stBindChannelToSession
792     if (BindChannelToSession(hChannel, nullptr, 0)) {
793         hChannel->availTailIndex = 0;
794         WRITE_LOG(LOG_FATAL, "BindChannelToSession failed channelId:%u", hChannel->channelId);
795         return ERR_GENERIC;
796     }
797     return 0;
798 }
799 
ReportServerVersion(HChannel hChannel)800 void HdcServerForClient::ReportServerVersion(HChannel hChannel)
801 {
802     string version = Base::GetVersion();
803     SendChannelWithCmd(hChannel, CMD_CHECK_SERVER,
804                        const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(version.c_str())),
805                        version.size());
806 }
807 
808 // 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)809 int HdcServerForClient::ReadChannel(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
810 {
811     int ret = 0;
812     if (!hChannel->handshakeOK) {
813         return ChannelHandShake(hChannel, bufPtr, bytesIO);
814     }
815 
816     uint16_t command = *reinterpret_cast<uint16_t *>(bufPtr);
817     if (command != 0 && (hChannel->remote > RemoteType::REMOTE_NONE)) {
818         // server directly passthrough file command to daemon
819         if (!SendToDaemon(hChannel, command, bufPtr + sizeof(uint16_t), bytesIO - sizeof(uint16_t))) {
820             WRITE_LOG(LOG_FATAL, "Client ReadChannel : direct send to daemon failed");
821         }
822         return ret;
823     }
824     struct TranslateCommand::FormatCommand formatCommand = { 0 };
825     if (!hChannel->interactiveShellMode) {
826         string retEcho = String2FormatCommand(reinterpret_cast<char *>(bufPtr), bytesIO, &formatCommand);
827         if (retEcho.length()) {
828             if (!strncmp(reinterpret_cast<char *>(bufPtr), CMDSTR_SOFTWARE_HELP.c_str(),
829                 CMDSTR_SOFTWARE_HELP.size()) ||
830                 !strcmp(reinterpret_cast<char *>(bufPtr), CMDSTR_SOFTWARE_VERSION.c_str()) ||
831                 !strcmp(reinterpret_cast<char *>(bufPtr), "flash")) {
832                 EchoClient(hChannel, MSG_OK, retEcho.c_str());
833             } else {
834                 EchoClient(hChannel, MSG_FAIL, retEcho.c_str());
835             }
836         }
837         WRITE_LOG(LOG_DEBUG, "ReadChannel command: %s", bufPtr);
838         if (formatCommand.bJumpDo) {
839             WRITE_LOG(LOG_FATAL, "ReadChannel bJumpDo true");
840             ret = -10;
841             return ret;
842         }
843     } else {
844         formatCommand.parameters = string(reinterpret_cast<char *>(bufPtr), bytesIO);
845         formatCommand.cmdFlag = CMD_SHELL_DATA;
846     }
847 
848     if (!DoCommand(hChannel, &formatCommand)) {
849         return -3;  // -3: error or want close
850     }
851     ret = bytesIO;
852     return ret;
853 };
854 
855 // avoid session dead
FindAliveSession(uint32_t sessionId)856 HSession HdcServerForClient::FindAliveSession(uint32_t sessionId)
857 {
858     HdcServer *ptrServer = (HdcServer *)clsServer;
859     HSession hSession = ptrServer->AdminSession(OP_QUERY, sessionId, nullptr);
860     if (!hSession || hSession->isDead) {
861         WRITE_LOG(LOG_FATAL, "FindAliveSession hSession nullptr or isDead sessionId:%u", sessionId);
862         return nullptr;
863     } else {
864         return hSession;
865     }
866 }
867 
ChannelSendSessionCtrlMsg(vector<uint8_t> & ctrlMsg,uint32_t sessionId)868 bool HdcServerForClient::ChannelSendSessionCtrlMsg(vector<uint8_t> &ctrlMsg, uint32_t sessionId)
869 {
870     HSession hSession = FindAliveSession(sessionId);
871     if (!hSession) {
872         sessionIsDead = true;
873         WRITE_LOG(LOG_FATAL, "ChannelSendSessionCtrlMsg hSession nullptr sessionId:%u", sessionId);
874         return false;
875     }
876     return Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrlMsg.data(), ctrlMsg.size()) > 0;
877 }
878 }  // namespace Hdc
879