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