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