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