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