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