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