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