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;
156 }
157 bool b = SetTCPListen();
158 if (!b) {
159 WRITE_LOG(LOG_FATAL, "SetTCPListen failed");
160 int listenError = -3;
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 if (childRet == -1) {
317 EchoClient(hChannel, MSG_INFO, "Target is connected, repeat operation");
318 } else if (childRet == connectError) {
319 EchoClient(hChannel, MSG_FAIL, "CreateConnect failed");
320 WRITE_LOG(LOG_FATAL, "CreateConnect failed");
321 } else {
322 size_t pos = connectKey.find(":");
323 if (pos != std::string::npos) {
324 string ip = connectKey.substr(0, pos);
325 if (ip == "127.0.0.1") {
326 hChannel->connectLocalDevice = true;
327 }
328 }
329 Base::ZeroBuf(hChannel->bufStd, 2);
330 childRet = snprintf_s(hChannel->bufStd + 2, sizeof(hChannel->bufStd) - 2, sizeof(hChannel->bufStd) - 3, "%s",
331 const_cast<char *>(connectKey.c_str()));
332 if (childRet > 0) {
333 Base::TimerUvTask(loopMain, hChannel, OrderConnecTargetResult, 10);
334 ret = true;
335 }
336 }
337 return ret;
338 }
339
CommandRemoveSession(HChannel hChannel,const char * connectKey)340 bool HdcServerForClient::CommandRemoveSession(HChannel hChannel, const char *connectKey)
341 {
342 HdcServer *ptrServer = (HdcServer *)clsServer;
343 HDaemonInfo hdiOld = nullptr;
344 (reinterpret_cast<HdcServer *>(ptrServer))->AdminDaemonMap(OP_QUERY, connectKey, hdiOld);
345 if (!hdiOld) {
346 EchoClient(hChannel, MSG_FAIL, "No target available");
347 return false;
348 }
349 (reinterpret_cast<HdcServer *>(ptrServer))->FreeSession(hdiOld->hSession->sessionId);
350 return true;
351 }
352
CommandRemoveForward(const string & forwardKey)353 bool HdcServerForClient::CommandRemoveForward(const string &forwardKey)
354 {
355 HdcServer *ptrServer = (HdcServer *)clsServer;
356 HForwardInfo hfi = nullptr;
357 ptrServer->AdminForwardMap(OP_QUERY, forwardKey, hfi);
358 if (!hfi) {
359 WRITE_LOG(LOG_FATAL, "CommandRemoveForward hfi nullptr forwardKey:%s", forwardKey.c_str());
360 return false;
361 }
362 HSession hSession = ptrServer->AdminSession(OP_QUERY, hfi->sessionId, nullptr);
363 if (!hSession) {
364 WRITE_LOG(LOG_FATAL, "CommandRemoveForward hSession nullptr sessionId:%u", hfi->sessionId);
365 ptrServer->AdminForwardMap(OP_REMOVE, forwardKey, hfi);
366 return true;
367 }
368 ptrServer->ClearOwnTasks(hSession, hfi->channelId);
369 FreeChannel(hfi->channelId);
370 hfi = nullptr;
371 ptrServer->AdminForwardMap(OP_REMOVE, forwardKey, hfi);
372 return true;
373 }
374
GetTargetList(HChannel hChannel,void * formatCommandInput)375 void HdcServerForClient::GetTargetList(HChannel hChannel, void *formatCommandInput)
376 {
377 TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
378 HdcServer *ptrServer = (HdcServer *)clsServer;
379 uint16_t cmd = OP_GET_STRLIST;
380 if (formatCommand->parameters == "v") {
381 cmd = OP_GET_STRLIST_FULL;
382 }
383 HDaemonInfo hdi = nullptr;
384 string sRet = ptrServer->AdminDaemonMap(cmd, STRING_EMPTY, hdi);
385 if (!sRet.length()) {
386 sRet = EMPTY_ECHO;
387 }
388 EchoClient(hChannel, MSG_OK, const_cast<char *>(sRet.c_str()));
389 #ifdef UNIT_TEST
390 Base::WriteBinFile((UT_TMP_PATH + "/base-list.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(),
391 MESSAGE_SUCCESS.size(), true);
392 #endif
393 }
394
GetAnyTarget(HChannel hChannel)395 bool HdcServerForClient::GetAnyTarget(HChannel hChannel)
396 {
397 HdcServer *ptrServer = (HdcServer *)clsServer;
398 HDaemonInfo hdi = nullptr;
399 ptrServer->AdminDaemonMap(OP_GET_ANY, STRING_EMPTY, hdi);
400 if (!hdi) {
401 EchoClient(hChannel, MSG_FAIL, "No target available");
402 return false;
403 }
404 // can not use hdi->connectKey.This memory may be released to re-Malloc
405 string connectKey = hdi->connectKey;
406 bool ret = NewConnectTry(ptrServer, hChannel, connectKey);
407 #ifdef UNIT_TEST
408 Base::WriteBinFile((UT_TMP_PATH + "/base-any.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(),
409 MESSAGE_SUCCESS.size(), true);
410 #endif
411 return ret;
412 }
413
WaitForAny(HChannel hChannel)414 bool HdcServerForClient::WaitForAny(HChannel hChannel)
415 {
416 HdcServer *ptrServer = (HdcServer *)clsServer;
417 HDaemonInfo hdi = nullptr;
418 ptrServer->AdminDaemonMap(OP_WAIT_FOR_ANY, STRING_EMPTY, hdi);
419 if (!hdi) {
420 EchoClient(hChannel, MSG_FAIL, "No any connected target");
421 return false;
422 }
423 string key = hdi->connectKey;
424 EchoClient(hChannel, MSG_OK, "Wait for connected target is %s", key.c_str());
425 return true;
426 }
427
RemoveForward(HChannel hChannel,const char * parameterString)428 bool HdcServerForClient::RemoveForward(HChannel hChannel, const char *parameterString)
429 {
430 HdcServer *ptrServer = (HdcServer *)clsServer;
431 if (parameterString == nullptr) { // remove all
432 HForwardInfo hfi = nullptr; // dummy
433 string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST, "", hfi);
434 if (!echo.length()) {
435 return false;
436 }
437 vector<string> filterStrings;
438 Base::SplitString(echo, string("\n"), filterStrings);
439 for (auto &&s : filterStrings) {
440 if (CommandRemoveForward(s.c_str())) {
441 EchoClient(hChannel, MSG_OK, "Remove forward ruler success, ruler:%s", s.c_str());
442 } else {
443 EchoClient(hChannel, MSG_FAIL, "Remove forward ruler failed, ruler is not exist %s", s.c_str());
444 }
445 }
446 } else { // remove single
447 if (CommandRemoveForward(parameterString)) {
448 EchoClient(hChannel, MSG_OK, "Remove forward ruler success, ruler:%s", parameterString);
449 } else {
450 EchoClient(hChannel, MSG_FAIL, "Remove forward ruler failed, ruler is not exist %s", parameterString);
451 }
452 }
453 return true;
454 }
455
DoCommandLocal(HChannel hChannel,void * formatCommandInput)456 bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandInput)
457 {
458 TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
459 HdcServer *ptrServer = (HdcServer *)clsServer;
460 bool ret = false;
461 // Main thread command, direct Listen main thread
462 switch (formatCommand->cmdFlag) {
463 case CMD_KERNEL_TARGET_DISCOVER: {
464 OrderFindTargets(hChannel);
465 ret = false;
466 break;
467 }
468 case CMD_KERNEL_TARGET_LIST: {
469 GetTargetList(hChannel, formatCommandInput);
470 ret = false;
471 break;
472 }
473 case CMD_CHECK_SERVER: {
474 WRITE_LOG(LOG_DEBUG, "CMD_CHECK_SERVER command");
475 ReportServerVersion(hChannel);
476 ret = false;
477 break;
478 }
479 case CMD_WAIT_FOR: {
480 WRITE_LOG(LOG_DEBUG, "CMD_WAIT_FOR command");
481 ret = !WaitForAny(hChannel);
482 break;
483 }
484 case CMD_KERNEL_TARGET_ANY: {
485 #ifdef HDC_DEBUG
486 WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_ANY %s", __FUNCTION__, formatCommand->parameters.c_str());
487 #endif
488 ret = GetAnyTarget(hChannel);
489 break;
490 }
491 case CMD_KERNEL_TARGET_CONNECT: {
492 #ifdef HDC_DEBUG
493 WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_CONNECT %s", __FUNCTION__, formatCommand->parameters.c_str());
494 #endif
495 ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str());
496 break;
497 }
498 case CMD_CHECK_DEVICE: {
499 WRITE_LOG(LOG_INFO, "%s CMD_CHECK_DEVICE %s", __FUNCTION__, formatCommand->parameters.c_str());
500 hChannel->isCheck = true;
501 hChannel->key = formatCommand->parameters.c_str();
502 ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str(), true);
503 break;
504 }
505 case CMD_KERNEL_TARGET_DISCONNECT: {
506 CommandRemoveSession(hChannel, formatCommand->parameters.c_str());
507 break;
508 }
509 case CMD_KERNEL_SERVER_KILL: {
510 WRITE_LOG(LOG_DEBUG, "Recv server kill command");
511 uv_stop(loopMain);
512 ret = true;
513 break;
514 }
515 // task will be global task,Therefore, it can only be controlled in the global session.
516 case CMD_FORWARD_LIST: {
517 HForwardInfo hfi = nullptr; // dummy
518 string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST_FULL, "", hfi);
519 if (!echo.length()) {
520 echo = EMPTY_ECHO;
521 }
522 EchoClient(hChannel, MSG_OK, const_cast<char *>(echo.c_str()));
523 break;
524 }
525 case CMD_FORWARD_REMOVE: {
526 RemoveForward(hChannel, formatCommand->parameters.c_str());
527 break;
528 }
529 case CMD_KERNEL_ENABLE_KEEPALIVE: {
530 // just use for 'list targets' now
531 hChannel->keepAlive = true;
532 ret = true;
533 break;
534 }
535 default: {
536 EchoClient(hChannel, MSG_FAIL, "ExecuteCommand need connect-key?");
537 break;
538 }
539 }
540 return ret;
541 }
542
TaskCommand(HChannel hChannel,void * formatCommandInput)543 bool HdcServerForClient::TaskCommand(HChannel hChannel, void *formatCommandInput)
544 {
545 TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
546 HdcServer *ptrServer = (HdcServer *)clsServer;
547 string cmdFlag;
548 uint8_t sizeCmdFlag = 0;
549 if (formatCommand->cmdFlag == CMD_FILE_INIT) {
550 cmdFlag = "send ";
551 sizeCmdFlag = 5; // 5: cmdFlag send size
552 HandleRemote(hChannel, formatCommand->parameters, RemoteType::REMOTE_FILE);
553 } else if (formatCommand->cmdFlag == CMD_FORWARD_INIT) {
554 cmdFlag = "fport ";
555 sizeCmdFlag = 6; // 6: cmdFlag fport size
556 } else if (formatCommand->cmdFlag == CMD_APP_INIT) {
557 cmdFlag = "install ";
558 sizeCmdFlag = 8; // 8: cmdFlag install size
559 HandleRemote(hChannel, formatCommand->parameters, RemoteType::REMOTE_APP);
560 } else if (formatCommand->cmdFlag == CMD_APP_UNINSTALL) {
561 cmdFlag = "uninstall ";
562 sizeCmdFlag = 10; // 10: cmdFlag uninstall size
563 } else if (formatCommand->cmdFlag == CMD_UNITY_BUGREPORT_INIT) {
564 cmdFlag = "bugreport ";
565 sizeCmdFlag = 10; // 10: cmdFlag bugreport size
566 } else if (formatCommand->cmdFlag == CMD_APP_SIDELOAD) {
567 cmdFlag = "sideload ";
568 sizeCmdFlag = 9; // 9: cmdFlag sideload size
569 } else if (formatCommand->cmdFlag == CMD_FLASHD_UPDATE_INIT) {
570 cmdFlag = "update ";
571 sizeCmdFlag = 7; // 7: cmdFlag update size
572 } else if (formatCommand->cmdFlag == CMD_FLASHD_FLASH_INIT) {
573 cmdFlag = "flash ";
574 sizeCmdFlag = 6; // 6: cmdFlag flash size
575 }
576 int sizeSend = formatCommand->parameters.size();
577 if (!strncmp(formatCommand->parameters.c_str(), cmdFlag.c_str(), sizeCmdFlag)) { // local do
578 HSession hSession = FindAliveSession(hChannel->targetSessionId);
579 if (!hSession) {
580 return false;
581 }
582 if ((formatCommand->cmdFlag == CMD_FILE_INIT || formatCommand->cmdFlag == CMD_APP_INIT) &&
583 hChannel->fromClient) {
584 // remote client mode, CMD_FILE_INIT and CMD_APP_INIT command send back to client
585 WRITE_LOG(LOG_DEBUG, "command send back to remote client channelId:%u", hChannel->channelId);
586 SendChannelWithCmd(hChannel, formatCommand->cmdFlag,
587 reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
588 sizeSend - sizeCmdFlag);
589 return false;
590 }
591 ptrServer->DispatchTaskData(hSession, hChannel->channelId, formatCommand->cmdFlag,
592 reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
593 sizeSend - sizeCmdFlag);
594 } else { // Send to Daemon-side to do
595 SendToDaemon(hChannel, formatCommand->cmdFlag,
596 reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
597 sizeSend - sizeCmdFlag);
598 }
599 return true;
600 }
601
HandleRemote(HChannel hChannel,string & parameters,RemoteType flag)602 void HdcServerForClient::HandleRemote(HChannel hChannel, string ¶meters, RemoteType flag)
603 {
604 hChannel->remote = flag;
605 int argc = 0;
606 char **argv = Base::SplitCommandToArgs(parameters.c_str(), &argc);
607 for (int i = 0; i < argc; i++) {
608 if (argv[i] == CMDSTR_REMOTE_PARAMETER) {
609 hChannel->fromClient = true;
610 WRITE_LOG(LOG_DEBUG, "remote client mode channelId:%u", hChannel->channelId);
611 break;
612 }
613 }
614 if (hChannel->fromClient) {
615 string remote = CMDSTR_REMOTE_PARAMETER + " ";
616 if (parameters.find(remote) != std::string::npos) {
617 parameters.replace(parameters.find(remote), remote.size(), "");
618 WRITE_LOG(LOG_DEBUG, "parameters: %s", parameters.c_str());
619 }
620 }
621 }
622
DoCommandRemote(HChannel hChannel,void * formatCommandInput)623 bool HdcServerForClient::DoCommandRemote(HChannel hChannel, void *formatCommandInput)
624 {
625 TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
626 bool ret = false;
627 int sizeSend = formatCommand->parameters.size();
628 string cmdFlag;
629 switch (formatCommand->cmdFlag) {
630 // Some simple commands only need to forward the instruction, no need to start Task
631 case CMD_SHELL_INIT:
632 case CMD_SHELL_DATA:
633 case CMD_UNITY_EXECUTE:
634 case CMD_UNITY_TERMINATE:
635 case CMD_UNITY_REMOUNT:
636 case CMD_UNITY_REBOOT:
637 case CMD_UNITY_RUNMODE:
638 case CMD_UNITY_HILOG:
639 case CMD_UNITY_ROOTRUN:
640 case CMD_JDWP_TRACK:
641 case CMD_JDWP_LIST: {
642 if (!SendToDaemon(hChannel, formatCommand->cmdFlag,
643 reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())),
644 sizeSend)) {
645 break;
646 }
647 ret = true;
648 if (formatCommand->cmdFlag == CMD_SHELL_INIT) {
649 hChannel->interactiveShellMode = true;
650 }
651 break;
652 }
653 case CMD_FILE_INIT:
654 case CMD_FORWARD_INIT:
655 case CMD_APP_INIT:
656 case CMD_APP_UNINSTALL:
657 case CMD_UNITY_BUGREPORT_INIT:
658 case CMD_APP_SIDELOAD:
659 case CMD_FLASHD_UPDATE_INIT:
660 case CMD_FLASHD_FLASH_INIT:
661 case CMD_FLASHD_ERASE:
662 case CMD_FLASHD_FORMAT: {
663 TaskCommand(hChannel, formatCommandInput);
664 ret = true;
665 break;
666 }
667 default:
668 break;
669 }
670 if (!ret) {
671 EchoClient(hChannel, MSG_FAIL, "Failed to communicate with daemon");
672 }
673 return ret;
674 }
675 // Do not specify Target's operations no longer need to put it in the thread.
DoCommand(HChannel hChannel,void * formatCommandInput)676 bool HdcServerForClient::DoCommand(HChannel hChannel, void *formatCommandInput)
677 {
678 bool ret = false;
679 TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
680 if (!hChannel->hChildWorkTCP.loop || formatCommand->cmdFlag == CMD_FORWARD_REMOVE) {
681 // Main thread command, direct Listen main thread
682 ret = DoCommandLocal(hChannel, formatCommandInput);
683 } else { // CONNECT DAEMON's work thread command, non-primary thread
684 ret = DoCommandRemote(hChannel, formatCommandInput);
685 }
686 return ret;
687 }
688
689 // just call from BindChannelToSession
FindAliveSessionFromDaemonMap(const HChannel hChannel)690 HSession HdcServerForClient::FindAliveSessionFromDaemonMap(const HChannel hChannel)
691 {
692 HSession hSession = nullptr;
693 HDaemonInfo hdi = nullptr;
694 HdcServer *ptrServer = (HdcServer *)clsServer;
695 ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi);
696 if (!hdi) {
697 EchoClient(hChannel, MSG_FAIL, "Not match target founded, check connect-key please");
698 return nullptr;
699 }
700 if (hdi->connStatus != STATUS_CONNECTED) {
701 EchoClient(hChannel, MSG_FAIL, "Device not founded or connected");
702 return nullptr;
703 }
704 if (hdi->hSession->isDead) {
705 EchoClient(hChannel, MSG_FAIL, "Bind tartget session is dead");
706 return nullptr;
707 }
708 hSession = reinterpret_cast<HSession>(hdi->hSession);
709 return hSession;
710 }
711
BindChannelToSession(HChannel hChannel,uint8_t * bufPtr,const int bytesIO)712 int HdcServerForClient::BindChannelToSession(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
713 {
714 if (FindAliveSessionFromDaemonMap(hChannel) == nullptr) {
715 WRITE_LOG(LOG_FATAL, "Find no alive session channelId:%u", hChannel->channelId);
716 return ERR_SESSION_NOFOUND;
717 }
718 bool isClosing = uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP);
719 if (!isClosing && (hChannel->fdChildWorkTCP = Base::DuplicateUvSocket(&hChannel->hWorkTCP)) < 0) {
720 WRITE_LOG(LOG_FATAL, "Duplicate socket failed channelId:%u", hChannel->channelId);
721 return ERR_SOCKET_DUPLICATE;
722 }
723 uv_close_cb funcWorkTcpClose = [](uv_handle_t *handle) -> void {
724 HChannel hChannel = (HChannel)handle->data;
725 --hChannel->ref;
726 };
727 ++hChannel->ref;
728 if (!isClosing) {
729 uv_close((uv_handle_t *)&hChannel->hWorkTCP, funcWorkTcpClose);
730 }
731 Base::DoNextLoop(loopMain, hChannel, [](const uint8_t flag, string &msg, const void *data) {
732 // Thread message can avoid using thread lock and improve program efficiency
733 // If not next loop call, ReadStream will thread conflict
734 HChannel hChannel = (HChannel)data;
735 auto thisClass = (HdcServerForClient *)hChannel->clsChannel;
736 HSession hSession = nullptr;
737 if ((hSession = thisClass->FindAliveSessionFromDaemonMap(hChannel)) == nullptr) {
738 WRITE_LOG(LOG_FATAL, "hSession nullptr channelId:%u", hChannel->channelId);
739 return;
740 }
741 auto ctrl = HdcSessionBase::BuildCtrlString(SP_ATTACH_CHANNEL, hChannel->channelId, nullptr, 0);
742 Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
743 });
744 return RET_SUCCESS;
745 }
746
CheckAutoFillTarget(HChannel hChannel)747 bool HdcServerForClient::CheckAutoFillTarget(HChannel hChannel)
748 {
749 HdcServer *ptrServer = (HdcServer *)clsServer;
750 if (!hChannel->connectKey.size()) {
751 WRITE_LOG(LOG_FATAL, "connectKey.size 0 channelId:%u", hChannel->channelId);
752 return false; // Operation of non-bound destination of scanning
753 }
754 if (hChannel->connectKey == CMDSTR_CONNECT_ANY) {
755 HDaemonInfo hdiOld = nullptr;
756 ptrServer->AdminDaemonMap(OP_GET_ONLY, "", hdiOld);
757 if (!hdiOld) {
758 WRITE_LOG(LOG_WARN, "No any key found channelId:%u", hChannel->channelId);
759 return false;
760 }
761 hChannel->connectKey = hdiOld->connectKey;
762 return true;
763 }
764 return true;
765 }
766
ChannelHandShake(HChannel hChannel,uint8_t * bufPtr,const int bytesIO)767 int HdcServerForClient::ChannelHandShake(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
768 {
769 vector<uint8_t> rebuildHandshake;
770 rebuildHandshake.insert(rebuildHandshake.end(), bufPtr, bufPtr + bytesIO);
771 rebuildHandshake.push_back(0x00);
772 struct ChannelHandShake *handShake = reinterpret_cast<struct ChannelHandShake *>(rebuildHandshake.data());
773 if (strncmp(handShake->banner, HANDSHAKE_MESSAGE.c_str(), HANDSHAKE_MESSAGE.size())) {
774 hChannel->availTailIndex = 0;
775 WRITE_LOG(LOG_DEBUG, "Channel Hello failed");
776 return ERR_HANDSHAKE_NOTMATCH;
777 }
778 if (strlen(handShake->connectKey) > sizeof(handShake->connectKey)) {
779 hChannel->availTailIndex = 0;
780 WRITE_LOG(LOG_DEBUG, "Connectkey's size incorrect");
781 return ERR_HANDSHAKE_CONNECTKEY_FAILED;
782 }
783 // channel handshake step3
784 WRITE_LOG(LOG_DEBUG, "ServerForClient channel handshake finished");
785 hChannel->connectKey = handShake->connectKey;
786 hChannel->handshakeOK = true;
787 if (!CheckAutoFillTarget(hChannel)) {
788 WRITE_LOG(LOG_WARN, "No target channelId:%u", hChannel->channelId);
789 return 0;
790 }
791 // channel handshake stBindChannelToSession
792 if (BindChannelToSession(hChannel, nullptr, 0)) {
793 hChannel->availTailIndex = 0;
794 WRITE_LOG(LOG_FATAL, "BindChannelToSession failed channelId:%u", hChannel->channelId);
795 return ERR_GENERIC;
796 }
797 return 0;
798 }
799
ReportServerVersion(HChannel hChannel)800 void HdcServerForClient::ReportServerVersion(HChannel hChannel)
801 {
802 string version = Base::GetVersion();
803 SendChannelWithCmd(hChannel, CMD_CHECK_SERVER,
804 const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(version.c_str())),
805 version.size());
806 }
807
808 // 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)809 int HdcServerForClient::ReadChannel(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
810 {
811 int ret = 0;
812 if (!hChannel->handshakeOK) {
813 return ChannelHandShake(hChannel, bufPtr, bytesIO);
814 }
815
816 uint16_t command = *reinterpret_cast<uint16_t *>(bufPtr);
817 if (command != 0 && (hChannel->remote > RemoteType::REMOTE_NONE)) {
818 // server directly passthrough file command to daemon
819 if (!SendToDaemon(hChannel, command, bufPtr + sizeof(uint16_t), bytesIO - sizeof(uint16_t))) {
820 WRITE_LOG(LOG_FATAL, "Client ReadChannel : direct send to daemon failed");
821 }
822 return ret;
823 }
824 struct TranslateCommand::FormatCommand formatCommand = { 0 };
825 if (!hChannel->interactiveShellMode) {
826 string retEcho = String2FormatCommand(reinterpret_cast<char *>(bufPtr), bytesIO, &formatCommand);
827 if (retEcho.length()) {
828 if (!strncmp(reinterpret_cast<char *>(bufPtr), CMDSTR_SOFTWARE_HELP.c_str(),
829 CMDSTR_SOFTWARE_HELP.size()) ||
830 !strcmp(reinterpret_cast<char *>(bufPtr), CMDSTR_SOFTWARE_VERSION.c_str()) ||
831 !strcmp(reinterpret_cast<char *>(bufPtr), "flash")) {
832 EchoClient(hChannel, MSG_OK, retEcho.c_str());
833 } else {
834 EchoClient(hChannel, MSG_FAIL, retEcho.c_str());
835 }
836 }
837 WRITE_LOG(LOG_DEBUG, "ReadChannel command: %s", bufPtr);
838 if (formatCommand.bJumpDo) {
839 WRITE_LOG(LOG_FATAL, "ReadChannel bJumpDo true");
840 ret = -10;
841 return ret;
842 }
843 } else {
844 formatCommand.parameters = string(reinterpret_cast<char *>(bufPtr), bytesIO);
845 formatCommand.cmdFlag = CMD_SHELL_DATA;
846 }
847
848 if (!DoCommand(hChannel, &formatCommand)) {
849 return -3; // -3: error or want close
850 }
851 ret = bytesIO;
852 return ret;
853 };
854
855 // avoid session dead
FindAliveSession(uint32_t sessionId)856 HSession HdcServerForClient::FindAliveSession(uint32_t sessionId)
857 {
858 HdcServer *ptrServer = (HdcServer *)clsServer;
859 HSession hSession = ptrServer->AdminSession(OP_QUERY, sessionId, nullptr);
860 if (!hSession || hSession->isDead) {
861 WRITE_LOG(LOG_FATAL, "FindAliveSession hSession nullptr or isDead sessionId:%u", sessionId);
862 return nullptr;
863 } else {
864 return hSession;
865 }
866 }
867
ChannelSendSessionCtrlMsg(vector<uint8_t> & ctrlMsg,uint32_t sessionId)868 bool HdcServerForClient::ChannelSendSessionCtrlMsg(vector<uint8_t> &ctrlMsg, uint32_t sessionId)
869 {
870 HSession hSession = FindAliveSession(sessionId);
871 if (!hSession) {
872 sessionIsDead = true;
873 WRITE_LOG(LOG_FATAL, "ChannelSendSessionCtrlMsg hSession nullptr sessionId:%u", sessionId);
874 return false;
875 }
876 return Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrlMsg.data(), ctrlMsg.size()) > 0;
877 }
878 } // namespace Hdc
879