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.h"
16 #include "host_updater.h"
17
18
19 namespace Hdc {
HdcServer(bool serverOrDaemonIn)20 HdcServer::HdcServer(bool serverOrDaemonIn)
21 : HdcSessionBase(serverOrDaemonIn)
22 {
23 clsTCPClt = nullptr;
24 clsUSBClt = nullptr;
25 #ifdef HDC_SUPPORT_UART
26 clsUARTClt = nullptr;
27 #endif
28 clsServerForClient = nullptr;
29 uv_rwlock_init(&daemonAdmin);
30 uv_rwlock_init(&forwardAdmin);
31 }
32
~HdcServer()33 HdcServer::~HdcServer()
34 {
35 WRITE_LOG(LOG_DEBUG, "~HdcServer");
36 uv_rwlock_destroy(&daemonAdmin);
37 uv_rwlock_destroy(&forwardAdmin);
38 }
39
ClearInstanceResource()40 void HdcServer::ClearInstanceResource()
41 {
42 TryStopInstance();
43 Base::TryCloseLoop(&loopMain, "HdcServer::~HdcServer");
44 if (clsTCPClt) {
45 delete clsTCPClt;
46 }
47 if (clsUSBClt) {
48 delete clsUSBClt;
49 }
50 #ifdef HDC_SUPPORT_UART
51 if (clsUARTClt) {
52 delete clsUARTClt;
53 }
54 #endif
55 if (clsServerForClient) {
56 delete (static_cast<HdcServerForClient *>(clsServerForClient));
57 }
58 }
59
TryStopInstance()60 void HdcServer::TryStopInstance()
61 {
62 ClearSessions();
63 if (clsTCPClt) {
64 clsTCPClt->Stop();
65 }
66 if (clsUSBClt) {
67 clsUSBClt->Stop();
68 }
69 #ifdef HDC_SUPPORT_UART
70 if (clsUARTClt) {
71 clsUARTClt->Stop();
72 }
73 #endif
74 if (clsServerForClient) {
75 ((HdcServerForClient *)clsServerForClient)->Stop();
76 }
77 ReMainLoopForInstanceClear();
78 ClearMapDaemonInfo();
79 }
80
Initial(const char * listenString)81 bool HdcServer::Initial(const char *listenString)
82 {
83 if (Base::ProgramMutex(SERVER_NAME.c_str(), false) != 0) {
84 WRITE_LOG(LOG_FATAL, "Other instance already running, program mutex failed");
85 return false;
86 }
87 Base::RemoveLogFile();
88 clsServerForClient = new HdcServerForClient(true, listenString, this, &loopMain);
89 (static_cast<HdcServerForClient *>(clsServerForClient))->Initial();
90 clsUSBClt->InitLogging(ctxUSB);
91 clsTCPClt = new HdcHostTCP(true, this);
92 clsUSBClt = new HdcHostUSB(true, this, ctxUSB);
93 if (clsUSBClt->Initial() != RET_SUCCESS) {
94 return false;
95 }
96 if (!clsServerForClient || !clsTCPClt || !clsUSBClt) {
97 WRITE_LOG(LOG_FATAL, "Class init failed");
98 return false;
99 }
100
101 #ifdef HDC_SUPPORT_UART
102 clsUARTClt = new HdcHostUART(*this);
103 if (!clsUARTClt) {
104 WRITE_LOG(LOG_FATAL, "Class init failed");
105 return false;
106 }
107 if (clsUARTClt->Initial() != RET_SUCCESS) {
108 WRITE_LOG(LOG_FATAL, "clsUARTClt Class init failed.");
109 return false;
110 }
111 #endif
112 return true;
113 }
114
PullupServerWin32(const char * path,const char * listenString)115 bool HdcServer::PullupServerWin32(const char *path, const char *listenString)
116 {
117 bool retVal = false;
118 #ifdef _WIN32
119 char buf[BUF_SIZE_SMALL] = "";
120 char shortPath[MAX_PATH] = "";
121 std::string strPath = Base::UnicodeToUtf8(path, true);
122 int ret = GetShortPathName(strPath.c_str(), shortPath, MAX_PATH);
123 std::string runPath = shortPath;
124 if (ret == 0) {
125 int err = GetLastError();
126 constexpr int bufSize = 1024;
127 char buffer[bufSize] = { 0 };
128 strerror_s(buffer, bufSize, err);
129 WRITE_LOG(LOG_WARN, "GetShortPath path:[%s] errmsg:%s", path, buffer);
130 string uvPath = path;
131 runPath = uvPath.substr(uvPath.find_last_of("/\\") + 1);
132 }
133 WRITE_LOG(LOG_DEBUG, "server shortpath:[%s] runPath:[%s]", shortPath, runPath.c_str());
134 // here we give a dummy option first, because getopt will assume the first option is command. it
135 // begin from 2nd args.
136 if (sprintf_s(buf, sizeof(buf), "dummy -l %d -s %s -m", Base::GetLogLevel(), listenString) < 0) {
137 return retVal;
138 }
139 WRITE_LOG(LOG_DEBUG, "Run server in debug-forground, cmd:%s, args:%s", runPath.c_str(), buf);
140 STARTUPINFO si = {};
141 si.cb = sizeof(STARTUPINFO);
142 PROCESS_INFORMATION pi = {};
143 #ifndef HDC_DEBUG
144 si.dwFlags = STARTF_USESHOWWINDOW;
145 si.wShowWindow = SW_HIDE;
146 #endif
147 if (!CreateProcess(runPath.c_str(), buf, nullptr, nullptr, true, CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi)) {
148 WRITE_LOG(LOG_WARN, "CreateProcess failed with cmd:%s, args:%s, Error Code %d", runPath.c_str(), buf,
149 GetLastError());
150 retVal = false;
151 } else {
152 retVal = true;
153 }
154 CloseHandle(pi.hThread);
155 CloseHandle(pi.hProcess);
156 #endif
157 return retVal;
158 }
159
160 // Only detects that the default call is in the loop address, the other tubes are not
PullupServer(const char * listenString)161 bool HdcServer::PullupServer(const char *listenString)
162 {
163 char path[BUF_SIZE_SMALL] = "";
164 size_t nPathSize = sizeof(path);
165 int ret = uv_exepath(path, &nPathSize);
166 if (ret < 0) {
167 constexpr int bufSize = 1024;
168 char buf[bufSize] = { 0 };
169 uv_err_name_r(ret, buf, bufSize);
170 WRITE_LOG(LOG_WARN, "uvexepath ret:%d error:%s", ret, buf);
171 return false;
172 }
173
174 #ifdef _WIN32
175 if (!PullupServerWin32(path, listenString)) {
176 return false;
177 }
178 #else
179 pid_t pc = fork(); // create process as daemon process
180 if (pc < 0) {
181 return false;
182 } else if (!pc) {
183 int i;
184 const int maxFD = 1024;
185 for (i = 0; i < maxFD; ++i) {
186 // close file pipe
187 int fd = i;
188 Base::CloseFd(fd);
189 }
190 execl(path, "hdc", "-m", "-s", listenString, nullptr);
191 exit(0);
192 return true;
193 }
194 // orig process
195 #endif
196 // wait little time, util backend-server work ready
197 uv_sleep(TIME_BASE);
198 return true;
199 }
200
ClearMapDaemonInfo()201 void HdcServer::ClearMapDaemonInfo()
202 {
203 map<string, HDaemonInfo>::iterator iter;
204 uv_rwlock_rdlock(&daemonAdmin);
205 for (iter = mapDaemon.begin(); iter != mapDaemon.end();) {
206 string sKey = iter->first;
207 HDaemonInfo hDi = iter->second;
208 delete hDi;
209 ++iter;
210 }
211 uv_rwlock_rdunlock(&daemonAdmin);
212 uv_rwlock_wrlock(&daemonAdmin);
213 mapDaemon.clear();
214 uv_rwlock_wrunlock(&daemonAdmin);
215 }
216
BuildDaemonVisableLine(HDaemonInfo hdi,bool fullDisplay,string & out)217 void HdcServer::BuildDaemonVisableLine(HDaemonInfo hdi, bool fullDisplay, string &out)
218 {
219 if (fullDisplay) {
220 string sConn;
221 string sStatus;
222 switch (hdi->connType) {
223 case CONN_TCP:
224 sConn = "TCP";
225 break;
226 case CONN_USB:
227 sConn = "USB";
228 break;
229 #ifdef HDC_SUPPORT_UART
230 case CONN_SERIAL:
231 sConn = "UART";
232 break;
233 #endif
234 case CONN_BT:
235 sConn = "BT";
236 break;
237 default:
238 sConn = "UNKNOW";
239 break;
240 }
241 switch (hdi->connStatus) {
242 case STATUS_READY:
243 sStatus = "Ready";
244 break;
245 case STATUS_CONNECTED:
246 sStatus = "Connected";
247 break;
248 case STATUS_OFFLINE:
249 sStatus = "Offline";
250 break;
251 default:
252 sStatus = "UNKNOW";
253 break;
254 }
255 out = Base::StringFormat("%s\t\t%s\t%s\t%s\n", hdi->connectKey.c_str(), sConn.c_str(), sStatus.c_str(),
256 hdi->devName.c_str());
257 } else {
258 if (hdi->connStatus == STATUS_CONNECTED) {
259 out = Base::StringFormat("%s\n", hdi->connectKey.c_str());
260 }
261 }
262 }
263
GetDaemonMapList(uint8_t opType)264 string HdcServer::GetDaemonMapList(uint8_t opType)
265 {
266 string ret;
267 bool fullDisplay = false;
268 if (opType == OP_GET_STRLIST_FULL) {
269 fullDisplay = true;
270 }
271 uv_rwlock_rdlock(&daemonAdmin);
272 map<string, HDaemonInfo>::iterator iter;
273 string echoLine;
274 for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
275 HDaemonInfo di = iter->second;
276 if (!di) {
277 continue;
278 }
279 echoLine = "";
280 BuildDaemonVisableLine(di, fullDisplay, echoLine);
281 ret += echoLine;
282 }
283 uv_rwlock_rdunlock(&daemonAdmin);
284 return ret;
285 }
286
GetDaemonMapOnlyOne(HDaemonInfo & hDaemonInfoInOut)287 void HdcServer::GetDaemonMapOnlyOne(HDaemonInfo &hDaemonInfoInOut)
288 {
289 uv_rwlock_rdlock(&daemonAdmin);
290 string key;
291 for (auto &i : mapDaemon) {
292 if (i.second->connStatus == STATUS_CONNECTED) {
293 if (key == STRING_EMPTY) {
294 key = i.first;
295 } else {
296 key = STRING_EMPTY;
297 break;
298 }
299 }
300 }
301 if (key.size() > 0) {
302 hDaemonInfoInOut = mapDaemon[key];
303 }
304 uv_rwlock_rdunlock(&daemonAdmin);
305 }
306
AdminDaemonMap(uint8_t opType,const string & connectKey,HDaemonInfo & hDaemonInfoInOut)307 string HdcServer::AdminDaemonMap(uint8_t opType, const string &connectKey, HDaemonInfo &hDaemonInfoInOut)
308 {
309 string sRet;
310 switch (opType) {
311 case OP_ADD: {
312 HDaemonInfo pdiNew = new(std::nothrow) HdcDaemonInformation();
313 if (pdiNew == nullptr) {
314 WRITE_LOG(LOG_FATAL, "AdminDaemonMap new pdiNew failed");
315 break;
316 }
317 *pdiNew = *hDaemonInfoInOut;
318 uv_rwlock_wrlock(&daemonAdmin);
319 if (!mapDaemon[hDaemonInfoInOut->connectKey]) {
320 mapDaemon[hDaemonInfoInOut->connectKey] = pdiNew;
321 }
322 uv_rwlock_wrunlock(&daemonAdmin);
323 break;
324 }
325 case OP_GET_STRLIST:
326 case OP_GET_STRLIST_FULL: {
327 sRet = GetDaemonMapList(opType);
328 break;
329 }
330 case OP_QUERY: {
331 uv_rwlock_rdlock(&daemonAdmin);
332 if (mapDaemon.count(connectKey)) {
333 hDaemonInfoInOut = mapDaemon[connectKey];
334 }
335 uv_rwlock_rdunlock(&daemonAdmin);
336 break;
337 }
338 case OP_REMOVE: {
339 uv_rwlock_wrlock(&daemonAdmin);
340 if (mapDaemon.count(connectKey)) {
341 mapDaemon.erase(connectKey);
342 }
343 uv_rwlock_wrunlock(&daemonAdmin);
344 break;
345 }
346 case OP_GET_ANY: {
347 uv_rwlock_rdlock(&daemonAdmin);
348 map<string, HDaemonInfo>::iterator iter;
349 for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
350 HDaemonInfo di = iter->second;
351 // usb will be auto connected
352 if (di->connStatus == STATUS_READY || di->connStatus == STATUS_CONNECTED) {
353 hDaemonInfoInOut = di;
354 break;
355 }
356 }
357 uv_rwlock_rdunlock(&daemonAdmin);
358 break;
359 }
360 case OP_WAIT_FOR_ANY: {
361 uv_rwlock_rdlock(&daemonAdmin);
362 map<string, HDaemonInfo>::iterator iter;
363 for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
364 HDaemonInfo di = iter->second;
365 if (di->connStatus == STATUS_CONNECTED) {
366 hDaemonInfoInOut = di;
367 break;
368 }
369 }
370 uv_rwlock_rdunlock(&daemonAdmin);
371 break;
372 }
373 case OP_GET_ONLY: {
374 GetDaemonMapOnlyOne(hDaemonInfoInOut);
375 break;
376 }
377 case OP_UPDATE: { // Cannot update the Object HDi lower key value by direct value
378 uv_rwlock_wrlock(&daemonAdmin);
379 HDaemonInfo hdi = mapDaemon[hDaemonInfoInOut->connectKey];
380 if (hdi) {
381 *mapDaemon[hDaemonInfoInOut->connectKey] = *hDaemonInfoInOut;
382 }
383 uv_rwlock_wrunlock(&daemonAdmin);
384 break;
385 }
386 default:
387 break;
388 }
389 return sRet;
390 }
391
NotifyInstanceSessionFree(HSession hSession,bool freeOrClear)392 void HdcServer::NotifyInstanceSessionFree(HSession hSession, bool freeOrClear)
393 {
394 HDaemonInfo hdiOld = nullptr;
395 AdminDaemonMap(OP_QUERY, hSession->connectKey, hdiOld);
396 if (hdiOld == nullptr) {
397 return;
398 }
399 if (!freeOrClear) { // step1
400 // update
401 HdcDaemonInformation diNew = *hdiOld;
402 diNew.connStatus = STATUS_OFFLINE;
403 HDaemonInfo hdiNew = &diNew;
404 AdminDaemonMap(OP_UPDATE, hSession->connectKey, hdiNew);
405 CleanForwardMap(hSession->sessionId);
406 } else { // step2
407 string usbMountPoint = hdiOld->usbMountPoint;
408 // The waiting time must be longer than DEVICE_CHECK_INTERVAL. Wait the method WatchUsbNodeChange
409 // to finish execution. Otherwise, the main thread and the session worker thread will conflict
410 constexpr int waitDaemonReconnect = DEVICE_CHECK_INTERVAL + DEVICE_CHECK_INTERVAL;
411 auto funcDelayUsbNotify = [this, usbMountPoint](const uint8_t flag, string &msg, const void *) -> void {
412 string s = usbMountPoint;
413 clsUSBClt->RemoveIgnoreDevice(s);
414 };
415 if (usbMountPoint.size() > 0) {
416 // wait time for daemon reconnect
417 // If removed from maplist, the USB module will be reconnected, so it needs to wait for a while
418 Base::DelayDoSimple(&loopMain, waitDaemonReconnect, funcDelayUsbNotify);
419 }
420 }
421 }
422
HandServerAuth(HSession hSession,SessionHandShake & handshake)423 bool HdcServer::HandServerAuth(HSession hSession, SessionHandShake &handshake)
424 {
425 bool ret = false;
426 int retChild = 0;
427 string bufString;
428 switch (handshake.authType) {
429 case AUTH_TOKEN: {
430 void *ptr = nullptr;
431 bool retChildForToken = HdcAuth::KeylistIncrement(hSession->listKey, hSession->authKeyIndex, &ptr);
432 // HdcAuth::FreeKey will be effect at function 'FreeSession'
433 if (!retChildForToken) {
434 // Iteration call certificate authentication
435 handshake.authType = AUTH_PUBLICKEY;
436 ret = HandServerAuth(hSession, handshake);
437 break;
438 }
439 char sign[BUF_SIZE_DEFAULT2] = { 0 };
440 retChildForToken = HdcAuth::AuthSign(ptr, reinterpret_cast<const unsigned char *>(handshake.buf.c_str()),
441 handshake.buf.size(), sign);
442 if (!retChildForToken) {
443 break;
444 }
445 handshake.buf = string(sign, retChildForToken);
446 handshake.authType = AUTH_SIGNATURE;
447 bufString = SerialStruct::SerializeToString(handshake);
448 Send(hSession->sessionId, 0, CMD_KERNEL_HANDSHAKE,
449 reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
450 ret = true;
451 break;
452 }
453 case AUTH_PUBLICKEY: {
454 char bufPrivateKey[BUF_SIZE_DEFAULT2] = "";
455 retChild = HdcAuth::GetPublicKeyFileBuf(reinterpret_cast<unsigned char *>(bufPrivateKey),
456 sizeof(bufPrivateKey));
457 if (!retChild) {
458 break;
459 }
460 handshake.buf = string(bufPrivateKey, retChild);
461 handshake.authType = AUTH_PUBLICKEY;
462 bufString = SerialStruct::SerializeToString(handshake);
463 Send(hSession->sessionId, 0, CMD_KERNEL_HANDSHAKE,
464 reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
465 ret = true;
466 break;
467 }
468 default:
469 break;
470 }
471 return ret;
472 }
473
ServerSessionHandshake(HSession hSession,uint8_t * payload,int payloadSize)474 bool HdcServer::ServerSessionHandshake(HSession hSession, uint8_t *payload, int payloadSize)
475 {
476 // session handshake step3
477 string s = string(reinterpret_cast<char *>(payload), payloadSize);
478 Hdc::HdcSessionBase::SessionHandShake handshake;
479 SerialStruct::ParseFromString(handshake, s);
480 #ifdef HDC_DEBUG
481 WRITE_LOG(LOG_DEBUG, "handshake.banner:%s, payload:%s(%d)", handshake.banner.c_str(), s.c_str(), payloadSize);
482 #endif
483
484 if (handshake.banner == HANDSHAKE_FAILED.c_str()) {
485 WRITE_LOG(LOG_FATAL, "Handshake failed");
486 return false;
487 }
488
489 if (handshake.banner != HANDSHAKE_MESSAGE.c_str()) {
490 WRITE_LOG(LOG_DEBUG, "Hello failed");
491 return false;
492 }
493 if (handshake.authType != AUTH_OK) {
494 if (!HandServerAuth(hSession, handshake)) {
495 WRITE_LOG(LOG_DEBUG, "Auth failed");
496 return false;
497 }
498 return true;
499 }
500 // handshake auth OK
501 HDaemonInfo hdiOld = nullptr;
502 AdminDaemonMap(OP_QUERY, hSession->connectKey, hdiOld);
503 if (!hdiOld) {
504 return false;
505 }
506 HdcDaemonInformation diNew = *hdiOld;
507 HDaemonInfo hdiNew = &diNew;
508 // update
509 hdiNew->connStatus = STATUS_CONNECTED;
510 if (handshake.buf.size() > sizeof(hdiNew->devName) || !handshake.buf.size()) {
511 hdiNew->devName = "unknown...";
512 } else {
513 hdiNew->devName = handshake.buf;
514 }
515 WRITE_LOG(LOG_INFO, "handshake.version = %s", handshake.version.c_str());
516 hdiNew->version = handshake.version;
517 AdminDaemonMap(OP_UPDATE, hSession->connectKey, hdiNew);
518 hSession->handshakeOK = true;
519 return true;
520 }
521
522 // call in child thread
FetchCommand(HSession hSession,const uint32_t channelId,const uint16_t command,uint8_t * payload,const int payloadSize)523 bool HdcServer::FetchCommand(HSession hSession, const uint32_t channelId, const uint16_t command, uint8_t *payload,
524 const int payloadSize)
525 {
526 bool ret = true;
527 HdcServerForClient *sfc = static_cast<HdcServerForClient *>(clsServerForClient);
528 if (command == CMD_KERNEL_HANDSHAKE) {
529 ret = ServerSessionHandshake(hSession, payload, payloadSize);
530 WRITE_LOG(LOG_DEBUG, "Session handshake %s connType:%d", ret ? "successful" : "failed",
531 hSession->connType);
532 return ret;
533 }
534 // When you first initialize, ChannelID may be 0
535 HChannel hChannel = sfc->AdminChannel(OP_QUERY_REF, channelId, nullptr);
536 if (!hChannel) {
537 if (command == CMD_KERNEL_CHANNEL_CLOSE) {
538 // Daemon close channel and want to notify server close channel also, but it may has been
539 // closed by herself
540 WRITE_LOG(LOG_DEBUG, "Die channelId :%lu recv CMD_KERNEL_CHANNEL_CLOSE", channelId);
541 } else {
542 // Client may be ctrl+c and Server remove channel. notify server async
543 WRITE_LOG(LOG_DEBUG, "channelId :%lu die", channelId);
544 }
545 uint8_t flag = 0;
546 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &flag, 1);
547 return ret;
548 }
549 if (hChannel->isDead) {
550 --hChannel->ref;
551 return ret;
552 }
553 switch (command) {
554 case CMD_KERNEL_ECHO_RAW: { // Native shell data output
555 sfc->EchoClientRaw(hChannel, payload, payloadSize);
556 break;
557 }
558 case CMD_KERNEL_ECHO: {
559 MessageLevel level = static_cast<MessageLevel>(*payload);
560 string s(reinterpret_cast<char *>(payload + 1), payloadSize - 1);
561 sfc->EchoClient(hChannel, level, s.c_str());
562 WRITE_LOG(LOG_DEBUG, "CMD_KERNEL_ECHO size:%d", payloadSize - 1);
563 break;
564 }
565 case CMD_KERNEL_CHANNEL_CLOSE: {
566 WRITE_LOG(LOG_DEBUG, "CMD_KERNEL_CHANNEL_CLOSE channelid:%u", channelId);
567 // Forcibly closing the tcp handle here may result in incomplete data reception on the client side
568 ClearOwnTasks(hSession, channelId);
569 // crossthread free
570 sfc->PushAsyncMessage(channelId, ASYNC_FREE_CHANNEL, nullptr, 0);
571 if (*payload != 0) {
572 --(*payload);
573 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, payload, 1);
574 }
575 break;
576 }
577 case CMD_FORWARD_SUCCESS: {
578 // add to local
579 HdcForwardInformation di;
580 HForwardInfo pdiNew = &di;
581 pdiNew->channelId = channelId;
582 pdiNew->sessionId = hSession->sessionId;
583 pdiNew->forwardDirection = (reinterpret_cast<char *>(payload))[0] == '1';
584 pdiNew->taskString = reinterpret_cast<char *>(payload) + 2;
585 AdminForwardMap(OP_ADD, STRING_EMPTY, pdiNew);
586 Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP); // detch client channel
587 break;
588 }
589 case CMD_FILE_INIT:
590 case CMD_FILE_CHECK:
591 case CMD_FILE_BEGIN:
592 case CMD_FILE_DATA:
593 case CMD_FILE_FINISH:
594 case CMD_FILE_MODE:
595 case CMD_DIR_MODE:
596 case CMD_APP_INIT:
597 case CMD_APP_CHECK:
598 case CMD_APP_BEGIN:
599 case CMD_APP_DATA:
600 case CMD_APP_FINISH:
601 if (hChannel->fromClient) {
602 // server directly passthrough app command to client if remote file mode, else go default
603 WRITE_LOG(LOG_DEBUG, "command passthrough to client command:%u channelId:%u", command, channelId);
604 sfc->SendCommandToClient(hChannel, command, payload, payloadSize);
605 break;
606 }
607 default: {
608 HSession hSessionByQuery = AdminSession(OP_QUERY, hChannel->targetSessionId, nullptr);
609 if (!hSessionByQuery) {
610 ret = false;
611 break;
612 }
613 ret = DispatchTaskData(hSessionByQuery, channelId, command, payload, payloadSize);
614 break;
615 }
616 }
617 --hChannel->ref;
618 return ret;
619 }
620
BuildForwardVisableLine(bool fullOrSimble,HForwardInfo hfi,string & echo)621 void HdcServer::BuildForwardVisableLine(bool fullOrSimble, HForwardInfo hfi, string &echo)
622 {
623 string buf;
624 if (fullOrSimble) {
625 buf = Base::StringFormat("'%s'\t%s\n", hfi->taskString.c_str(),
626 hfi->forwardDirection ? "[Forward]" : "[Reverse]");
627 } else {
628 buf = Base::StringFormat("%s\n", hfi->taskString.c_str());
629 }
630 echo += buf;
631 }
632
AdminForwardMap(uint8_t opType,const string & taskString,HForwardInfo & hForwardInfoInOut)633 string HdcServer::AdminForwardMap(uint8_t opType, const string &taskString, HForwardInfo &hForwardInfoInOut)
634 {
635 string sRet;
636 switch (opType) {
637 case OP_ADD: {
638 HForwardInfo pfiNew = new(std::nothrow) HdcForwardInformation();
639 if (pfiNew == nullptr) {
640 WRITE_LOG(LOG_FATAL, "AdminForwardMap new pfiNew failed");
641 break;
642 }
643 *pfiNew = *hForwardInfoInOut;
644 uv_rwlock_wrlock(&forwardAdmin);
645 if (!mapForward[hForwardInfoInOut->taskString]) {
646 mapForward[hForwardInfoInOut->taskString] = pfiNew;
647 }
648 uv_rwlock_wrunlock(&forwardAdmin);
649 break;
650 }
651 case OP_GET_STRLIST:
652 case OP_GET_STRLIST_FULL: {
653 uv_rwlock_rdlock(&forwardAdmin);
654 map<string, HForwardInfo>::iterator iter;
655 for (iter = mapForward.begin(); iter != mapForward.end(); ++iter) {
656 HForwardInfo di = iter->second;
657 if (!di) {
658 continue;
659 }
660 BuildForwardVisableLine(opType == OP_GET_STRLIST_FULL, di, sRet);
661 }
662 uv_rwlock_rdunlock(&forwardAdmin);
663 break;
664 }
665 case OP_QUERY: {
666 uv_rwlock_rdlock(&forwardAdmin);
667 if (mapForward.count(taskString)) {
668 hForwardInfoInOut = mapForward[taskString];
669 }
670 uv_rwlock_rdunlock(&forwardAdmin);
671 break;
672 }
673 case OP_REMOVE: {
674 uv_rwlock_wrlock(&forwardAdmin);
675 if (mapForward.count(taskString)) {
676 mapForward.erase(taskString);
677 }
678 uv_rwlock_wrunlock(&forwardAdmin);
679 break;
680 }
681 default:
682 break;
683 }
684 return sRet;
685 }
686
CleanForwardMap(uint32_t sessionId)687 void HdcServer::CleanForwardMap(uint32_t sessionId)
688 {
689 uv_rwlock_rdlock(&forwardAdmin);
690 map<string, HForwardInfo>::iterator iter;
691 for (iter = mapForward.begin(); iter != mapForward.end();) {
692 HForwardInfo di = iter->second;
693 if (!di) {
694 continue;
695 }
696 if (sessionId == 0 || sessionId == di->sessionId) {
697 iter = mapForward.erase(iter);
698 } else {
699 iter++;
700 }
701 }
702 uv_rwlock_rdunlock(&forwardAdmin);
703 }
704
UsbPreConnect(uv_timer_t * handle)705 void HdcServer::UsbPreConnect(uv_timer_t *handle)
706 {
707 HSession hSession = (HSession)handle->data;
708 bool stopLoop = false;
709 HdcServer *hdcServer = (HdcServer *)hSession->classInstance;
710 const int usbConnectRetryMax = 5;
711 while (true) {
712 WRITE_LOG(LOG_DEBUG, "HdcServer::UsbPreConnect");
713 if (++hSession->hUSB->retryCount > usbConnectRetryMax) { // max 15s
714 hdcServer->FreeSession(hSession->sessionId);
715 stopLoop = true;
716 break;
717 }
718 HDaemonInfo pDi = nullptr;
719 if (hSession->connectKey == "any") {
720 hdcServer->AdminDaemonMap(OP_GET_ANY, hSession->connectKey, pDi);
721 } else {
722 hdcServer->AdminDaemonMap(OP_QUERY, hSession->connectKey, pDi);
723 }
724 if (!pDi || !pDi->usbMountPoint.size()) {
725 break;
726 }
727 HdcHostUSB *hdcHostUSB = (HdcHostUSB *)hSession->classModule;
728 hdcHostUSB->ConnectDetectDaemon(hSession, pDi);
729 stopLoop = true;
730 break;
731 }
732 if (stopLoop && !uv_is_closing((const uv_handle_t *)handle)) {
733 uv_close((uv_handle_t *)handle, Base::CloseTimerCallback);
734 }
735 }
736 #ifdef HDC_SUPPORT_UART
UartPreConnect(uv_timer_t * handle)737 void HdcServer::UartPreConnect(uv_timer_t *handle)
738 {
739 WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__);
740 HSession hSession = (HSession)handle->data;
741 bool stopLoop = false;
742 HdcServer *hdcServer = (HdcServer *)hSession->classInstance;
743 const int uartConnectRetryMax = 100; // max 6s
744 while (true) {
745 if (hSession->hUART->retryCount > uartConnectRetryMax) {
746 WRITE_LOG(LOG_DEBUG, "%s failed because max retry limit %d", __FUNCTION__,
747 hSession->hUART->retryCount);
748 hdcServer->FreeSession(hSession->sessionId);
749 stopLoop = true;
750 break;
751 }
752 hSession->hUART->retryCount++;
753 HDaemonInfo pDi = nullptr;
754
755 WRITE_LOG(LOG_DEBUG, "%s query %s", __FUNCTION__, hSession->ToDebugString().c_str());
756 hdcServer->AdminDaemonMap(OP_QUERY, hSession->connectKey, pDi);
757 if (!pDi) {
758 WRITE_LOG(LOG_DEBUG, "%s not found", __FUNCTION__);
759 break;
760 }
761 HdcHostUART *hdcHostUART = (HdcHostUART *)hSession->classModule;
762 hdcHostUART->ConnectDaemonByUart(hSession, pDi);
763 WRITE_LOG(LOG_DEBUG, "%s ConnectDaemonByUart done", __FUNCTION__);
764
765 stopLoop = true;
766 break;
767 }
768 if (stopLoop) {
769 uv_close((uv_handle_t *)handle, Base::CloseTimerCallback);
770 }
771 }
772
CreatConnectUart(HSession hSession)773 void HdcServer::CreatConnectUart(HSession hSession)
774 {
775 uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
776 if (waitTimeDoCmd == nullptr) {
777 WRITE_LOG(LOG_FATAL, "CreatConnectUart new waitTimeDoCmd failed");
778 return;
779 }
780 uv_timer_init(&loopMain, waitTimeDoCmd);
781 waitTimeDoCmd->data = hSession;
782 uv_timer_start(waitTimeDoCmd, UartPreConnect, UV_TIMEOUT, UV_REPEAT);
783 }
784 #endif
785 // -1,has old,-2 error
CreateConnect(const string & connectKey,bool isCheck)786 int HdcServer::CreateConnect(const string &connectKey, bool isCheck)
787 {
788 uint8_t connType = 0;
789 if (connectKey.find(":") != std::string::npos) { // TCP
790 connType = CONN_TCP;
791 }
792 #ifdef HDC_SUPPORT_UART
793 else if (connectKey.find("COM") == 0 ||
794 connectKey.find("/dev/ttyUSB") == 0 ||
795 connectKey.find("/dev/cu.") == 0) { // UART
796 connType = CONN_SERIAL;
797 }
798 #endif
799 else { // USB
800 connType = CONN_USB;
801 }
802 HDaemonInfo hdi = nullptr;
803 if (connectKey == "any") {
804 return RET_SUCCESS;
805 }
806 AdminDaemonMap(OP_QUERY, connectKey, hdi);
807 if (hdi == nullptr) {
808 HdcDaemonInformation di = {};
809 di.connectKey = connectKey;
810 di.connType = connType;
811 di.connStatus = STATUS_UNKNOW;
812 HDaemonInfo pDi = reinterpret_cast<HDaemonInfo>(&di);
813 AdminDaemonMap(OP_ADD, "", pDi);
814 AdminDaemonMap(OP_QUERY, connectKey, hdi);
815 }
816 if (!hdi || hdi->connStatus == STATUS_CONNECTED) {
817 WRITE_LOG(LOG_FATAL, "Connected return");
818 return ERR_GENERIC;
819 }
820 HSession hSession = nullptr;
821 if (connType == CONN_TCP) {
822 hSession = clsTCPClt->ConnectDaemon(connectKey, isCheck);
823 } else if (connType == CONN_SERIAL) {
824 #ifdef HDC_SUPPORT_UART
825 clsUARTClt->SetCheckFlag(isCheck);
826 hSession = clsUARTClt->ConnectDaemon(connectKey);
827 #endif
828 } else {
829 hSession = MallocSession(true, CONN_USB, clsUSBClt);
830 hSession->connectKey = connectKey;
831 uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
832 if (waitTimeDoCmd == nullptr) {
833 WRITE_LOG(LOG_FATAL, "CreateConnect new waitTimeDoCmd failed");
834 return ERR_GENERIC;
835 }
836 uv_timer_init(&loopMain, waitTimeDoCmd);
837 waitTimeDoCmd->data = hSession;
838 uv_timer_start(waitTimeDoCmd, UsbPreConnect, 10, 100);
839 }
840 if (!hSession) {
841 return ERR_BUF_ALLOC;
842 }
843 HDaemonInfo hdiQuery = nullptr;
844 AdminDaemonMap(OP_QUERY, connectKey, hdiQuery);
845 if (hdiQuery) {
846 HdcDaemonInformation diNew = *hdiQuery;
847 diNew.hSession = hSession;
848 HDaemonInfo hdiNew = &diNew;
849 AdminDaemonMap(OP_UPDATE, hdiQuery->connectKey, hdiNew);
850 }
851 return RET_SUCCESS;
852 }
853
AttachChannel(HSession hSession,const uint32_t channelId)854 void HdcServer::AttachChannel(HSession hSession, const uint32_t channelId)
855 {
856 int ret = 0;
857 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
858 HChannel hChannel = hSfc->AdminChannel(OP_QUERY_REF, channelId, nullptr);
859 if (!hChannel) {
860 return;
861 }
862 uv_tcp_init(&hSession->childLoop, &hChannel->hChildWorkTCP);
863 hChannel->hChildWorkTCP.data = hChannel;
864 hChannel->targetSessionId = hSession->sessionId;
865 if ((ret = uv_tcp_open((uv_tcp_t *)&hChannel->hChildWorkTCP, hChannel->fdChildWorkTCP)) < 0) {
866 constexpr int bufSize = 1024;
867 char buf[bufSize] = { 0 };
868 uv_err_name_r(ret, buf, bufSize);
869 WRITE_LOG(LOG_DEBUG, "Hdcserver AttachChannel uv_tcp_open failed %s, channelid:%d fdChildWorkTCP:%d",
870 buf, hChannel->channelId, hChannel->fdChildWorkTCP);
871 Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP);
872 --hChannel->ref;
873 return;
874 }
875 Base::SetTcpOptions((uv_tcp_t *)&hChannel->hChildWorkTCP);
876 uv_read_start((uv_stream_t *)&hChannel->hChildWorkTCP, hSfc->AllocCallback, hSfc->ReadStream);
877 --hChannel->ref;
878 };
879
DeatchChannel(HSession hSession,const uint32_t channelId)880 void HdcServer::DeatchChannel(HSession hSession, const uint32_t channelId)
881 {
882 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
883 // childCleared has not set, no need OP_QUERY_REF
884 HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr);
885 if (!hChannel) {
886 return;
887 }
888 if (hChannel->childCleared) {
889 WRITE_LOG(LOG_DEBUG, "Childchannel has already freed, cid:%u", channelId);
890 return;
891 }
892 // The own task for this channel must be clear before free channel
893 ClearOwnTasks(hSession, channelId);
894 uint8_t count = 0;
895 Send(hSession->sessionId, hChannel->channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
896 if (uv_is_closing((const uv_handle_t *)&hChannel->hChildWorkTCP)) {
897 Base::DoNextLoop(&hSession->childLoop, hChannel, [](const uint8_t flag, string &msg, const void *data) {
898 HChannel hChannel = (HChannel)data;
899 hChannel->childCleared = true;
900 WRITE_LOG(LOG_DEBUG, "Childchannel free direct, cid:%u", hChannel->channelId);
901 });
902 } else {
903 Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP, [](uv_handle_t *handle) -> void {
904 HChannel hChannel = (HChannel)handle->data;
905 hChannel->childCleared = true;
906 WRITE_LOG(LOG_DEBUG, "Childchannel free callback, cid:%u", hChannel->channelId);
907 });
908 }
909 };
910
ServerCommand(const uint32_t sessionId,const uint32_t channelId,const uint16_t command,uint8_t * bufPtr,const int size)911 bool HdcServer::ServerCommand(const uint32_t sessionId, const uint32_t channelId, const uint16_t command,
912 uint8_t *bufPtr, const int size)
913 {
914 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
915 HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr);
916 HSession hSession = AdminSession(OP_QUERY, sessionId, nullptr);
917 if (!hChannel || !hSession) {
918 return false;
919 }
920 return FetchCommand(hSession, channelId, command, bufPtr, size);
921 }
922
923 // clang-format off
RedirectToTask(HTaskInfo hTaskInfo,HSession hSession,const uint32_t channelId,const uint16_t command,uint8_t * payload,const int payloadSize)924 bool HdcServer::RedirectToTask(HTaskInfo hTaskInfo, HSession hSession, const uint32_t channelId,
925 const uint16_t command, uint8_t *payload, const int payloadSize)
926 // clang-format on
927 {
928 bool ret = true;
929 hTaskInfo->ownerSessionClass = this;
930 switch (command) {
931 case CMD_UNITY_BUGREPORT_INIT:
932 case CMD_UNITY_BUGREPORT_DATA:
933 ret = TaskCommandDispatch<HdcHostUnity>(hTaskInfo, TYPE_UNITY, command, payload, payloadSize);
934 break;
935 case CMD_FILE_INIT:
936 case CMD_FILE_BEGIN:
937 case CMD_FILE_CHECK:
938 case CMD_FILE_DATA:
939 case CMD_FILE_FINISH:
940 case CMD_FILE_MODE:
941 case CMD_DIR_MODE:
942 ret = TaskCommandDispatch<HdcFile>(hTaskInfo, TASK_FILE, command, payload, payloadSize);
943 break;
944 case CMD_FORWARD_INIT:
945 case CMD_FORWARD_CHECK:
946 case CMD_FORWARD_CHECK_RESULT:
947 case CMD_FORWARD_ACTIVE_MASTER:
948 case CMD_FORWARD_ACTIVE_SLAVE:
949 case CMD_FORWARD_DATA:
950 case CMD_FORWARD_FREE_CONTEXT:
951 ret = TaskCommandDispatch<HdcHostForward>(hTaskInfo, TASK_FORWARD, command, payload, payloadSize);
952 break;
953 case CMD_APP_INIT:
954 case CMD_APP_SIDELOAD:
955 case CMD_APP_BEGIN:
956 case CMD_APP_FINISH:
957 case CMD_APP_UNINSTALL:
958 ret = TaskCommandDispatch<HdcHostApp>(hTaskInfo, TASK_APP, command, payload, payloadSize);
959 break;
960 case CMD_FLASHD_UPDATE_INIT:
961 case CMD_FLASHD_FLASH_INIT:
962 case CMD_FLASHD_CHECK:
963 case CMD_FLASHD_BEGIN:
964 case CMD_FLASHD_DATA:
965 case CMD_FLASHD_FINISH:
966 case CMD_FLASHD_ERASE:
967 case CMD_FLASHD_FORMAT:
968 case CMD_FLASHD_PROGRESS:
969 ret = TaskCommandDispatch<HostUpdater>(hTaskInfo, TASK_FLASHD, command, payload, payloadSize);
970 break;
971 default:
972 // ignore unknown command
973 break;
974 }
975 return ret;
976 }
977
RemoveInstanceTask(const uint8_t op,HTaskInfo hTask)978 bool HdcServer::RemoveInstanceTask(const uint8_t op, HTaskInfo hTask)
979 {
980 bool ret = true;
981 switch (hTask->taskType) {
982 case TYPE_SHELL:
983 WRITE_LOG(LOG_DEBUG, "Server not enable unity/shell");
984 break;
985 case TYPE_UNITY:
986 ret = DoTaskRemove<HdcHostUnity>(hTask, op);
987 break;
988 case TASK_FILE:
989 ret = DoTaskRemove<HdcFile>(hTask, op);
990 break;
991 case TASK_FORWARD:
992 ret = DoTaskRemove<HdcHostForward>(hTask, op);
993 break;
994 case TASK_APP:
995 ret = DoTaskRemove<HdcHostApp>(hTask, op);
996 break;
997 case TASK_FLASHD:
998 ret = DoTaskRemove<HostUpdater>(hTask, op);
999 break;
1000 default:
1001 ret = false;
1002 break;
1003 }
1004 return ret;
1005 }
1006
EchoToClientsForSession(uint32_t targetSessionId,const string & echo)1007 void HdcServer::EchoToClientsForSession(uint32_t targetSessionId, const string &echo)
1008 {
1009 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
1010 WRITE_LOG(LOG_INFO, "%s:%u %s", __FUNCTION__, targetSessionId, echo.c_str());
1011 hSfc->EchoToAllChannelsViaSessionId(targetSessionId, echo);
1012 }
1013 } // namespace Hdc
1014