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