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