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 } else {
520 WRITE_LOG(LOG_FATAL, "TlvToStringMap failed");
521 }
522 }
523 hdiNew->version = handshake.version;
524 AdminDaemonMap(OP_UPDATE, connectKey, hdiNew);
525 }
526
ServerSessionHandshake(HSession hSession,uint8_t * payload,int payloadSize)527 bool HdcServer::ServerSessionHandshake(HSession hSession, uint8_t *payload, int payloadSize)
528 {
529 // session handshake step3
530 string s = string(reinterpret_cast<char *>(payload), payloadSize);
531 Hdc::HdcSessionBase::SessionHandShake handshake;
532 SerialStruct::ParseFromString(handshake, s);
533 #ifdef HDC_DEBUG
534 WRITE_LOG(LOG_DEBUG, "handshake.banner:%s, payload:%s(%d)", handshake.banner.c_str(), s.c_str(), payloadSize);
535 #endif
536
537 if (handshake.banner == HANDSHAKE_FAILED.c_str()) {
538 WRITE_LOG(LOG_FATAL, "Handshake failed");
539 return false;
540 }
541
542 if (handshake.banner != HANDSHAKE_MESSAGE.c_str()) {
543 WRITE_LOG(LOG_DEBUG, "Hello failed");
544 return false;
545 }
546 if (handshake.authType != AUTH_OK) {
547 if (!HandServerAuth(hSession, handshake)) {
548 WRITE_LOG(LOG_WARN, "Auth failed");
549 return false;
550 }
551 return true;
552 }
553 // handshake auth OK
554 UpdateHdiInfo(handshake, hSession->connectKey);
555 hSession->handshakeOK = true;
556 return true;
557 }
558
559 // call in child thread
FetchCommand(HSession hSession,const uint32_t channelId,const uint16_t command,uint8_t * payload,const int payloadSize)560 bool HdcServer::FetchCommand(HSession hSession, const uint32_t channelId, const uint16_t command, uint8_t *payload,
561 const int payloadSize)
562 {
563 bool ret = true;
564 HdcServerForClient *sfc = static_cast<HdcServerForClient *>(clsServerForClient);
565 if (command == CMD_KERNEL_HANDSHAKE) {
566 ret = ServerSessionHandshake(hSession, payload, payloadSize);
567 WRITE_LOG(LOG_DEBUG, "Session handshake %s connType:%d", ret ? "successful" : "failed",
568 hSession->connType);
569 return ret;
570 }
571 // When you first initialize, ChannelID may be 0
572 HChannel hChannel = sfc->AdminChannel(OP_QUERY_REF, channelId, nullptr);
573 if (!hChannel) {
574 if (command == CMD_KERNEL_CHANNEL_CLOSE) {
575 // Daemon close channel and want to notify server close channel also, but it may has been
576 // closed by herself
577 WRITE_LOG(LOG_WARN, "Die channelId :%lu recv CMD_KERNEL_CHANNEL_CLOSE", channelId);
578 } else {
579 // Client may be ctrl+c and Server remove channel. notify server async
580 WRITE_LOG(LOG_DEBUG, "channelId :%lu die", channelId);
581 }
582 uint8_t flag = 0;
583 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &flag, 1);
584 return ret;
585 }
586 if (hChannel->isDead) {
587 WRITE_LOG(LOG_FATAL, "FetchCommand channelId:%u isDead", channelId);
588 --hChannel->ref;
589 return ret;
590 }
591 switch (command) {
592 case CMD_KERNEL_ECHO_RAW: { // Native shell data output
593 sfc->EchoClientRaw(hChannel, payload, payloadSize);
594 break;
595 }
596 case CMD_KERNEL_ECHO: {
597 MessageLevel level = static_cast<MessageLevel>(*payload);
598 string s(reinterpret_cast<char *>(payload + 1), payloadSize - 1);
599 sfc->EchoClient(hChannel, level, s.c_str());
600 WRITE_LOG(LOG_INFO, "CMD_KERNEL_ECHO size:%d channelId:%u", payloadSize - 1, channelId);
601 break;
602 }
603 case CMD_KERNEL_CHANNEL_CLOSE: {
604 WRITE_LOG(LOG_DEBUG, "CMD_KERNEL_CHANNEL_CLOSE channelid:%u", channelId);
605 // Forcibly closing the tcp handle here may result in incomplete data reception on the client side
606 ClearOwnTasks(hSession, channelId);
607 // crossthread free
608 sfc->PushAsyncMessage(channelId, ASYNC_FREE_CHANNEL, nullptr, 0);
609 if (*payload != 0) {
610 --(*payload);
611 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, payload, 1);
612 }
613 break;
614 }
615 case CMD_FORWARD_SUCCESS: {
616 // add to local
617 HdcForwardInformation di;
618 HForwardInfo pdiNew = &di;
619 pdiNew->channelId = channelId;
620 pdiNew->sessionId = hSession->sessionId;
621 pdiNew->connectKey = hSession->connectKey;
622 pdiNew->forwardDirection = (reinterpret_cast<char *>(payload))[0] == '1';
623 pdiNew->taskString = reinterpret_cast<char *>(payload);
624 AdminForwardMap(OP_ADD, STRING_EMPTY, pdiNew);
625 Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP); // detch client channel
626 break;
627 }
628 case CMD_FILE_INIT:
629 case CMD_FILE_CHECK:
630 case CMD_FILE_BEGIN:
631 case CMD_FILE_DATA:
632 case CMD_FILE_FINISH:
633 case CMD_FILE_MODE:
634 case CMD_DIR_MODE:
635 case CMD_APP_INIT:
636 case CMD_APP_CHECK:
637 case CMD_APP_BEGIN:
638 case CMD_APP_DATA:
639 case CMD_APP_FINISH:
640 if (hChannel->fromClient) {
641 // server directly passthrough app command to client if remote file mode, else go default
642 sfc->SendCommandToClient(hChannel, command, payload, payloadSize);
643 break;
644 }
645 default: {
646 HSession hSessionByQuery = AdminSession(OP_QUERY, hChannel->targetSessionId, nullptr);
647 if (!hSessionByQuery) {
648 ret = false;
649 break;
650 }
651 ret = DispatchTaskData(hSessionByQuery, channelId, command, payload, payloadSize);
652 break;
653 }
654 }
655 --hChannel->ref;
656 return ret;
657 }
658
BuildForwardVisableLine(bool fullOrSimble,HForwardInfo hfi,string & echo)659 void HdcServer::BuildForwardVisableLine(bool fullOrSimble, HForwardInfo hfi, string &echo)
660 {
661 string buf;
662 if (fullOrSimble) {
663 buf = Base::StringFormat("%s %s %s\n", hfi->connectKey.c_str(), hfi->taskString.substr(OFFSET).c_str(),
664 hfi->forwardDirection ? "[Forward]" : "[Reverse]");
665 } else {
666 buf = Base::StringFormat("%s\n", hfi->taskString.c_str());
667 }
668 echo += buf;
669 }
670
AdminForwardMap(uint8_t opType,const string & taskString,HForwardInfo & hForwardInfoInOut)671 string HdcServer::AdminForwardMap(uint8_t opType, const string &taskString, HForwardInfo &hForwardInfoInOut)
672 {
673 string sRet;
674 switch (opType) {
675 case OP_ADD: {
676 HForwardInfo pfiNew = new(std::nothrow) HdcForwardInformation();
677 if (pfiNew == nullptr) {
678 WRITE_LOG(LOG_FATAL, "AdminForwardMap new pfiNew failed");
679 break;
680 }
681 *pfiNew = *hForwardInfoInOut;
682 uv_rwlock_wrlock(&forwardAdmin);
683 if (!mapForward[hForwardInfoInOut->taskString]) {
684 mapForward[hForwardInfoInOut->taskString] = pfiNew;
685 }
686 uv_rwlock_wrunlock(&forwardAdmin);
687 break;
688 }
689 case OP_GET_STRLIST:
690 case OP_GET_STRLIST_FULL: {
691 uv_rwlock_rdlock(&forwardAdmin);
692 map<string, HForwardInfo>::iterator iter;
693 for (iter = mapForward.begin(); iter != mapForward.end(); ++iter) {
694 HForwardInfo di = iter->second;
695 if (!di) {
696 continue;
697 }
698 BuildForwardVisableLine(opType == OP_GET_STRLIST_FULL, di, sRet);
699 }
700 uv_rwlock_rdunlock(&forwardAdmin);
701 break;
702 }
703 case OP_QUERY: {
704 uv_rwlock_rdlock(&forwardAdmin);
705 if (mapForward.count(taskString)) {
706 hForwardInfoInOut = mapForward[taskString];
707 }
708 uv_rwlock_rdunlock(&forwardAdmin);
709 break;
710 }
711 case OP_REMOVE: {
712 uv_rwlock_wrlock(&forwardAdmin);
713 if (mapForward.count(taskString)) {
714 mapForward.erase(taskString);
715 }
716 uv_rwlock_wrunlock(&forwardAdmin);
717 break;
718 }
719 default:
720 break;
721 }
722 return sRet;
723 }
724
CleanForwardMap(uint32_t sessionId)725 void HdcServer::CleanForwardMap(uint32_t sessionId)
726 {
727 uv_rwlock_rdlock(&forwardAdmin);
728 map<string, HForwardInfo>::iterator iter;
729 for (iter = mapForward.begin(); iter != mapForward.end();) {
730 HForwardInfo di = iter->second;
731 if (!di) {
732 continue;
733 }
734 if (sessionId == 0 || sessionId == di->sessionId) {
735 iter = mapForward.erase(iter);
736 } else {
737 iter++;
738 }
739 }
740 uv_rwlock_rdunlock(&forwardAdmin);
741 }
742
UsbPreConnect(uv_timer_t * handle)743 void HdcServer::UsbPreConnect(uv_timer_t *handle)
744 {
745 HSession hSession = (HSession)handle->data;
746 bool stopLoop = false;
747 HdcServer *hdcServer = (HdcServer *)hSession->classInstance;
748 while (true) {
749 WRITE_LOG(LOG_DEBUG, "HdcServer::UsbPreConnect");
750 HDaemonInfo pDi = nullptr;
751 if (hSession->connectKey == "any") {
752 hdcServer->AdminDaemonMap(OP_GET_ANY, hSession->connectKey, pDi);
753 } else {
754 hdcServer->AdminDaemonMap(OP_QUERY, hSession->connectKey, pDi);
755 }
756 if (!pDi || !pDi->usbMountPoint.size()) {
757 break;
758 }
759 HdcHostUSB *hdcHostUSB = (HdcHostUSB *)hSession->classModule;
760 hdcHostUSB->ConnectDetectDaemon(hSession, pDi);
761 stopLoop = true;
762 break;
763 }
764 if (stopLoop && !uv_is_closing((const uv_handle_t *)handle)) {
765 uv_close((uv_handle_t *)handle, Base::CloseTimerCallback);
766 }
767 }
768 #ifdef HDC_SUPPORT_UART
UartPreConnect(uv_timer_t * handle)769 void HdcServer::UartPreConnect(uv_timer_t *handle)
770 {
771 WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__);
772 HSession hSession = (HSession)handle->data;
773 bool stopLoop = false;
774 HdcServer *hdcServer = (HdcServer *)hSession->classInstance;
775 const int uartConnectRetryMax = 100; // max 6s
776 while (true) {
777 if (hSession->hUART->retryCount > uartConnectRetryMax) {
778 WRITE_LOG(LOG_DEBUG, "%s failed because max retry limit %d", __FUNCTION__,
779 hSession->hUART->retryCount);
780 hdcServer->FreeSession(hSession->sessionId);
781 stopLoop = true;
782 break;
783 }
784 hSession->hUART->retryCount++;
785 HDaemonInfo pDi = nullptr;
786
787 WRITE_LOG(LOG_DEBUG, "%s query %s", __FUNCTION__, hSession->ToDebugString().c_str());
788 hdcServer->AdminDaemonMap(OP_QUERY, hSession->connectKey, pDi);
789 if (!pDi) {
790 WRITE_LOG(LOG_DEBUG, "%s not found", __FUNCTION__);
791 break;
792 }
793 HdcHostUART *hdcHostUART = (HdcHostUART *)hSession->classModule;
794 hdcHostUART->ConnectDaemonByUart(hSession, pDi);
795 WRITE_LOG(LOG_DEBUG, "%s ConnectDaemonByUart done", __FUNCTION__);
796
797 stopLoop = true;
798 break;
799 }
800 if (stopLoop) {
801 uv_close((uv_handle_t *)handle, Base::CloseTimerCallback);
802 }
803 }
804
CreatConnectUart(HSession hSession)805 void HdcServer::CreatConnectUart(HSession hSession)
806 {
807 uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
808 if (waitTimeDoCmd == nullptr) {
809 WRITE_LOG(LOG_FATAL, "CreatConnectUart new waitTimeDoCmd failed");
810 return;
811 }
812 uv_timer_init(&loopMain, waitTimeDoCmd);
813 waitTimeDoCmd->data = hSession;
814 uv_timer_start(waitTimeDoCmd, UartPreConnect, UV_TIMEOUT, UV_REPEAT);
815 }
816 #endif
817 // -1,has old,-2 error
CreateConnect(const string & connectKey,bool isCheck)818 int HdcServer::CreateConnect(const string &connectKey, bool isCheck)
819 {
820 uint8_t connType = 0;
821 if (connectKey.find(":") != std::string::npos) { // TCP
822 connType = CONN_TCP;
823 }
824 #ifdef HDC_SUPPORT_UART
825 else if (connectKey.find("COM") == 0 ||
826 connectKey.find("/dev/ttyUSB") == 0 ||
827 connectKey.find("/dev/cu.") == 0) { // UART
828 connType = CONN_SERIAL;
829 }
830 #endif
831 else { // USB
832 connType = CONN_USB;
833 }
834 HDaemonInfo hdi = nullptr;
835 if (connectKey == "any") {
836 return RET_SUCCESS;
837 }
838 AdminDaemonMap(OP_QUERY, connectKey, hdi);
839 if (hdi == nullptr) {
840 HdcDaemonInformation di = {};
841 di.connectKey = connectKey;
842 di.connType = connType;
843 di.connStatus = STATUS_UNKNOW;
844 HDaemonInfo pDi = reinterpret_cast<HDaemonInfo>(&di);
845 AdminDaemonMap(OP_ADD, "", pDi);
846 AdminDaemonMap(OP_QUERY, connectKey, hdi);
847 }
848 if (!hdi || hdi->connStatus == STATUS_CONNECTED) {
849 WRITE_LOG(LOG_FATAL, "Connected return");
850 return ERR_GENERIC;
851 }
852 HSession hSession = nullptr;
853 if (connType == CONN_TCP) {
854 hSession = clsTCPClt->ConnectDaemon(connectKey, isCheck);
855 } else if (connType == CONN_SERIAL) {
856 #ifdef HDC_SUPPORT_UART
857 clsUARTClt->SetCheckFlag(isCheck);
858 hSession = clsUARTClt->ConnectDaemon(connectKey);
859 #endif
860 } else {
861 hSession = MallocSession(true, CONN_USB, clsUSBClt);
862 if (!hSession) {
863 WRITE_LOG(LOG_FATAL, "CreateConnect malloc usb session failed %s", Hdc::MaskString(connectKey).c_str());
864 return ERR_BUF_ALLOC;
865 }
866 hSession->connectKey = connectKey;
867 uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
868 if (waitTimeDoCmd == nullptr) {
869 WRITE_LOG(LOG_FATAL, "CreateConnect new waitTimeDoCmd failed");
870 FreeSession(hSession->sessionId);
871 return ERR_GENERIC;
872 }
873 uv_timer_init(&loopMain, waitTimeDoCmd);
874 waitTimeDoCmd->data = hSession;
875 uv_timer_start(waitTimeDoCmd, UsbPreConnect, UV_TIMEOUT, UV_REPEAT);
876 }
877 if (!hSession) {
878 WRITE_LOG(LOG_FATAL, "CreateConnect hSession nullptr");
879 return ERR_BUF_ALLOC;
880 }
881 HDaemonInfo hdiQuery = nullptr;
882 AdminDaemonMap(OP_QUERY, connectKey, hdiQuery);
883 if (hdiQuery) {
884 HdcDaemonInformation diNew = *hdiQuery;
885 diNew.hSession = hSession;
886 HDaemonInfo hdiNew = &diNew;
887 AdminDaemonMap(OP_UPDATE, hdiQuery->connectKey, hdiNew);
888 }
889 return RET_SUCCESS;
890 }
891
AttachChannel(HSession hSession,const uint32_t channelId)892 void HdcServer::AttachChannel(HSession hSession, const uint32_t channelId)
893 {
894 int ret = 0;
895 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
896 HChannel hChannel = hSfc->AdminChannel(OP_QUERY_REF, channelId, nullptr);
897 if (!hChannel) {
898 WRITE_LOG(LOG_DEBUG, "AttachChannel hChannel null channelId:%u", channelId);
899 return;
900 }
901 uv_tcp_init(&hSession->childLoop, &hChannel->hChildWorkTCP);
902 hChannel->hChildWorkTCP.data = hChannel;
903 hChannel->targetSessionId = hSession->sessionId;
904 if ((ret = uv_tcp_open((uv_tcp_t *)&hChannel->hChildWorkTCP, hChannel->fdChildWorkTCP)) < 0) {
905 constexpr int bufSize = 1024;
906 char buf[bufSize] = { 0 };
907 uv_err_name_r(ret, buf, bufSize);
908 WRITE_LOG(LOG_WARN, "Hdcserver AttachChannel uv_tcp_open failed %s, channelid:%d fdChildWorkTCP:%d",
909 buf, hChannel->channelId, hChannel->fdChildWorkTCP);
910 Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP);
911 --hChannel->ref;
912 return;
913 }
914 Base::SetTcpOptions((uv_tcp_t *)&hChannel->hChildWorkTCP);
915 uv_read_start((uv_stream_t *)&hChannel->hChildWorkTCP, hSfc->AllocCallback, hSfc->ReadStream);
916 --hChannel->ref;
917 };
918
DeatchChannel(HSession hSession,const uint32_t channelId)919 void HdcServer::DeatchChannel(HSession hSession, const uint32_t channelId)
920 {
921 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
922 // childCleared has not set, no need OP_QUERY_REF
923 HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr);
924 if (!hChannel) {
925 ClearOwnTasks(hSession, channelId);
926 uint8_t count = 0;
927 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
928 WRITE_LOG(LOG_WARN, "DeatchChannel hChannel null channelId:%u", channelId);
929 return;
930 }
931 if (hChannel->childCleared) {
932 WRITE_LOG(LOG_DEBUG, "Childchannel has already freed, cid:%u", channelId);
933 return;
934 }
935 // The own task for this channel must be clear before free channel
936 ClearOwnTasks(hSession, channelId);
937 uint8_t count = 0;
938 Send(hSession->sessionId, hChannel->channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
939 WRITE_LOG(LOG_DEBUG, "Childchannel begin close, cid:%u, sid:%u", hChannel->channelId, hSession->sessionId);
940 if (uv_is_closing((const uv_handle_t *)&hChannel->hChildWorkTCP)) {
941 Base::DoNextLoop(&hSession->childLoop, hChannel, [](const uint8_t flag, string &msg, const void *data) {
942 HChannel hChannel = (HChannel)data;
943 hChannel->childCleared = true;
944 WRITE_LOG(LOG_DEBUG, "Childchannel free direct, cid:%u", hChannel->channelId);
945 });
946 } else {
947 if (hChannel->hChildWorkTCP.loop == NULL) {
948 WRITE_LOG(LOG_DEBUG, "Childchannel loop is null, cid:%u", hChannel->channelId);
949 }
950 Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP, [](uv_handle_t *handle) -> void {
951 HChannel hChannel = (HChannel)handle->data;
952 hChannel->childCleared = true;
953 WRITE_LOG(LOG_DEBUG, "Childchannel free callback, cid:%u", hChannel->channelId);
954 });
955 }
956 };
957
ServerCommand(const uint32_t sessionId,const uint32_t channelId,const uint16_t command,uint8_t * bufPtr,const int size)958 bool HdcServer::ServerCommand(const uint32_t sessionId, const uint32_t channelId, const uint16_t command,
959 uint8_t *bufPtr, const int size)
960 {
961 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
962 HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr);
963 HSession hSession = AdminSession(OP_QUERY, sessionId, nullptr);
964 if (!hChannel || !hSession) {
965 return false;
966 }
967 return FetchCommand(hSession, channelId, command, bufPtr, size);
968 }
969
970 // clang-format off
RedirectToTask(HTaskInfo hTaskInfo,HSession hSession,const uint32_t channelId,const uint16_t command,uint8_t * payload,const int payloadSize)971 bool HdcServer::RedirectToTask(HTaskInfo hTaskInfo, HSession hSession, const uint32_t channelId,
972 const uint16_t command, uint8_t *payload, const int payloadSize)
973 // clang-format on
974 {
975 bool ret = true;
976 hTaskInfo->ownerSessionClass = this;
977 switch (command) {
978 case CMD_UNITY_BUGREPORT_INIT:
979 case CMD_UNITY_BUGREPORT_DATA:
980 ret = TaskCommandDispatch<HdcHostUnity>(hTaskInfo, TYPE_UNITY, command, payload, payloadSize);
981 break;
982 case CMD_FILE_INIT:
983 case CMD_FILE_BEGIN:
984 case CMD_FILE_CHECK:
985 case CMD_FILE_DATA:
986 case CMD_FILE_FINISH:
987 case CMD_FILE_MODE:
988 case CMD_DIR_MODE:
989 ret = TaskCommandDispatch<HdcFile>(hTaskInfo, TASK_FILE, command, payload, payloadSize);
990 break;
991 case CMD_FORWARD_INIT:
992 case CMD_FORWARD_CHECK:
993 case CMD_FORWARD_CHECK_RESULT:
994 case CMD_FORWARD_ACTIVE_MASTER:
995 case CMD_FORWARD_ACTIVE_SLAVE:
996 case CMD_FORWARD_DATA:
997 case CMD_FORWARD_FREE_CONTEXT:
998 ret = TaskCommandDispatch<HdcHostForward>(hTaskInfo, TASK_FORWARD, command, payload, payloadSize);
999 break;
1000 case CMD_APP_INIT:
1001 case CMD_APP_SIDELOAD:
1002 case CMD_APP_BEGIN:
1003 case CMD_APP_FINISH:
1004 case CMD_APP_UNINSTALL:
1005 ret = TaskCommandDispatch<HdcHostApp>(hTaskInfo, TASK_APP, command, payload, payloadSize);
1006 break;
1007 case CMD_FLASHD_UPDATE_INIT:
1008 case CMD_FLASHD_FLASH_INIT:
1009 case CMD_FLASHD_CHECK:
1010 case CMD_FLASHD_BEGIN:
1011 case CMD_FLASHD_DATA:
1012 case CMD_FLASHD_FINISH:
1013 case CMD_FLASHD_ERASE:
1014 case CMD_FLASHD_FORMAT:
1015 case CMD_FLASHD_PROGRESS:
1016 ret = TaskCommandDispatch<HostUpdater>(hTaskInfo, TASK_FLASHD, command, payload, payloadSize);
1017 break;
1018 default:
1019 // ignore unknown command
1020 break;
1021 }
1022 return ret;
1023 }
1024
RemoveInstanceTask(const uint8_t op,HTaskInfo hTask)1025 bool HdcServer::RemoveInstanceTask(const uint8_t op, HTaskInfo hTask)
1026 {
1027 bool ret = true;
1028 switch (hTask->taskType) {
1029 case TYPE_SHELL:
1030 WRITE_LOG(LOG_DEBUG, "Server not enable unity/shell");
1031 break;
1032 case TYPE_UNITY:
1033 ret = DoTaskRemove<HdcHostUnity>(hTask, op);
1034 break;
1035 case TASK_FILE:
1036 ret = DoTaskRemove<HdcFile>(hTask, op);
1037 break;
1038 case TASK_FORWARD:
1039 ret = DoTaskRemove<HdcHostForward>(hTask, op);
1040 break;
1041 case TASK_APP:
1042 ret = DoTaskRemove<HdcHostApp>(hTask, op);
1043 break;
1044 case TASK_FLASHD:
1045 ret = DoTaskRemove<HostUpdater>(hTask, op);
1046 break;
1047 default:
1048 ret = false;
1049 break;
1050 }
1051 return ret;
1052 }
1053
EchoToClientsForSession(uint32_t targetSessionId,const string & echo)1054 void HdcServer::EchoToClientsForSession(uint32_t targetSessionId, const string &echo)
1055 {
1056 HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
1057 WRITE_LOG(LOG_INFO, "%s:%u %s", __FUNCTION__, targetSessionId, echo.c_str());
1058 hSfc->EchoToAllChannelsViaSessionId(targetSessionId, echo);
1059 }
1060 } // namespace Hdc
1061