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::GetLogLevelByEnv(), 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, false, 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 = conTypeDetail[CONN_UNKNOWN];
226 if (hdi->connType < CONN_UNKNOWN) {
227 sConn = conTypeDetail[hdi->connType];
228 }
229
230 string sStatus = conStatusDetail[STATUS_UNKNOW];
231 if (hdi->connStatus < STATUS_UNAUTH) {
232 if (hdi->connStatus == STATUS_CONNECTED && hdi->daemonAuthStatus == DAEOMN_UNAUTHORIZED) {
233 sStatus = conStatusDetail[STATUS_UNAUTH];
234 } else {
235 sStatus = conStatusDetail[hdi->connStatus];
236 }
237 }
238
239 string devname = hdi->devName;
240 if (devname.empty()) {
241 devname = "unknown...";
242 }
243 out = Base::StringFormat("%s\t\t%s\t%s\t%s\n", hdi->connectKey.c_str(), sConn.c_str(), sStatus.c_str(),
244 devname.c_str());
245 } else {
246 if (hdi->connStatus == STATUS_CONNECTED) {
247 out = Base::StringFormat("%s", hdi->connectKey.c_str());
248 if (hdi->daemonAuthStatus == DAEOMN_UNAUTHORIZED) {
249 out.append("\tUnauthorized");
250 }
251 out.append("\n");
252 }
253 }
254 }
255
GetDaemonMapList(uint8_t opType)256 string HdcServer::GetDaemonMapList(uint8_t opType)
257 {
258 string ret;
259 bool fullDisplay = false;
260 if (opType == OP_GET_STRLIST_FULL) {
261 fullDisplay = true;
262 }
263 uv_rwlock_rdlock(&daemonAdmin);
264 map<string, HDaemonInfo>::iterator iter;
265 string echoLine;
266 for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
267 HDaemonInfo di = iter->second;
268 if (!di) {
269 continue;
270 }
271 echoLine = "";
272 BuildDaemonVisableLine(di, fullDisplay, echoLine);
273 ret += echoLine;
274 }
275 uv_rwlock_rdunlock(&daemonAdmin);
276 return ret;
277 }
278
GetDaemonMapOnlyOne(HDaemonInfo & hDaemonInfoInOut)279 void HdcServer::GetDaemonMapOnlyOne(HDaemonInfo &hDaemonInfoInOut)
280 {
281 uv_rwlock_rdlock(&daemonAdmin);
282 string key;
283 for (auto &i : mapDaemon) {
284 if (i.second->connStatus == STATUS_CONNECTED) {
285 if (key == STRING_EMPTY) {
286 key = i.first;
287 } else {
288 key = STRING_EMPTY;
289 break;
290 }
291 }
292 }
293 if (key.size() > 0) {
294 hDaemonInfoInOut = mapDaemon[key];
295 }
296 uv_rwlock_rdunlock(&daemonAdmin);
297 }
298
AdminDaemonMap(uint8_t opType,const string & connectKey,HDaemonInfo & hDaemonInfoInOut)299 string HdcServer::AdminDaemonMap(uint8_t opType, const string &connectKey, HDaemonInfo &hDaemonInfoInOut)
300 {
301 string sRet;
302 switch (opType) {
303 case OP_ADD: {
304 HDaemonInfo pdiNew = new(std::nothrow) HdcDaemonInformation();
305 if (pdiNew == nullptr) {
306 WRITE_LOG(LOG_FATAL, "AdminDaemonMap new pdiNew failed");
307 break;
308 }
309 *pdiNew = *hDaemonInfoInOut;
310 uv_rwlock_wrlock(&daemonAdmin);
311 if (!mapDaemon[hDaemonInfoInOut->connectKey]) {
312 mapDaemon[hDaemonInfoInOut->connectKey] = pdiNew;
313 }
314 uv_rwlock_wrunlock(&daemonAdmin);
315 break;
316 }
317 case OP_GET_STRLIST:
318 case OP_GET_STRLIST_FULL: {
319 sRet = GetDaemonMapList(opType);
320 break;
321 }
322 case OP_QUERY: {
323 uv_rwlock_rdlock(&daemonAdmin);
324 if (mapDaemon.count(connectKey)) {
325 hDaemonInfoInOut = mapDaemon[connectKey];
326 }
327 uv_rwlock_rdunlock(&daemonAdmin);
328 break;
329 }
330 case OP_REMOVE: {
331 uv_rwlock_wrlock(&daemonAdmin);
332 if (mapDaemon.count(connectKey)) {
333 mapDaemon.erase(connectKey);
334 }
335 uv_rwlock_wrunlock(&daemonAdmin);
336 break;
337 }
338 case OP_GET_ANY: {
339 uv_rwlock_rdlock(&daemonAdmin);
340 map<string, HDaemonInfo>::iterator iter;
341 for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
342 HDaemonInfo di = iter->second;
343 // usb will be auto connected
344 if (di->connStatus == STATUS_READY || di->connStatus == STATUS_CONNECTED) {
345 hDaemonInfoInOut = di;
346 break;
347 }
348 }
349 uv_rwlock_rdunlock(&daemonAdmin);
350 break;
351 }
352 case OP_WAIT_FOR_ANY: {
353 uv_rwlock_rdlock(&daemonAdmin);
354 map<string, HDaemonInfo>::iterator iter;
355 for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
356 HDaemonInfo di = iter->second;
357 if (di->connStatus == STATUS_CONNECTED) {
358 hDaemonInfoInOut = di;
359 break;
360 }
361 }
362 uv_rwlock_rdunlock(&daemonAdmin);
363 break;
364 }
365 case OP_GET_ONLY: {
366 GetDaemonMapOnlyOne(hDaemonInfoInOut);
367 break;
368 }
369 case OP_UPDATE: { // Cannot update the Object HDi lower key value by direct value
370 uv_rwlock_wrlock(&daemonAdmin);
371 HDaemonInfo hdi = mapDaemon[hDaemonInfoInOut->connectKey];
372 if (hdi) {
373 *mapDaemon[hDaemonInfoInOut->connectKey] = *hDaemonInfoInOut;
374 }
375 uv_rwlock_wrunlock(&daemonAdmin);
376 break;
377 }
378 default:
379 break;
380 }
381 return sRet;
382 }
383
NotifyInstanceSessionFree(HSession hSession,bool freeOrClear)384 void HdcServer::NotifyInstanceSessionFree(HSession hSession, bool freeOrClear)
385 {
386 HDaemonInfo hdiOld = nullptr;
387 AdminDaemonMap(OP_QUERY, hSession->connectKey, hdiOld);
388 if (hdiOld == nullptr) {
389 WRITE_LOG(LOG_FATAL, "NotifyInstanceSessionFree hdiOld nullptr");
390 return;
391 }
392 if (!freeOrClear) { // step1
393 // update
394 HdcDaemonInformation diNew = *hdiOld;
395 diNew.connStatus = STATUS_OFFLINE;
396 HDaemonInfo hdiNew = &diNew;
397 AdminDaemonMap(OP_UPDATE, hSession->connectKey, hdiNew);
398 CleanForwardMap(hSession->sessionId);
399 } else { // step2
400 string usbMountPoint = hdiOld->usbMountPoint;
401 // The waiting time must be longer than DEVICE_CHECK_INTERVAL. Wait the method WatchUsbNodeChange
402 // to finish execution. Otherwise, the main thread and the session worker thread will conflict
403 constexpr int waitDaemonReconnect = DEVICE_CHECK_INTERVAL + DEVICE_CHECK_INTERVAL;
404 auto funcDelayUsbNotify = [this, usbMountPoint](const uint8_t flag, string &msg, const void *) -> void {
405 string s = usbMountPoint;
406 clsUSBClt->RemoveIgnoreDevice(s);
407 };
408 if (usbMountPoint.size() > 0) {
409 // wait time for daemon reconnect
410 // If removed from maplist, the USB module will be reconnected, so it needs to wait for a while
411 Base::DelayDoSimple(&loopMain, waitDaemonReconnect, funcDelayUsbNotify);
412 }
413 }
414 }
415
HandServerAuth(HSession hSession,SessionHandShake & handshake)416 bool HdcServer::HandServerAuth(HSession hSession, SessionHandShake &handshake)
417 {
418 string bufString;
419 switch (handshake.authType) {
420 case AUTH_PUBLICKEY: {
421 WRITE_LOG(LOG_INFO, "recive get publickey cmd");
422 if (!HdcAuth::GetPublicKeyinfo(handshake.buf)) {
423 WRITE_LOG(LOG_FATAL, "load public key failed");
424 return false;
425 }
426 handshake.authType = AUTH_PUBLICKEY;
427 bufString = SerialStruct::SerializeToString(handshake);
428 Send(hSession->sessionId, 0, CMD_KERNEL_HANDSHAKE,
429 reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
430
431 WRITE_LOG(LOG_INFO, "send pubkey over");
432 return true;
433 }
434 case AUTH_SIGNATURE: {
435 WRITE_LOG(LOG_INFO, "recive auth signture cmd");
436 if (!HdcAuth::RsaSignAndBase64(handshake.buf)) {
437 WRITE_LOG(LOG_FATAL, "sign failed");
438 return false;
439 }
440 handshake.authType = AUTH_SIGNATURE;
441 bufString = SerialStruct::SerializeToString(handshake);
442 Send(hSession->sessionId, 0, CMD_KERNEL_HANDSHAKE,
443 reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
444 WRITE_LOG(LOG_INFO, "response auth signture success");
445 return true;
446 }
447 default:
448 WRITE_LOG(LOG_FATAL, "invalid auth type %d", handshake.authType);
449 return false;
450 }
451 }
452
UpdateHdiInfo(Hdc::HdcSessionBase::SessionHandShake & handshake,const string & connectKey)453 void HdcServer::UpdateHdiInfo(Hdc::HdcSessionBase::SessionHandShake &handshake, const string &connectKey)
454 {
455 HDaemonInfo hdiOld = nullptr;
456 AdminDaemonMap(OP_QUERY, connectKey, hdiOld);
457 if (!hdiOld) {
458 return;
459 }
460 HdcDaemonInformation diNew = *hdiOld;
461 HDaemonInfo hdiNew = &diNew;
462 // update
463 hdiNew->connStatus = STATUS_CONNECTED;
464 WRITE_LOG(LOG_INFO, "handshake info is : %s", handshake.ToDebugString().c_str());
465 WRITE_LOG(LOG_INFO, "handshake.buf = %s", handshake.buf.c_str());
466 if (handshake.version < "Ver: 3.0.0b") {
467 if (!handshake.buf.empty()) {
468 hdiNew->devName = handshake.buf;
469 }
470 } else {
471 std::map<string, string> tlvmap;
472 if (Base::TlvToStringMap(handshake.buf, tlvmap)) {
473 if (tlvmap.find(TAG_DEVNAME) != tlvmap.end()) {
474 hdiNew->devName = tlvmap[TAG_DEVNAME];
475 WRITE_LOG(LOG_INFO, "devname = %s", hdiNew->devName.c_str());
476 }
477 if (tlvmap.find(TAG_EMGMSG) != tlvmap.end()) {
478 hdiNew->emgmsg = tlvmap[TAG_EMGMSG];
479 WRITE_LOG(LOG_INFO, "emgmsg = %s", hdiNew->emgmsg.c_str());
480 }
481 if (tlvmap.find(TAG_DAEOMN_AUTHSTATUS) != tlvmap.end()) {
482 hdiNew->daemonAuthStatus = tlvmap[TAG_DAEOMN_AUTHSTATUS];
483 WRITE_LOG(LOG_INFO, "daemonauthstatus = %s", hdiNew->daemonAuthStatus.c_str());
484 }
485 } else {
486 WRITE_LOG(LOG_FATAL, "TlvToStringMap failed");
487 }
488 }
489 hdiNew->version = handshake.version;
490 AdminDaemonMap(OP_UPDATE, connectKey, hdiNew);
491 }
492
ServerSessionHandshake(HSession hSession,uint8_t * payload,int payloadSize)493 bool HdcServer::ServerSessionHandshake(HSession hSession, uint8_t *payload, int payloadSize)
494 {
495 // session handshake step3
496 string s = string(reinterpret_cast<char *>(payload), payloadSize);
497 Hdc::HdcSessionBase::SessionHandShake handshake;
498 SerialStruct::ParseFromString(handshake, s);
499 #ifdef HDC_DEBUG
500 WRITE_LOG(LOG_DEBUG, "handshake.banner:%s, payload:%s(%d)", handshake.banner.c_str(), s.c_str(), payloadSize);
501 #endif
502
503 if (handshake.banner == HANDSHAKE_FAILED.c_str()) {
504 WRITE_LOG(LOG_FATAL, "Handshake failed");
505 return false;
506 }
507
508 if (handshake.banner != HANDSHAKE_MESSAGE.c_str()) {
509 WRITE_LOG(LOG_DEBUG, "Hello failed");
510 return false;
511 }
512 if (handshake.authType != AUTH_OK) {
513 if (!HandServerAuth(hSession, handshake)) {
514 WRITE_LOG(LOG_DEBUG, "Auth failed");
515 return false;
516 }
517 return true;
518 }
519 // handshake auth OK
520 UpdateHdiInfo(handshake, hSession->connectKey);
521 hSession->handshakeOK = true;
522 return true;
523 }
524
525 // call in child thread
FetchCommand(HSession hSession,const uint32_t channelId,const uint16_t command,uint8_t * payload,const int payloadSize)526 bool HdcServer::FetchCommand(HSession hSession, const uint32_t channelId, const uint16_t command, uint8_t *payload,
527 const int payloadSize)
528 {
529 bool ret = true;
530 HdcServerForClient *sfc = static_cast<HdcServerForClient *>(clsServerForClient);
531 if (command == CMD_KERNEL_HANDSHAKE) {
532 ret = ServerSessionHandshake(hSession, payload, payloadSize);
533 WRITE_LOG(LOG_DEBUG, "Session handshake %s connType:%d", ret ? "successful" : "failed",
534 hSession->connType);
535 return ret;
536 }
537 // When you first initialize, ChannelID may be 0
538 HChannel hChannel = sfc->AdminChannel(OP_QUERY_REF, channelId, nullptr);
539 if (!hChannel) {
540 if (command == CMD_KERNEL_CHANNEL_CLOSE) {
541 // Daemon close channel and want to notify server close channel also, but it may has been
542 // closed by herself
543 WRITE_LOG(LOG_DEBUG, "Die channelId :%lu recv CMD_KERNEL_CHANNEL_CLOSE", channelId);
544 } else {
545 // Client may be ctrl+c and Server remove channel. notify server async
546 WRITE_LOG(LOG_DEBUG, "channelId :%lu die", channelId);
547 }
548 uint8_t flag = 0;
549 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &flag, 1);
550 return ret;
551 }
552 if (hChannel->isDead) {
553 WRITE_LOG(LOG_FATAL, "FetchCommand channelId:%u isDead", channelId);
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 pdiNew->channelId = channelId;
586 pdiNew->sessionId = hSession->sessionId;
587 pdiNew->connectKey = hSession->connectKey;
588 pdiNew->forwardDirection = (reinterpret_cast<char *>(payload))[0] == '1';
589 pdiNew->taskString = reinterpret_cast<char *>(payload);
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 sfc->SendCommandToClient(hChannel, command, payload, payloadSize);
609 break;
610 }
611 default: {
612 HSession hSessionByQuery = AdminSession(OP_QUERY, hChannel->targetSessionId, nullptr);
613 if (!hSessionByQuery) {
614 ret = false;
615 break;
616 }
617 ret = DispatchTaskData(hSessionByQuery, channelId, command, payload, payloadSize);
618 break;
619 }
620 }
621 --hChannel->ref;
622 return ret;
623 }
624
BuildForwardVisableLine(bool fullOrSimble,HForwardInfo hfi,string & echo)625 void HdcServer::BuildForwardVisableLine(bool fullOrSimble, HForwardInfo hfi, string &echo)
626 {
627 string buf;
628 if (fullOrSimble) {
629 buf = Base::StringFormat("%s %s %s\n", hfi->connectKey.c_str(), hfi->taskString.substr(OFFSET).c_str(),
630 hfi->forwardDirection ? "[Forward]" : "[Reverse]");
631 } else {
632 buf = Base::StringFormat("%s\n", hfi->taskString.c_str());
633 }
634 echo += buf;
635 }
636
AdminForwardMap(uint8_t opType,const string & taskString,HForwardInfo & hForwardInfoInOut)637 string HdcServer::AdminForwardMap(uint8_t opType, const string &taskString, HForwardInfo &hForwardInfoInOut)
638 {
639 string sRet;
640 switch (opType) {
641 case OP_ADD: {
642 HForwardInfo pfiNew = new(std::nothrow) HdcForwardInformation();
643 if (pfiNew == nullptr) {
644 WRITE_LOG(LOG_FATAL, "AdminForwardMap new pfiNew failed");
645 break;
646 }
647 *pfiNew = *hForwardInfoInOut;
648 uv_rwlock_wrlock(&forwardAdmin);
649 if (!mapForward[hForwardInfoInOut->taskString]) {
650 mapForward[hForwardInfoInOut->taskString] = pfiNew;
651 }
652 uv_rwlock_wrunlock(&forwardAdmin);
653 break;
654 }
655 case OP_GET_STRLIST:
656 case OP_GET_STRLIST_FULL: {
657 uv_rwlock_rdlock(&forwardAdmin);
658 map<string, HForwardInfo>::iterator iter;
659 for (iter = mapForward.begin(); iter != mapForward.end(); ++iter) {
660 HForwardInfo di = iter->second;
661 if (!di) {
662 continue;
663 }
664 BuildForwardVisableLine(opType == OP_GET_STRLIST_FULL, di, sRet);
665 }
666 uv_rwlock_rdunlock(&forwardAdmin);
667 break;
668 }
669 case OP_QUERY: {
670 uv_rwlock_rdlock(&forwardAdmin);
671 if (mapForward.count(taskString)) {
672 hForwardInfoInOut = mapForward[taskString];
673 }
674 uv_rwlock_rdunlock(&forwardAdmin);
675 break;
676 }
677 case OP_REMOVE: {
678 uv_rwlock_wrlock(&forwardAdmin);
679 if (mapForward.count(taskString)) {
680 mapForward.erase(taskString);
681 }
682 uv_rwlock_wrunlock(&forwardAdmin);
683 break;
684 }
685 default:
686 break;
687 }
688 return sRet;
689 }
690
CleanForwardMap(uint32_t sessionId)691 void HdcServer::CleanForwardMap(uint32_t sessionId)
692 {
693 uv_rwlock_rdlock(&forwardAdmin);
694 map<string, HForwardInfo>::iterator iter;
695 for (iter = mapForward.begin(); iter != mapForward.end();) {
696 HForwardInfo di = iter->second;
697 if (!di) {
698 continue;
699 }
700 if (sessionId == 0 || sessionId == di->sessionId) {
701 iter = mapForward.erase(iter);
702 } else {
703 iter++;
704 }
705 }
706 uv_rwlock_rdunlock(&forwardAdmin);
707 }
708
UsbPreConnect(uv_timer_t * handle)709 void HdcServer::UsbPreConnect(uv_timer_t *handle)
710 {
711 HSession hSession = (HSession)handle->data;
712 bool stopLoop = false;
713 HdcServer *hdcServer = (HdcServer *)hSession->classInstance;
714 while (true) {
715 WRITE_LOG(LOG_DEBUG, "HdcServer::UsbPreConnect");
716 HDaemonInfo pDi = nullptr;
717 if (hSession->connectKey == "any") {
718 hdcServer->AdminDaemonMap(OP_GET_ANY, hSession->connectKey, pDi);
719 } else {
720 hdcServer->AdminDaemonMap(OP_QUERY, hSession->connectKey, pDi);
721 }
722 if (!pDi || !pDi->usbMountPoint.size()) {
723 break;
724 }
725 HdcHostUSB *hdcHostUSB = (HdcHostUSB *)hSession->classModule;
726 hdcHostUSB->ConnectDetectDaemon(hSession, pDi);
727 stopLoop = true;
728 break;
729 }
730 if (stopLoop && !uv_is_closing((const uv_handle_t *)handle)) {
731 uv_close((uv_handle_t *)handle, Base::CloseTimerCallback);
732 }
733 }
734 #ifdef HDC_SUPPORT_UART
UartPreConnect(uv_timer_t * handle)735 void HdcServer::UartPreConnect(uv_timer_t *handle)
736 {
737 WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__);
738 HSession hSession = (HSession)handle->data;
739 bool stopLoop = false;
740 HdcServer *hdcServer = (HdcServer *)hSession->classInstance;
741 const int uartConnectRetryMax = 100; // max 6s
742 while (true) {
743 if (hSession->hUART->retryCount > uartConnectRetryMax) {
744 WRITE_LOG(LOG_DEBUG, "%s failed because max retry limit %d", __FUNCTION__,
745 hSession->hUART->retryCount);
746 hdcServer->FreeSession(hSession->sessionId);
747 stopLoop = true;
748 break;
749 }
750 hSession->hUART->retryCount++;
751 HDaemonInfo pDi = nullptr;
752
753 WRITE_LOG(LOG_DEBUG, "%s query %s", __FUNCTION__, hSession->ToDebugString().c_str());
754 hdcServer->AdminDaemonMap(OP_QUERY, hSession->connectKey, pDi);
755 if (!pDi) {
756 WRITE_LOG(LOG_DEBUG, "%s not found", __FUNCTION__);
757 break;
758 }
759 HdcHostUART *hdcHostUART = (HdcHostUART *)hSession->classModule;
760 hdcHostUART->ConnectDaemonByUart(hSession, pDi);
761 WRITE_LOG(LOG_DEBUG, "%s ConnectDaemonByUart done", __FUNCTION__);
762
763 stopLoop = true;
764 break;
765 }
766 if (stopLoop) {
767 uv_close((uv_handle_t *)handle, Base::CloseTimerCallback);
768 }
769 }
770
CreatConnectUart(HSession hSession)771 void HdcServer::CreatConnectUart(HSession hSession)
772 {
773 uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
774 if (waitTimeDoCmd == nullptr) {
775 WRITE_LOG(LOG_FATAL, "CreatConnectUart new waitTimeDoCmd failed");
776 return;
777 }
778 uv_timer_init(&loopMain, waitTimeDoCmd);
779 waitTimeDoCmd->data = hSession;
780 uv_timer_start(waitTimeDoCmd, UartPreConnect, UV_TIMEOUT, UV_REPEAT);
781 }
782 #endif
783 // -1,has old,-2 error
CreateConnect(const string & connectKey,bool isCheck)784 int HdcServer::CreateConnect(const string &connectKey, bool isCheck)
785 {
786 uint8_t connType = 0;
787 if (connectKey.find(":") != std::string::npos) { // TCP
788 connType = CONN_TCP;
789 }
790 #ifdef HDC_SUPPORT_UART
791 else if (connectKey.find("COM") == 0 ||
792 connectKey.find("/dev/ttyUSB") == 0 ||
793 connectKey.find("/dev/cu.") == 0) { // UART
794 connType = CONN_SERIAL;
795 }
796 #endif
797 else { // USB
798 connType = CONN_USB;
799 }
800 HDaemonInfo hdi = nullptr;
801 if (connectKey == "any") {
802 return RET_SUCCESS;
803 }
804 AdminDaemonMap(OP_QUERY, connectKey, hdi);
805 if (hdi == nullptr) {
806 HdcDaemonInformation di = {};
807 di.connectKey = connectKey;
808 di.connType = connType;
809 di.connStatus = STATUS_UNKNOW;
810 HDaemonInfo pDi = reinterpret_cast<HDaemonInfo>(&di);
811 AdminDaemonMap(OP_ADD, "", pDi);
812 AdminDaemonMap(OP_QUERY, connectKey, hdi);
813 }
814 if (!hdi || hdi->connStatus == STATUS_CONNECTED) {
815 WRITE_LOG(LOG_FATAL, "Connected return");
816 return ERR_GENERIC;
817 }
818 HSession hSession = nullptr;
819 if (connType == CONN_TCP) {
820 hSession = clsTCPClt->ConnectDaemon(connectKey, isCheck);
821 } else if (connType == CONN_SERIAL) {
822 #ifdef HDC_SUPPORT_UART
823 clsUARTClt->SetCheckFlag(isCheck);
824 hSession = clsUARTClt->ConnectDaemon(connectKey);
825 #endif
826 } else {
827 hSession = MallocSession(true, CONN_USB, clsUSBClt);
828 if (!hSession) {
829 WRITE_LOG(LOG_FATAL, "CreateConnect malloc usb session failed %s", connectKey.c_str());
830 return ERR_BUF_ALLOC;
831 }
832 hSession->connectKey = connectKey;
833 uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
834 if (waitTimeDoCmd == nullptr) {
835 WRITE_LOG(LOG_FATAL, "CreateConnect new waitTimeDoCmd failed");
836 FreeSession(hSession->sessionId);
837 return ERR_GENERIC;
838 }
839 uv_timer_init(&loopMain, waitTimeDoCmd);
840 waitTimeDoCmd->data = hSession;
841 uv_timer_start(waitTimeDoCmd, UsbPreConnect, UV_TIMEOUT, UV_REPEAT);
842 }
843 if (!hSession) {
844 WRITE_LOG(LOG_FATAL, "CreateConnect hSession nullptr");
845 return ERR_BUF_ALLOC;
846 }
847 HDaemonInfo hdiQuery = nullptr;
848 AdminDaemonMap(OP_QUERY, connectKey, hdiQuery);
849 if (hdiQuery) {
850 HdcDaemonInformation diNew = *hdiQuery;
851 diNew.hSession = hSession;
852 HDaemonInfo hdiNew = &diNew;
853 AdminDaemonMap(OP_UPDATE, hdiQuery->connectKey, hdiNew);
854 }
855 return RET_SUCCESS;
856 }
857
AttachChannel(HSession hSession,const uint32_t channelId)858 void HdcServer::AttachChannel(HSession hSession, const uint32_t channelId)
859 {
860 int ret = 0;
861 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
862 HChannel hChannel = hSfc->AdminChannel(OP_QUERY_REF, channelId, nullptr);
863 if (!hChannel) {
864 WRITE_LOG(LOG_DEBUG, "AttachChannel hChannel null channelId:%u", channelId);
865 return;
866 }
867 uv_tcp_init(&hSession->childLoop, &hChannel->hChildWorkTCP);
868 hChannel->hChildWorkTCP.data = hChannel;
869 hChannel->targetSessionId = hSession->sessionId;
870 if ((ret = uv_tcp_open((uv_tcp_t *)&hChannel->hChildWorkTCP, hChannel->fdChildWorkTCP)) < 0) {
871 constexpr int bufSize = 1024;
872 char buf[bufSize] = { 0 };
873 uv_err_name_r(ret, buf, bufSize);
874 WRITE_LOG(LOG_DEBUG, "Hdcserver AttachChannel uv_tcp_open failed %s, channelid:%d fdChildWorkTCP:%d",
875 buf, hChannel->channelId, hChannel->fdChildWorkTCP);
876 Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP);
877 --hChannel->ref;
878 return;
879 }
880 Base::SetTcpOptions((uv_tcp_t *)&hChannel->hChildWorkTCP);
881 uv_read_start((uv_stream_t *)&hChannel->hChildWorkTCP, hSfc->AllocCallback, hSfc->ReadStream);
882 --hChannel->ref;
883 };
884
DeatchChannel(HSession hSession,const uint32_t channelId)885 void HdcServer::DeatchChannel(HSession hSession, const uint32_t channelId)
886 {
887 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
888 // childCleared has not set, no need OP_QUERY_REF
889 HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr);
890 if (!hChannel) {
891 ClearOwnTasks(hSession, channelId);
892 uint8_t count = 0;
893 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
894 WRITE_LOG(LOG_WARN, "DeatchChannel hChannel null channelId:%u", channelId);
895 return;
896 }
897 if (hChannel->childCleared) {
898 WRITE_LOG(LOG_DEBUG, "Childchannel has already freed, cid:%u", channelId);
899 return;
900 }
901 // The own task for this channel must be clear before free channel
902 ClearOwnTasks(hSession, channelId);
903 uint8_t count = 0;
904 Send(hSession->sessionId, hChannel->channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
905 WRITE_LOG(LOG_DEBUG, "Childchannel begin close, cid:%u", hChannel->channelId);
906 if (uv_is_closing((const uv_handle_t *)&hChannel->hChildWorkTCP)) {
907 Base::DoNextLoop(&hSession->childLoop, hChannel, [](const uint8_t flag, string &msg, const void *data) {
908 HChannel hChannel = (HChannel)data;
909 hChannel->childCleared = true;
910 WRITE_LOG(LOG_DEBUG, "Childchannel free direct, cid:%u", hChannel->channelId);
911 });
912 } else {
913 if (hChannel->hChildWorkTCP.loop == NULL) {
914 WRITE_LOG(LOG_DEBUG, "Childchannel loop is null, cid:%u", hChannel->channelId);
915 }
916 Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP, [](uv_handle_t *handle) -> void {
917 HChannel hChannel = (HChannel)handle->data;
918 hChannel->childCleared = true;
919 WRITE_LOG(LOG_DEBUG, "Childchannel free callback, cid:%u", hChannel->channelId);
920 });
921 }
922 };
923
ServerCommand(const uint32_t sessionId,const uint32_t channelId,const uint16_t command,uint8_t * bufPtr,const int size)924 bool HdcServer::ServerCommand(const uint32_t sessionId, const uint32_t channelId, const uint16_t command,
925 uint8_t *bufPtr, const int size)
926 {
927 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
928 HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr);
929 HSession hSession = AdminSession(OP_QUERY, sessionId, nullptr);
930 if (!hChannel || !hSession) {
931 return false;
932 }
933 return FetchCommand(hSession, channelId, command, bufPtr, size);
934 }
935
936 // clang-format off
RedirectToTask(HTaskInfo hTaskInfo,HSession hSession,const uint32_t channelId,const uint16_t command,uint8_t * payload,const int payloadSize)937 bool HdcServer::RedirectToTask(HTaskInfo hTaskInfo, HSession hSession, const uint32_t channelId,
938 const uint16_t command, uint8_t *payload, const int payloadSize)
939 // clang-format on
940 {
941 bool ret = true;
942 hTaskInfo->ownerSessionClass = this;
943 switch (command) {
944 case CMD_UNITY_BUGREPORT_INIT:
945 case CMD_UNITY_BUGREPORT_DATA:
946 ret = TaskCommandDispatch<HdcHostUnity>(hTaskInfo, TYPE_UNITY, command, payload, payloadSize);
947 break;
948 case CMD_FILE_INIT:
949 case CMD_FILE_BEGIN:
950 case CMD_FILE_CHECK:
951 case CMD_FILE_DATA:
952 case CMD_FILE_FINISH:
953 case CMD_FILE_MODE:
954 case CMD_DIR_MODE:
955 ret = TaskCommandDispatch<HdcFile>(hTaskInfo, TASK_FILE, command, payload, payloadSize);
956 break;
957 case CMD_FORWARD_INIT:
958 case CMD_FORWARD_CHECK:
959 case CMD_FORWARD_CHECK_RESULT:
960 case CMD_FORWARD_ACTIVE_MASTER:
961 case CMD_FORWARD_ACTIVE_SLAVE:
962 case CMD_FORWARD_DATA:
963 case CMD_FORWARD_FREE_CONTEXT:
964 ret = TaskCommandDispatch<HdcHostForward>(hTaskInfo, TASK_FORWARD, command, payload, payloadSize);
965 break;
966 case CMD_APP_INIT:
967 case CMD_APP_SIDELOAD:
968 case CMD_APP_BEGIN:
969 case CMD_APP_FINISH:
970 case CMD_APP_UNINSTALL:
971 ret = TaskCommandDispatch<HdcHostApp>(hTaskInfo, TASK_APP, command, payload, payloadSize);
972 break;
973 case CMD_FLASHD_UPDATE_INIT:
974 case CMD_FLASHD_FLASH_INIT:
975 case CMD_FLASHD_CHECK:
976 case CMD_FLASHD_BEGIN:
977 case CMD_FLASHD_DATA:
978 case CMD_FLASHD_FINISH:
979 case CMD_FLASHD_ERASE:
980 case CMD_FLASHD_FORMAT:
981 case CMD_FLASHD_PROGRESS:
982 ret = TaskCommandDispatch<HostUpdater>(hTaskInfo, TASK_FLASHD, command, payload, payloadSize);
983 break;
984 default:
985 // ignore unknown command
986 break;
987 }
988 return ret;
989 }
990
RemoveInstanceTask(const uint8_t op,HTaskInfo hTask)991 bool HdcServer::RemoveInstanceTask(const uint8_t op, HTaskInfo hTask)
992 {
993 bool ret = true;
994 switch (hTask->taskType) {
995 case TYPE_SHELL:
996 WRITE_LOG(LOG_DEBUG, "Server not enable unity/shell");
997 break;
998 case TYPE_UNITY:
999 ret = DoTaskRemove<HdcHostUnity>(hTask, op);
1000 break;
1001 case TASK_FILE:
1002 ret = DoTaskRemove<HdcFile>(hTask, op);
1003 break;
1004 case TASK_FORWARD:
1005 ret = DoTaskRemove<HdcHostForward>(hTask, op);
1006 break;
1007 case TASK_APP:
1008 ret = DoTaskRemove<HdcHostApp>(hTask, op);
1009 break;
1010 case TASK_FLASHD:
1011 ret = DoTaskRemove<HostUpdater>(hTask, op);
1012 break;
1013 default:
1014 ret = false;
1015 break;
1016 }
1017 return ret;
1018 }
1019
EchoToClientsForSession(uint32_t targetSessionId,const string & echo)1020 void HdcServer::EchoToClientsForSession(uint32_t targetSessionId, const string &echo)
1021 {
1022 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
1023 WRITE_LOG(LOG_INFO, "%s:%u %s", __FUNCTION__, targetSessionId, echo.c_str());
1024 hSfc->EchoToAllChannelsViaSessionId(targetSessionId, echo);
1025 }
1026 } // namespace Hdc
1027