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