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