• 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 "client.h"
16 #ifndef TEST_HASH
17 #include "hdc_hash_gen.h"
18 #endif
19 #include "host_updater.h"
20 #include "server.h"
21 #ifdef __OHOS__
22 #include <sys/un.h>
23 #endif
24 #include "file.h"
25 
26 std::map<std::string, std::string> g_lists;
27 bool g_show = true;
28 
29 namespace Hdc {
30 bool g_terminalStateChange = false;
HdcClient(const bool serverOrClient,const string & addrString,uv_loop_t * loopMainIn,bool checkVersion)31 HdcClient::HdcClient(const bool serverOrClient, const string &addrString, uv_loop_t *loopMainIn, bool checkVersion)
32     : HdcChannelBase(serverOrClient, addrString, loopMainIn)
33 {
34 #ifdef __OHOS__
35     serverAddress = addrString;
36     channel = new HdcChannel();
37     channel->isUds = (serverAddress.empty() || serverAddress == UDS_STR);
38 #endif
39     MallocChannel(&channel);  // free by logic
40     debugRetryCount = 0;
41 #ifndef _WIN32
42     Base::ZeroStruct(terminalState);
43 #endif
44     isCheckVersionCmd = checkVersion;
45 }
46 
~HdcClient()47 HdcClient::~HdcClient()
48 {
49 #ifndef _WIN32
50     if (g_terminalStateChange) {
51         tcsetattr(STDIN_FILENO, TCSAFLUSH, &terminalState);
52     }
53 #endif
54     Base::TryCloseLoop(loopMain, "ExecuteCommand finish");
55 }
56 
NotifyInstanceChannelFree(HChannel hChannel)57 void HdcClient::NotifyInstanceChannelFree(HChannel hChannel)
58 {
59     if (bShellInteractive) {
60         WRITE_LOG(LOG_DEBUG, "Restore tty");
61         ModifyTty(false, &hChannel->stdinTty);
62     }
63 }
64 
GetLastPID()65 uint32_t HdcClient::GetLastPID()
66 {
67     char bufPath[BUF_SIZE_MEDIUM] = "";
68     char pidBuf[BUF_SIZE_TINY] = "";
69     // get running pid to kill it
70     size_t size = BUF_SIZE_MEDIUM;
71 #ifdef HOST_OHOS
72     if (uv_os_homedir(bufPath, &size) < 0) {
73         WRITE_LOG(LOG_FATAL, "Homepath failed");
74         return 0;
75     }
76 #else
77     if (uv_os_tmpdir(bufPath, &size) < 0) {
78         WRITE_LOG(LOG_FATAL, "Tmppath failed");
79         return 0;
80     }
81 #endif
82     string path = Base::StringFormat("%s%c.%s.pid", bufPath, Base::GetPathSep(), SERVER_NAME.c_str());
83     Base::ReadBinFile(path.c_str(), reinterpret_cast<void **>(&pidBuf), BUF_SIZE_TINY);
84     int pid = atoi(pidBuf);  // pid  maybe 0
85     return pid;
86 }
87 
StartServer(const string & cmd)88 bool HdcClient::StartServer(const string &cmd)
89 {
90     int serverStatus = Base::ProgramMutex(SERVER_NAME.c_str(), true);
91     if (serverStatus < 0) {
92         WRITE_LOG(LOG_DEBUG, "get server status failed, serverStatus:%d", serverStatus);
93         return false;
94     }
95 
96     // server is not running
97     if (serverStatus == 0) {
98         HdcServer::PullupServer(channelHostPort.c_str());
99         return true;
100     }
101 
102     // server is running
103     if (cmd.find(" -r") == std::string::npos) {
104         return true;
105     }
106 
107     // restart server
108     uint32_t pid = GetLastPID();
109     if (pid == 0) {
110         Base::PrintMessage(TERMINAL_HDC_PROCESS_FAILED.c_str());
111         return false;
112     }
113     int rc = uv_kill(pid, SIGKILL);
114     WRITE_LOG(LOG_DEBUG, "uv_kill rc:%d", rc);
115     HdcServer::PullupServer(channelHostPort.c_str());
116     return true;
117 }
118 
ChannelCtrlServerStart(const char * listenString)119 void HdcClient::ChannelCtrlServerStart(const char *listenString)
120 {
121     Base::PrintMessage("hdc start server, listening: %s", channelHostPort.c_str());
122     HdcServer::PullupServer(channelHostPort.c_str());
123     uv_sleep(START_CMD_WAIT_TIME);
124     ExecuteCommand(CMDSTR_SERVICE_START.c_str());
125 }
126 
ChannelCtrlServer(const string & cmd,string & connectKey)127 bool HdcClient::ChannelCtrlServer(const string &cmd, string &connectKey)
128 {
129     // new version build channle to send Ctrl command to server
130     int serverStatus = Base::ProgramMutex(SERVER_NAME.c_str(), true);
131     if (serverStatus < 0) {
132         WRITE_LOG(LOG_DEBUG, "get server status failed, serverStatus:%d", serverStatus);
133         return false;
134     }
135     bool isRestart = (cmd.find(" -r") != std::string::npos);
136     bool isKill = !strncmp(cmd.c_str(), CMDSTR_SERVICE_KILL.c_str(), CMDSTR_SERVICE_KILL.size());
137     bool isStart = !strncmp(cmd.c_str(), CMDSTR_SERVICE_START.c_str(), CMDSTR_SERVICE_START.size());
138     if (isKill) {
139         Base::PrintMessage("[E002201]Kill server failed, unsupport channel kill.");
140         return false;
141     }
142     if (!isStart) {
143         Base::PrintMessage("[E002202]Unsupport command or parameters");
144         return false;
145     }
146     Initial(connectKey);
147     // server is not running, "hdc start [-r]" and "hdc kill -r" will start server directly.
148     if (serverStatus == 0) {
149         HdcServer::PullupServer(channelHostPort.c_str());
150         return true;
151     }
152     // server is running
153     if (isRestart) { // "hdc start -r": kill and restart server.
154         if (!KillMethodByUv(true)) {
155             return false;
156         }
157         HdcServer::PullupServer(channelHostPort.c_str());
158     }
159     return true;
160 }
161 
KillMethodByUv(bool isStart)162 bool HdcClient::KillMethodByUv(bool isStart)
163 {
164     uint32_t pid = GetLastPID();
165     if (pid == 0) {
166         Base::PrintMessage(TERMINAL_HDC_PROCESS_FAILED.c_str());
167         return false;
168     }
169     int rc = uv_kill(pid, SIGKILL);
170     if (isStart) {
171         return true;
172     }
173     if (rc == 0) {
174         Base::PrintMessage("Kill server finish");
175     } else {
176         constexpr int size = 1024;
177         char buf[size] = { 0 };
178         uv_strerror_r(rc, buf, size);
179         Base::PrintMessage("Kill server failed %s", buf);
180         return false;
181     }
182     return true;
183 }
184 
KillServer(const string & cmd)185 bool HdcClient::KillServer(const string &cmd)
186 {
187     int serverStatus = Base::ProgramMutex(SERVER_NAME.c_str(), true);
188     if (serverStatus < 0) {
189         WRITE_LOG(LOG_FATAL, "get server status failed, serverStatus:%d", serverStatus);
190         return false;
191     }
192 
193     // server is running
194     if (serverStatus != 0 && !KillMethodByUv(false)) {
195         return false;
196     }
197 
198     // server need to restart
199     if (cmd.find(" -r") != std::string::npos) {
200         string connectKey;
201         HdcServer::PullupServer(channelHostPort.c_str());
202         uv_sleep(START_SERVER_FOR_CLIENT_TIME);
203     }
204     return true;
205 }
206 
DoCtrlServiceWork(uv_check_t * handle)207 void HdcClient::DoCtrlServiceWork(uv_check_t *handle)
208 {
209     HdcClient *thisClass = (HdcClient *)handle->data;
210     CALLSTAT_GUARD(thisClass->loopMainStatus, handle->loop, "HdcClient::DoCtrlServiceWork");
211     string &strCmd = thisClass->command;
212     if (!strncmp(thisClass->command.c_str(), CMDSTR_SERVICE_START.c_str(), CMDSTR_SERVICE_START.size())) {
213         thisClass->StartServer(strCmd);
214     } else if (!strncmp(thisClass->command.c_str(), CMDSTR_SERVICE_KILL.c_str(), CMDSTR_SERVICE_KILL.size())) {
215         thisClass->KillServer(strCmd);
216         // clang-format off
217     } else if (!strncmp(thisClass->command.c_str(), CMDSTR_GENERATE_KEY.c_str(), CMDSTR_GENERATE_KEY.size()) &&
218                 strCmd.find(" ") != std::string::npos) {
219         // clang-format on
220         string keyPath = strCmd.substr(CMDSTR_GENERATE_KEY.size() + 1, strCmd.size());
221         HdcAuth::GenerateKey(keyPath.c_str());
222     } else {
223         Base::PrintMessage("Unknown command");
224     }
225     Base::TryCloseHandle((const uv_handle_t *)handle);
226 }
227 
CtrlServiceWork(const char * commandIn)228 int HdcClient::CtrlServiceWork(const char *commandIn)
229 {
230     command = commandIn;
231     ctrlServerWork.data = this;
232     uv_check_init(loopMain, &ctrlServerWork);
233     uv_check_start(&ctrlServerWork, DoCtrlServiceWork);
234     uv_run(loopMain, UV_RUN_NOWAIT);
235     return 0;
236 }
237 
AutoConnectKey(string & doCommand,const string & preConnectKey) const238 string HdcClient::AutoConnectKey(string &doCommand, const string &preConnectKey) const
239 {
240     string key = preConnectKey;
241     bool isNoTargetCommand = false;
242     vector<string> vecNoConnectKeyCommand;
243     vecNoConnectKeyCommand.push_back(CMDSTR_SOFTWARE_VERSION);
244     vecNoConnectKeyCommand.push_back(CMDSTR_SOFTWARE_HELP);
245     vecNoConnectKeyCommand.push_back(CMDSTR_TARGET_DISCOVER);
246 #ifdef HOST_OHOS
247     vecNoConnectKeyCommand.push_back(CMDSTR_SERVICE_KILL);
248 #endif
249     vecNoConnectKeyCommand.push_back(CMDSTR_LIST_TARGETS);
250     vecNoConnectKeyCommand.push_back(CMDSTR_CHECK_SERVER);
251     vecNoConnectKeyCommand.push_back(CMDSTR_CONNECT_TARGET);
252     vecNoConnectKeyCommand.push_back(CMDSTR_CHECK_DEVICE);
253     vecNoConnectKeyCommand.push_back(CMDSTR_WAIT_FOR);
254     vecNoConnectKeyCommand.push_back(CMDSTR_FORWARD_FPORT + " ls");
255     vecNoConnectKeyCommand.push_back(CMDSTR_FORWARD_FPORT + " rm");
256     for (string v : vecNoConnectKeyCommand) {
257         if (!doCommand.compare(0, v.size(), v)) {
258             isNoTargetCommand = true;
259             break;
260         }
261     }
262     if (isNoTargetCommand) {
263         if (this->command != CMDSTR_WAIT_FOR) {
264             key = "";
265         }
266     } else {
267         if (!preConnectKey.size()) {
268             key = CMDSTR_CONNECT_ANY;
269         }
270     }
271     return key;
272 }
273 
274 #ifdef _WIN32
ReadFileThreadFunc(void * arg)275 static void ReadFileThreadFunc(void* arg)
276 {
277     char buffer[BUF_SIZE_DEFAULT] = { 0 };
278     DWORD bytesRead = 0;
279 
280     HANDLE* read = reinterpret_cast<HANDLE*>(arg);
281     while (true) {
282         if (!ReadFile(*read, buffer, BUF_SIZE_DEFAULT - 1, &bytesRead, NULL)) {
283             break;
284         }
285         string str = std::to_string(bytesRead);
286         const char* zero = "0";
287         if (!strncmp(zero, str.c_str(), strlen(zero))) {
288             return;
289         }
290         printf("%s", buffer);
291         if (memset_s(buffer, sizeof(buffer), 0, sizeof(buffer)) != EOK) {
292             return;
293         }
294     }
295 }
296 
GetHilogPath()297 string HdcClient::GetHilogPath()
298 {
299     string hdcPath = Base::GetHdcAbsolutePath();
300     int index = hdcPath.find_last_of(Base::GetPathSep());
301     string exePath = hdcPath.substr(0, index) + Base::GetPathSep() + HILOG_NAME;
302 
303     return exePath;
304 }
305 
CreatePipePair(HANDLE * hParentRead,HANDLE * hSubWrite,HANDLE * hSubRead,HANDLE * hParentWrite,SECURITY_ATTRIBUTES * sa)306 bool HdcClient::CreatePipePair(HANDLE *hParentRead, HANDLE *hSubWrite, HANDLE *hSubRead, HANDLE *hParentWrite,
307     SECURITY_ATTRIBUTES *sa)
308 {
309     if (!CreatePipe(hParentRead, hSubWrite, sa, 0)) {
310         return false;
311     }
312     if (!CreatePipe(hSubRead, hParentWrite, sa, 0)) {
313         CloseHandle(*hParentRead);
314         CloseHandle(*hSubWrite);
315         return false;
316     }
317     if (!SetHandleInformation(*hParentRead, HANDLE_FLAG_INHERIT, 0) ||
318         !SetHandleInformation(*hParentWrite, HANDLE_FLAG_INHERIT, 0)) {
319         CloseHandle(*hParentRead);
320         CloseHandle(*hSubWrite);
321         CloseHandle(*hSubRead);
322         CloseHandle(*hParentWrite);
323         return false;
324     }
325     return true;
326 }
327 
CreateChildProcess(HANDLE hSubWrite,HANDLE hSubRead,PROCESS_INFORMATION * pi,const string & cmd)328 bool HdcClient::CreateChildProcess(HANDLE hSubWrite, HANDLE hSubRead, PROCESS_INFORMATION *pi, const string& cmd)
329 {
330     STARTUPINFO si;
331     bool ret = false;
332 
333     ZeroMemory(&si, sizeof(STARTUPINFO));
334     si.cb = sizeof(STARTUPINFO);
335     GetStartupInfo(&si);
336     si.hStdError = hSubWrite;
337     si.hStdOutput = hSubWrite;
338     si.hStdInput = hSubRead;
339     si.wShowWindow = SW_HIDE;
340     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
341 
342     do {
343         const char *msg = cmd.c_str();
344         char buffer[BUF_SIZE_SMALL] = {0};
345         if (strcpy_s(buffer, sizeof(buffer), msg) != EOK) {
346             break;
347         }
348         const string exePath = GetHilogPath();
349         if (!CreateProcess(_T(exePath.c_str()), _T(buffer), NULL, NULL, true, NULL, NULL, NULL, &si, pi)) {
350             WRITE_LOG(LOG_INFO, "create process failed, error:%d", GetLastError());
351             break;
352         }
353         ret = true;
354     } while (0);
355 
356     return ret;
357 }
358 
RunCommandWin32(const string & cmd)359 void HdcClient::RunCommandWin32(const string& cmd)
360 {
361     HANDLE hSubWrite;
362     HANDLE hParentRead;
363     HANDLE hParentWrite;
364     HANDLE hSubRead;
365     PROCESS_INFORMATION pi;
366     SECURITY_ATTRIBUTES sa;
367     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
368     sa.lpSecurityDescriptor = NULL;
369     sa.bInheritHandle = true;
370 
371     if (!CreatePipePair(&hParentRead, &hSubWrite, &hSubRead, &hParentWrite, &sa)) {
372         return;
373     }
374 
375     if (!CreateChildProcess(hSubWrite, hSubRead, &pi, cmd)) {
376         CloseHandle(hSubWrite);
377         CloseHandle(hParentRead);
378         CloseHandle(hParentWrite);
379         CloseHandle(hSubRead);
380     } else {
381         auto thread = std::thread([&hParentRead]() {
382             ReadFileThreadFunc(&hParentRead);
383         });
384         WaitForSingleObject(pi.hProcess, INFINITE);
385         CloseHandle(hSubWrite);
386         CloseHandle(pi.hProcess);
387         CloseHandle(pi.hThread);
388         thread.join();
389         CloseHandle(hParentRead);
390         CloseHandle(hParentWrite);
391         CloseHandle(hSubRead);
392     }
393 }
394 #else
RunCommand(const string & cmd)395 void HdcClient::RunCommand(const string& cmd)
396 {
397     FILE *procFileInfo = nullptr;
398     procFileInfo = popen(cmd.c_str(), "r");
399     if (procFileInfo == nullptr) {
400         perror("popen execute failed");
401         return;
402     }
403     char resultBufShell[BUF_SIZE_DEFAULT] = {0};
404     while (fgets(resultBufShell, sizeof(resultBufShell), procFileInfo) != nullptr) {
405         printf("%s", resultBufShell);
406         if (memset_s(resultBufShell, sizeof(resultBufShell), 0, sizeof(resultBufShell)) != EOK) {
407             break;
408         }
409     }
410     pclose(procFileInfo);
411 }
412 #endif
413 
RunExecuteCommand(const string & cmd)414 void HdcClient::RunExecuteCommand(const string& cmd)
415 {
416 #ifdef _WIN32
417     RunCommandWin32(cmd);
418 #else
419     RunCommand(cmd);
420 #endif
421 }
422 
IsCaptureCommand(const string & cmd)423 bool IsCaptureCommand(const string& cmd)
424 {
425     int index = string(CMDSTR_HILOG).length();
426     int length = cmd.length();
427     const string captureOption = "parse";
428     while (index < length) {
429         if (cmd[index] == ' ') {
430             index++;
431             continue;
432         }
433         if (!strncmp(cmd.c_str() + index, captureOption.c_str(), captureOption.size())) {
434             return true;
435         } else {
436             return false;
437         }
438     }
439     return false;
440 }
441 
ExecuteCommand(const string & commandIn)442 int HdcClient::ExecuteCommand(const string &commandIn)
443 {
444     char ip[BUF_SIZE_TINY] = "";
445     uint16_t port = 0;
446     int ret = Base::ConnectKey2IPPort(channelHostPort.c_str(), ip, &port, sizeof(ip));
447     if (ret < 0) {
448 #ifndef __OHOS__
449         WRITE_LOG(LOG_FATAL, "ConnectKey2IPPort %s failed with %d",
450                   channelHostPort.c_str(), ret);
451         return -1;
452 #endif
453     }
454 
455     if (!strncmp(commandIn.c_str(), CMDSTR_HILOG.c_str(), CMDSTR_HILOG.size()) &&
456         IsCaptureCommand(commandIn)) {
457         RunExecuteCommand(commandIn);
458         return 0;
459     }
460 
461     if (!strncmp(commandIn.c_str(), CMDSTR_FILE_SEND.c_str(), CMDSTR_FILE_SEND.size()) ||
462         !strncmp(commandIn.c_str(), CMDSTR_FILE_RECV.c_str(), CMDSTR_FILE_RECV.size())) {
463         WRITE_LOG(LOG_DEBUG, "Set file send mode");
464         channel->remote = RemoteType::REMOTE_FILE;
465     }
466     if (!strncmp(commandIn.c_str(), CMDSTR_APP_INSTALL.c_str(), CMDSTR_APP_INSTALL.size())) {
467         channel->remote = RemoteType::REMOTE_APP;
468     }
469     command = commandIn;
470     connectKey = AutoConnectKey(command, connectKey);
471 #ifdef __OHOS__
472     AdminChannel(OP_UPDATE, channel->channelId, channel);
473     if (channel->isUds) {
474         ConnectUdsServerForClient();
475     } else {
476         ConnectServerForClient(ip, port);
477     }
478 #else
479     ConnectServerForClient(ip, port);
480 #endif
481     uv_timer_init(loopMain, &waitTimeDoCmd);
482     waitTimeDoCmd.data = this;
483     uv_timer_start(&waitTimeDoCmd, CommandWorker, UV_START_TIMEOUT, UV_START_REPEAT);
484     WorkerPendding();
485     return 0;
486 }
487 
Initial(const string & connectKeyIn)488 int HdcClient::Initial(const string &connectKeyIn)
489 {
490     connectKey = connectKeyIn;
491 #ifdef __OHOS__
492     if (channel->isUds) {
493         return 0;
494     }
495 #endif
496     if (!channelHostPort.size() || !channelHost.size() || !channelPort) {
497         WRITE_LOG(LOG_FATAL, "Listen string initial failed");
498         return ERR_PARM_FAIL;
499     }
500     return 0;
501 }
502 
503 #ifdef __OHOS__
ConnectUdsServerForClient()504 int HdcClient::ConnectUdsServerForClient()
505 {
506     if (uv_is_closing((const uv_handle_t *)&channel->hWorkUds)) {
507         WRITE_LOG(LOG_FATAL, "ConnectServerForClient uv_is_closing");
508         return ERR_SOCKET_FAIL;
509     }
510     WRITE_LOG(LOG_DEBUG, "Try to connect uds");
511     uv_connect_t *conn = new(std::nothrow) uv_connect_t();
512     if (conn == nullptr) {
513         WRITE_LOG(LOG_FATAL, "ConnectServerForClient new conn failed");
514         return ERR_GENERIC;
515     }
516     conn->data = this;
517     udsConnectRetryCount = 0;
518     uv_timer_init(loopMain, &retryUdsConnTimer);
519     retryUdsConnTimer.data = this;
520 
521     uv_pipe_connect(conn, (uv_pipe_t *)&channel->hWorkUds, UDS_PATH.c_str(), ConnectUds);
522     return 0;
523 }
524 #endif
525 
ConnectServerForClient(const char * ip,uint16_t port)526 int HdcClient::ConnectServerForClient(const char *ip, uint16_t port)
527 {
528     if (uv_is_closing((const uv_handle_t *)&channel->hWorkTCP)) {
529         WRITE_LOG(LOG_FATAL, "ConnectServerForClient uv_is_closing");
530         return ERR_SOCKET_FAIL;
531     }
532     WRITE_LOG(LOG_DEBUG, "Try to connect %s:%d", ip, port);
533     uv_connect_t *conn = new(std::nothrow) uv_connect_t();
534     if (conn == nullptr) {
535         WRITE_LOG(LOG_FATAL, "ConnectServerForClient new conn failed");
536         return ERR_GENERIC;
537     }
538     conn->data = this;
539     tcpConnectRetryCount = 0;
540     uv_timer_init(loopMain, &retryTcpConnTimer);
541     retryTcpConnTimer.data = this;
542     if (strchr(ip, '.')) {
543         isIpV4 = true;
544         std::string s = ip;
545         size_t index = s.find(IPV4_MAPPING_PREFIX);
546         size_t size = IPV4_MAPPING_PREFIX.size();
547         if (index != std::string::npos) {
548             s = s.substr(index + size);
549         }
550         WRITE_LOG(LOG_DEBUG, "ConnectServerForClient ipv4 %s:%d", s.c_str(), port);
551         uv_ip4_addr(s.c_str(), port, &destv4);
552         uv_tcp_connect(conn, (uv_tcp_t *)&channel->hWorkTCP, (const struct sockaddr *)&destv4, Connect);
553     } else {
554         isIpV4 = false;
555         WRITE_LOG(LOG_DEBUG, "ConnectServerForClient ipv6 %s:%d", ip, port);
556         uv_ip6_addr(ip, port, &dest);
557         uv_tcp_connect(conn, (uv_tcp_t *)&channel->hWorkTCP, (const struct sockaddr *)&dest, Connect);
558     }
559     return 0;
560 }
561 
CommandWorker(uv_timer_t * handle)562 void HdcClient::CommandWorker(uv_timer_t *handle)
563 {
564     const uint16_t maxWaitRetry = 1200; // client socket try 12s
565     HdcClient *thisClass = (HdcClient *)handle->data;
566     CALLSTAT_GUARD(thisClass->loopMainStatus, handle->loop, "HdcClient::CommandWorker");
567     if (++thisClass->debugRetryCount > maxWaitRetry) {
568         uv_timer_stop(handle);
569         uv_stop(thisClass->loopMain);
570         WRITE_LOG(LOG_DEBUG, "Connect server failed");
571         fprintf(stderr, "Connect server failed\n");
572         return;
573     }
574     if (!thisClass->channel->handshakeOK) {
575         return;
576     }
577     uv_timer_stop(handle);
578 #ifdef HOST_OHOS
579     if (!strncmp(thisClass->command.c_str(), CMDSTR_SERVICE_KILL.c_str(),
580         CMDSTR_SERVICE_KILL.size()) && !thisClass->channel->isSupportedKillServerCmd) {
581         WRITE_LOG(LOG_DEBUG, "uv_kill server");
582         thisClass->CtrlServiceWork(CMDSTR_SERVICE_KILL.c_str());
583         return;
584     }
585 #endif
586     WRITE_LOG(LOG_DEBUG, "Connect server successful");
587     bool closeInput = false;
588     if (!HostUpdater::ConfirmCommand(thisClass->command, closeInput)) {
589         uv_timer_stop(handle);
590         uv_stop(thisClass->loopMain);
591         WRITE_LOG(LOG_DEBUG, "Cmd \'%s\' has been canceld", thisClass->command.c_str());
592         return;
593     }
594     while (closeInput) {
595 #ifndef _WIN32
596         if (tcgetattr(STDIN_FILENO, &thisClass->terminalState)) {
597             break;
598         }
599         termios tio;
600         if (tcgetattr(STDIN_FILENO, &tio)) {
601             break;
602         }
603         cfmakeraw(&tio);
604         tio.c_cc[VTIME] = 0;
605         tio.c_cc[VMIN] = 1;
606         tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
607         g_terminalStateChange = true;
608 #endif
609         break;
610     }
611     thisClass->Send(thisClass->channel->channelId,
612                     const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(thisClass->command.c_str())),
613                     thisClass->command.size() + 1);
614 }
615 
AllocStdbuf(uv_handle_t * handle,size_t sizeWanted,uv_buf_t * buf)616 void HdcClient::AllocStdbuf(uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf)
617 {
618     if (sizeWanted <= 0) {
619         return;
620     }
621     HChannel context = (HChannel)handle->data;
622     int availSize = strlen(context->bufStd);
623     buf->base = (char *)context->bufStd + availSize;
624     buf->len = sizeof(context->bufStd) - availSize - 2;  // reserve 2bytes
625 }
626 
ReadStd(uv_stream_t * stream,ssize_t nread,const uv_buf_t * buf)627 void HdcClient::ReadStd(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
628 {
629     HChannel hChannel = (HChannel)stream->data;
630     HdcClient *thisClass = (HdcClient *)hChannel->clsChannel;
631     CALLSTAT_GUARD(thisClass->loopMainStatus, stream->loop, "HdcClient::ReadStd");
632     if (!hChannel->handshakeOK) {
633         WRITE_LOG(LOG_WARN, "ReadStd handshake not ready");
634         return; // if not handshake, do not send the cmd input to server.
635     }
636     char *cmd = hChannel->bufStd;
637     if (nread <= 0) {
638         WRITE_LOG(LOG_FATAL, "ReadStd error nread:%zd", nread);
639         return;  // error
640     }
641     thisClass->Send(hChannel->channelId, reinterpret_cast<uint8_t *>(cmd), strlen(cmd));
642     Base::ZeroArray(hChannel->bufStd);
643 }
644 
ModifyTty(bool setOrRestore,uv_tty_t * tty)645 void HdcClient::ModifyTty(bool setOrRestore, uv_tty_t *tty)
646 {
647     if (setOrRestore) {
648 #ifdef _WIN32
649         uv_tty_set_mode(tty, UV_TTY_MODE_RAW);
650 #else
651         if (tcgetattr(STDIN_FILENO, &terminalState)) {
652             return;
653         }
654         termios tio;
655         if (tcgetattr(STDIN_FILENO, &tio)) {
656             return;
657         }
658         cfmakeraw(&tio);
659         tio.c_cc[VTIME] = 0;
660         tio.c_cc[VMIN] = 1;
661         tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
662 #endif
663     } else {
664 #ifndef _WIN32
665         tcsetattr(STDIN_FILENO, TCSAFLUSH, &terminalState);
666 #endif
667     }
668 }
669 
BindLocalStd(HChannel hChannel)670 void HdcClient::BindLocalStd(HChannel hChannel)
671 {
672     if (command == CMDSTR_SHELL) {
673         bShellInteractive = true;
674     }
675     if (bShellInteractive && uv_guess_handle(STDIN_FILENO) != UV_TTY) {
676         WRITE_LOG(LOG_WARN, "Not support stdio TTY mode");
677         return;
678     }
679 
680     WRITE_LOG(LOG_DEBUG, "setup stdio TTY mode");
681     if (uv_tty_init(loopMain, &hChannel->stdoutTty, STDOUT_FILENO, 0)
682         || uv_tty_init(loopMain, &hChannel->stdinTty, STDIN_FILENO, 1)) {
683         WRITE_LOG(LOG_DEBUG, "uv_tty_init failed");
684         return;
685     }
686     hChannel->stdoutTty.data = hChannel;
687     ++hChannel->uvHandleRef;
688     hChannel->stdinTty.data = hChannel;
689     ++hChannel->uvHandleRef;
690     if (bShellInteractive) {
691         WRITE_LOG(LOG_DEBUG, "uv_tty_init uv_tty_set_mode");
692         ModifyTty(true, &hChannel->stdinTty);
693         uv_read_start((uv_stream_t *)&hChannel->stdinTty, AllocStdbuf, ReadStd);
694     }
695 }
696 
697 #ifdef __OHOS__
ConnectUds(uv_connect_t * connection,int status)698 void HdcClient::ConnectUds(uv_connect_t *connection, int status)
699 {
700     WRITE_LOG(LOG_DEBUG, "Enter ConnectUds, status:%d", status);
701     HdcClient *thisClass = (HdcClient *)connection->data;
702     CALLSTAT_GUARD(thisClass->loopMainStatus, connection->handle->loop, "HdcClient::Connect");
703     delete connection;
704     HChannel hChannel = reinterpret_cast<HChannel>(thisClass->channel);
705     if (uv_is_closing((const uv_handle_t *)&hChannel->hWorkUds)) {
706         WRITE_LOG(LOG_DEBUG, "uv_is_closing...");
707         thisClass->FreeChannel(hChannel->channelId);
708         return;
709     }
710 
711     // connect success
712     if (status == 0) {
713         thisClass->BindLocalStd(hChannel);
714         Base::SetUdsOptions((uv_pipe_t *)&hChannel->hWorkUds);
715         WRITE_LOG(LOG_DEBUG, "uv_read_start");
716         uv_read_start((uv_stream_t *)&hChannel->hWorkUds, AllocCallback, ReadStream);
717         return;
718     }
719 
720     // connect failed, start timer and retry
721     WRITE_LOG(LOG_DEBUG, "retry count:%d", thisClass->udsConnectRetryCount);
722     if (thisClass->udsConnectRetryCount >= TCP_CONNECT_MAX_RETRY_COUNT) {
723         WRITE_LOG(LOG_DEBUG, "stop retry for connect");
724         thisClass->FreeChannel(hChannel->channelId);
725         return;
726     }
727     thisClass->udsConnectRetryCount++;
728     uv_timer_start(&(thisClass->retryUdsConnTimer), thisClass->RetryUdsConnectWorker, TCP_CONNECT_RETRY_TIME_MS, 0);
729 }
730 #endif
731 
Connect(uv_connect_t * connection,int status)732 void HdcClient::Connect(uv_connect_t *connection, int status)
733 {
734     WRITE_LOG(LOG_DEBUG, "Enter Connect, status:%d", status);
735     HdcClient *thisClass = (HdcClient *)connection->data;
736     CALLSTAT_GUARD(thisClass->loopMainStatus, connection->handle->loop, "HdcClient::Connect");
737     delete connection;
738     HChannel hChannel = reinterpret_cast<HChannel>(thisClass->channel);
739     if (uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP)) {
740         WRITE_LOG(LOG_DEBUG, "uv_is_closing...");
741         thisClass->FreeChannel(hChannel->channelId);
742         return;
743     }
744 
745     // connect success
746     if (status == 0) {
747         thisClass->BindLocalStd(hChannel);
748         Base::SetTcpOptions((uv_tcp_t *)&hChannel->hWorkTCP);
749         WRITE_LOG(LOG_DEBUG, "uv_read_start");
750         uv_read_start((uv_stream_t *)&hChannel->hWorkTCP, AllocCallback, ReadStream);
751         return;
752     }
753 
754     // connect failed, start timer and retry
755     WRITE_LOG(LOG_DEBUG, "retry count:%d", thisClass->tcpConnectRetryCount);
756     if (thisClass->tcpConnectRetryCount >= TCP_CONNECT_MAX_RETRY_COUNT) {
757         WRITE_LOG(LOG_DEBUG, "stop retry for connect");
758         thisClass->FreeChannel(hChannel->channelId);
759         return;
760     }
761     thisClass->tcpConnectRetryCount++;
762     uv_timer_start(&(thisClass->retryTcpConnTimer), thisClass->RetryTcpConnectWorker, TCP_CONNECT_RETRY_TIME_MS, 0);
763 }
764 
765 #ifdef __OHOS__
RetryUdsConnectWorker(uv_timer_t * handle)766 void HdcClient::RetryUdsConnectWorker(uv_timer_t *handle)
767 {
768     HdcClient *thisClass = (HdcClient *)handle->data;
769     HChannel hChannel = reinterpret_cast<HChannel>(thisClass->channel);
770     CALLSTAT_GUARD(thisClass->loopMainStatus, handle->loop, "HdcClient::RetryUdsConnectWorker");
771     uv_connect_t *connection = new(std::nothrow) uv_connect_t();
772     if (connection == nullptr) {
773         WRITE_LOG(LOG_FATAL, "RetryUdsConnectWorker new conn failed");
774         thisClass->FreeChannel(hChannel->channelId);
775         return;
776     }
777     connection->data = thisClass;
778     WRITE_LOG(LOG_DEBUG, "RetryUdsConnectWorker start tcp connect");
779     uv_pipe_connect(connection, &(thisClass->channel->hWorkUds), UDS_PATH.c_str(), thisClass->ConnectUds);
780 }
781 #endif
782 
RetryTcpConnectWorker(uv_timer_t * handle)783 void HdcClient::RetryTcpConnectWorker(uv_timer_t *handle)
784 {
785     HdcClient *thisClass = (HdcClient *)handle->data;
786     HChannel hChannel = reinterpret_cast<HChannel>(thisClass->channel);
787     CALLSTAT_GUARD(thisClass->loopMainStatus, handle->loop, "HdcClient::RetryTcpConnectWorker");
788     uv_connect_t *connection = new(std::nothrow) uv_connect_t();
789     if (connection == nullptr) {
790         WRITE_LOG(LOG_FATAL, "RetryTcpConnectWorker new conn failed");
791         thisClass->FreeChannel(hChannel->channelId);
792         return;
793     }
794     connection->data = thisClass;
795     WRITE_LOG(LOG_DEBUG, "RetryTcpConnectWorker start tcp connect");
796     if (thisClass->isIpV4) {
797         uv_tcp_connect(connection, &(thisClass->channel->hWorkTCP),
798             (const struct sockaddr *)&(thisClass->destv4), thisClass->Connect);
799     } else {
800         uv_tcp_connect(connection, &(thisClass->channel->hWorkTCP),
801             (const struct sockaddr *)&(thisClass->dest), thisClass->Connect);
802     }
803 }
804 
PreHandshake(HChannel hChannel,const uint8_t * buf)805 int HdcClient::PreHandshake(HChannel hChannel, const uint8_t *buf)
806 {
807     ChannelHandShake *hShake = reinterpret_cast<ChannelHandShake *>(const_cast<uint8_t *>(buf));
808     if (strncmp(hShake->banner, HANDSHAKE_MESSAGE.c_str(), HANDSHAKE_MESSAGE.size())) {
809         hChannel->availTailIndex = 0;
810         WRITE_LOG(LOG_DEBUG, "Channel Hello failed");
811         return ERR_BUF_CHECK;
812     }
813     hChannel->isStableBuf = (hShake->banner[BANNER_FEATURE_TAG_OFFSET] != HUGE_BUF_TAG);
814 #ifdef HOST_OHOS
815     hChannel->isSupportedKillServerCmd = (hShake->banner[SERVICE_KILL_OFFSET] == SERVICE_KILL_TAG);
816     WRITE_LOG(LOG_DEBUG, "Channel PreHandshake isStableBuf:%d, killflag:%d",
817         hChannel->isStableBuf, hChannel->isSupportedKillServerCmd);
818 #else
819     WRITE_LOG(LOG_DEBUG, "Channel PreHandshake isStableBuf:%d", hChannel->isStableBuf);
820 #endif
821     if (this->command == CMDSTR_WAIT_FOR && !connectKey.empty()) {
822         hShake->banner[WAIT_TAG_OFFSET] = WAIT_DEVICE_TAG;
823     }
824     // sync remote session id to local
825     uint32_t unOld = hChannel->channelId;
826     hChannel->channelId = ntohl(hShake->channelId);
827     AdminChannel(OP_UPDATE, unOld, hChannel);
828     WRITE_LOG(LOG_DEBUG, "Client channel handshake finished, use connectkey:%s",
829               Hdc::MaskString(connectKey).c_str());
830     // send config
831     // channel handshake step2
832     if (memset_s(hShake->connectKey, sizeof(hShake->connectKey), 0, sizeof(hShake->connectKey)) != EOK
833         || memcpy_s(hShake->connectKey, sizeof(hShake->connectKey), connectKey.c_str(), connectKey.size()) != EOK) {
834         hChannel->availTailIndex = 0;
835         WRITE_LOG(LOG_DEBUG, "Channel Hello failed");
836         return ERR_BUF_COPY;
837     }
838 #ifdef HDC_VERSION_CHECK
839     // add check version
840     if (!isCheckVersionCmd) { // do not check version cause user want to get server version
841         string clientVer = Base::GetVersion() + HDC_MSG_HASH;
842         string serverVer(hShake->version);
843         if (clientVer != serverVer) {
844             serverVer = serverVer.substr(0, Base::GetVersion().size());
845             WRITE_LOG(LOG_FATAL, "Client version:%s, server version:%s", clientVer.c_str(), serverVer.c_str());
846             hChannel->availTailIndex = 0;
847             return ERR_CHECK_VERSION;
848         }
849     }
850     Send(hChannel->channelId, reinterpret_cast<uint8_t *>(hShake), sizeof(ChannelHandShake));
851 #else
852         // do not send version message if check feature disable
853     Send(hChannel->channelId, reinterpret_cast<uint8_t *>(hShake), offsetof(struct ChannelHandShake, version));
854 #endif
855     hChannel->handshakeOK = true;
856 #ifdef HDC_CHANNEL_KEEP_ALIVE
857     // Evaluation method, non long-term support
858     Send(hChannel->channelId,
859          reinterpret_cast<uint8_t *>(const_cast<char*>(CMDSTR_INNER_ENABLE_KEEPALIVE.c_str())),
860          CMDSTR_INNER_ENABLE_KEEPALIVE.size());
861 #endif
862     return RET_SUCCESS;
863 }
864 
865 // read serverForClient(server)TCP data
ReadChannel(HChannel hChannel,uint8_t * buf,const int bytesIO)866 int HdcClient::ReadChannel(HChannel hChannel, uint8_t *buf, const int bytesIO)
867 {
868     if (!hChannel->handshakeOK) {
869         return PreHandshake(hChannel, buf);
870     }
871 #ifdef UNIT_TEST
872     // Do not output to console when the unit test
873     return 0;
874 #endif
875     WRITE_LOG(LOG_DEBUG, "Client ReadChannel :%d", bytesIO);
876 
877     uint16_t cmd = 0;
878     bool bOffset = false;
879     if (bytesIO >= static_cast<int>(sizeof(uint16_t))) {
880         cmd = *reinterpret_cast<uint16_t *>(buf);
881         bOffset = IsOffset(cmd);
882     }
883     if (cmd == CMD_CHECK_SERVER && isCheckVersionCmd) {
884         WRITE_LOG(LOG_DEBUG, "recieve CMD_CHECK_VERSION command");
885         string version(reinterpret_cast<char *>(buf + sizeof(uint16_t)), bytesIO - sizeof(uint16_t));
886         fprintf(stdout, "Client version:%s, server version:%s\n", Base::GetVersion().c_str(), version.c_str());
887         fflush(stdout);
888         return 0;
889     }
890     if (hChannel->remote > RemoteType::REMOTE_NONE && bOffset) {
891         // file command
892         if (hChannel->remote == RemoteType::REMOTE_FILE) {
893             if (fileTask == nullptr) {
894                 HTaskInfo hTaskInfo = GetRemoteTaskInfo(hChannel);
895                 hTaskInfo->masterSlave = (cmd == CMD_FILE_INIT);
896                 fileTask = std::make_unique<HdcFile>(hTaskInfo);
897             }
898             if (!fileTask->CommandDispatch(cmd, buf + sizeof(uint16_t), bytesIO - sizeof(uint16_t))) {
899                 fileTask->TaskFinish();
900             }
901         }
902         // app command
903         if (hChannel->remote == RemoteType::REMOTE_APP) {
904             if (appTask == nullptr) {
905                 HTaskInfo hTaskInfo = GetRemoteTaskInfo(hChannel);
906                 hTaskInfo->masterSlave = (cmd == CMD_APP_INIT);
907                 appTask = std::make_unique<HdcHostApp>(hTaskInfo);
908             }
909             if (!appTask->CommandDispatch(cmd, buf + sizeof(uint16_t), bytesIO - sizeof(uint16_t))) {
910                 appTask->TaskFinish();
911             }
912         }
913         return 0;
914     }
915 
916     string s(reinterpret_cast<char *>(buf), bytesIO);
917     if (WaitFor(s)) {
918         return 0;
919     }
920     s = ListTargetsAll(s);
921     if (g_show) {
922 #ifdef _WIN32
923         fprintf(stdout, "%s", s.c_str());
924         fflush(stdout);
925 #else
926         constexpr int len = 512;
927         int size = s.size() / len;
928         int left = s.size() % len;
929         for (int i = 0; i <= size; i++) {
930             int cnt = len;
931             const char *p = reinterpret_cast<char *>(buf) + i * cnt;
932             if (i == size) {
933                 cnt = left;
934             }
935             fprintf(stdout, "%.*s", cnt, p);
936             fflush(stdout);
937             std::this_thread::sleep_for(std::chrono::milliseconds(1));
938         }
939 #endif
940     }
941     return 0;
942 }
943 
WaitFor(const string & str)944 bool HdcClient::WaitFor(const string &str)
945 {
946     bool wait = false;
947     if (!strncmp(this->command.c_str(), CMDSTR_WAIT_FOR.c_str(), CMDSTR_WAIT_FOR.size())) {
948         const string waitFor = "[Fail]No any connected target";
949         if (!strncmp(str.c_str(), waitFor.c_str(), waitFor.size())) {
950             Send(this->channel->channelId, reinterpret_cast<uint8_t *>(const_cast<char *>(this->command.c_str())),
951                  this->command.size() + 1);
952             constexpr int timeout = 1;
953             std::this_thread::sleep_for(std::chrono::seconds(timeout));
954             wait = true;
955         } else {
956             _exit(0);
957         }
958     }
959     return wait;
960 }
961 
ListTargetsAll(const string & str)962 string HdcClient::ListTargetsAll(const string &str)
963 {
964     string all = str;
965     const string lists = "list targets -v";
966     if (!strncmp(this->command.c_str(), lists.c_str(), lists.size())) {
967         UpdateList(str);
968         all = Base::ReplaceAll(all, "\n", "\thdc\n");
969     } else if (!strncmp(this->command.c_str(), CMDSTR_LIST_TARGETS.c_str(), CMDSTR_LIST_TARGETS.size())) {
970         UpdateList(str);
971     }
972     if (!strncmp(this->command.c_str(), CMDSTR_LIST_TARGETS.c_str(), CMDSTR_LIST_TARGETS.size())) {
973         if (g_lists.size() > 0 && !strncmp(str.c_str(), EMPTY_ECHO.c_str(), EMPTY_ECHO.size())) {
974             all = "";
975         }
976     }
977     return all;
978 }
979 
UpdateList(const string & str)980 void HdcClient::UpdateList(const string &str)
981 {
982     if (!strncmp(str.c_str(), EMPTY_ECHO.c_str(), EMPTY_ECHO.size())) {
983         return;
984     }
985     vector<string> devs;
986     Base::SplitString(str, "\n", devs);
987     for (size_t i = 0; i < devs.size(); i++) {
988         string::size_type pos = devs[i].find("\t");
989         if (pos != string::npos) {
990             string key = devs[i].substr(0, pos);
991             g_lists[key] = "hdc";
992         } else {
993             string key = devs[i];
994             g_lists[key] = "hdc";
995         }
996     }
997 }
998 
IsOffset(uint16_t cmd)999 bool HdcClient::IsOffset(uint16_t cmd)
1000 {
1001     return (cmd == CMD_CHECK_SERVER) ||
1002            (cmd == CMD_FILE_INIT) ||
1003            (cmd == CMD_FILE_CHECK) ||
1004            (cmd == CMD_FILE_BEGIN) ||
1005            (cmd == CMD_FILE_DATA) ||
1006            (cmd == CMD_FILE_FINISH) ||
1007            (cmd == CMD_FILE_MODE) ||
1008            (cmd == CMD_DIR_MODE) ||
1009            (cmd == CMD_APP_INIT) ||
1010            (cmd == CMD_APP_CHECK) ||
1011            (cmd == CMD_APP_BEGIN) ||
1012            (cmd == CMD_APP_DATA) ||
1013            (cmd == CMD_APP_FINISH);
1014 }
1015 
GetRemoteTaskInfo(HChannel hChannel)1016 HTaskInfo HdcClient::GetRemoteTaskInfo(HChannel hChannel)
1017 {
1018     HTaskInfo hTaskInfo = new TaskInformation();
1019     hTaskInfo->channelId = hChannel->channelId;
1020     hTaskInfo->runLoop = loopMain;
1021     hTaskInfo->runLoopStatus = &loopMainStatus;
1022     hTaskInfo->serverOrDaemon = true;
1023     hTaskInfo->channelTask = true;
1024     hTaskInfo->channelClass = this;
1025     hTaskInfo->isStableBuf = hChannel->isStableBuf;
1026     hTaskInfo->isCleared = false;
1027     return hTaskInfo;
1028 };
1029 }  // namespace Hdc
1030