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
16 #include <iostream>
17
18 #include "server.h"
19 #include "server_for_client.h"
20
21 #ifndef HARMONY_PROJECT
22 #include "../test/ut_command.h"
23 using namespace HdcTest;
24 #endif
25
26 #include "server.h"
27 #include "server_for_client.h"
28 #include "ext_client.h"
29 using namespace Hdc;
30
31 namespace {
32 bool g_isServerMode = false;
33 bool g_isPullServer = true;
34 bool g_isPcDebugRun = false;
35 bool g_isTCPorUSB = false;
36 bool g_isCustomLoglevel = false;
37 bool g_externalCmd = false;
38 int g_isTestMethod = 0;
39 string g_connectKey = "";
40 string g_serverListenString = "";
41 string g_containerInOut = "";
42 }
43
44 namespace Hdc {
45 // return value: 0 == not command, 1 == one command, 2 == double command
IsRegisterCommand(string & outCommand,const char * cmd,const char * cmdnext)46 int IsRegisterCommand(string &outCommand, const char *cmd, const char *cmdnext)
47 {
48 string sCmdNext = cmdnext == nullptr ? string("") : string(cmdnext);
49 string doubleCommand = cmd + string(" ") + sCmdNext;
50 vector<string> registerCommand;
51 registerCommand.push_back(CMDSTR_SOFTWARE_VERSION);
52 registerCommand.push_back(CMDSTR_SOFTWARE_HELP);
53 registerCommand.push_back(CMDSTR_TARGET_DISCOVER);
54 registerCommand.push_back(CMDSTR_LIST_TARGETS);
55 registerCommand.push_back(CMDSTR_CHECK_SERVER);
56 registerCommand.push_back(CMDSTR_CHECK_DEVICE);
57 registerCommand.push_back(CMDSTR_WAIT_FOR);
58 registerCommand.push_back(CMDSTR_CONNECT_ANY);
59 registerCommand.push_back(CMDSTR_CONNECT_TARGET);
60 registerCommand.push_back(CMDSTR_SHELL);
61 registerCommand.push_back(CMDSTR_FILE_SEND);
62 registerCommand.push_back(CMDSTR_FILE_RECV);
63 registerCommand.push_back(CMDSTR_FORWARD_FPORT);
64 registerCommand.push_back(CMDSTR_FORWARD_RPORT);
65 registerCommand.push_back(CMDSTR_SERVICE_KILL);
66 registerCommand.push_back(CMDSTR_SERVICE_START);
67 registerCommand.push_back(CMDSTR_GENERATE_KEY);
68 registerCommand.push_back(CMDSTR_KILL_SERVER);
69 registerCommand.push_back(CMDSTR_KILL_DAEMON);
70 registerCommand.push_back(CMDSTR_APP_INSTALL);
71 registerCommand.push_back(CMDSTR_APP_UNINSTALL);
72 registerCommand.push_back(CMDSTR_TARGET_MOUNT);
73 registerCommand.push_back(CMDSTR_HILOG);
74 registerCommand.push_back(CMDSTR_STARTUP_MODE);
75 registerCommand.push_back(CMDSTR_BUGREPORT);
76 registerCommand.push_back(CMDSTR_TARGET_MODE);
77 registerCommand.push_back(CMDSTR_APP_SIDELOAD);
78 registerCommand.push_back(CMDSTR_TARGET_REBOOT);
79 registerCommand.push_back(CMDSTR_LIST_JDWP);
80 registerCommand.push_back(CMDSTR_TRACK_JDWP);
81 registerCommand.push_back(CMDSTR_FLASHD_UPDATE);
82 registerCommand.push_back(CMDSTR_FLASHD_FLASH);
83 registerCommand.push_back(CMDSTR_FLASHD_ERASE);
84 registerCommand.push_back(CMDSTR_FLASHD_FORMAT);
85
86 for (string v : registerCommand) {
87 if (doubleCommand == v) {
88 outCommand = doubleCommand;
89 return 2;
90 }
91 if (cmd == v || !strncmp(cmd, CMDSTR_WAIT_FOR.c_str(), CMDSTR_WAIT_FOR.size())) {
92 outCommand = cmd;
93 return 1;
94 }
95 }
96 return 0;
97 }
98
AppendCwdWhenTransfer(string & outCommand)99 void AppendCwdWhenTransfer(string &outCommand)
100 {
101 if (outCommand != CMDSTR_FILE_SEND && outCommand != CMDSTR_FILE_RECV && outCommand != CMDSTR_APP_INSTALL &&
102 outCommand != CMDSTR_APP_SIDELOAD) {
103 return;
104 }
105 int value = -1;
106 char path[PATH_MAX] = "";
107 size_t size = sizeof(path);
108 value = uv_cwd(path, &size);
109 if (value < 0) {
110 constexpr int bufSize = 1024;
111 char buf[bufSize] = { 0 };
112 uv_strerror_r(value, buf, bufSize);
113 WRITE_LOG(LOG_FATAL, "append cwd path failed: %s", buf);
114 return;
115 }
116 if (strlen(path) >= PATH_MAX - 1) {
117 WRITE_LOG(LOG_FATAL, "append cwd path failed: buffer space max");
118 return;
119 }
120 if (path[strlen(path) - 1] != Base::GetPathSep()) {
121 path[strlen(path)] = Base::GetPathSep();
122 }
123 outCommand += outCommand.size() ? " " : "";
124 outCommand += CMDSTR_REMOTE_PARAMETER;
125 outCommand += outCommand.size() ? " -cwd " : "-cwd ";
126 string utf8Path = Base::UnicodeToUtf8(path, true);
127 outCommand += Base::StringFormat("\"%s\"", utf8Path.c_str());
128 }
129
SplitOptionAndCommand(int argc,const char ** argv,string & outOption,string & outCommand)130 int SplitOptionAndCommand(int argc, const char **argv, string &outOption, string &outCommand)
131 {
132 bool foundCommand = false;
133 int resultChild = 0;
134 // we want to start from 1, ignore argv[0], but it has issue
135 for (int i = 0; i < argc; ++i) {
136 if (!foundCommand) {
137 resultChild = IsRegisterCommand(outCommand, argv[i], (i == argc - 1) ? nullptr : argv[i + 1]);
138 if (resultChild > 0) {
139 foundCommand = true;
140 if (resultChild == 2) {
141 ++i;
142 }
143 AppendCwdWhenTransfer(outCommand);
144 continue;
145 }
146 }
147 if (foundCommand) {
148 outCommand += outCommand.size() ? " " : "";
149 string rawCmd = argv[i];
150 string packageCmd = Base::StringFormat("\"%s\"", argv[i]);
151 outCommand += rawCmd.find(" ") == string::npos ? rawCmd : packageCmd;
152 } else {
153 outOption += outOption.size() ? " " : "";
154 if (i == 0) {
155 outOption += Base::StringFormat("\"%s\"", argv[i]);
156 } else {
157 outOption += argv[i];
158 }
159 }
160 }
161 return 0;
162 }
163
RunServerMode(string & serverListenString)164 int RunServerMode(string &serverListenString)
165 {
166 if (serverListenString.empty()) {
167 return -1;
168 }
169 HdcServer server(true);
170 if (!server.Initial(serverListenString.c_str())) {
171 Base::PrintMessage("Initial failed");
172 return -1;
173 }
174 server.WorkerPendding();
175 return 0;
176 }
177
RunPcDebugMode(bool isPullServer,bool isTCPorUSB,int isTestMethod)178 int RunPcDebugMode(bool isPullServer, bool isTCPorUSB, int isTestMethod)
179 {
180 #ifdef HARMONY_PROJECT
181 Base::PrintMessage("Not support command...");
182 #else
183 pthread_t pt;
184 if (isPullServer) {
185 pthread_create(&pt, nullptr, TestBackgroundServerForClient, nullptr);
186 uv_sleep(200); // give time to start serverForClient,at least 200ms
187 }
188 TestRuntimeCommandSimple(isTCPorUSB, isTestMethod, true);
189 if (isPullServer) {
190 pthread_join(pt, nullptr);
191 WRITE_LOG(LOG_DEBUG, "!!!!!!!!!Server finish");
192 }
193 #endif
194 return 0;
195 }
196
RunClientMode(string & commands,string & serverListenString,string & connectKey,bool isPullServer)197 int RunClientMode(string &commands, string &serverListenString, string &connectKey, bool isPullServer)
198 {
199 if (serverListenString.empty()) {
200 return -1;
201 }
202 uv_loop_t loopMain;
203 uv_loop_init(&loopMain);
204 HdcClient client(false, serverListenString, &loopMain, commands == CMDSTR_CHECK_SERVER);
205 if (!commands.size()) {
206 Base::PrintMessage("Unknown operation command...");
207 std::cerr << TranslateCommand::Usage();
208 return 0;
209 }
210 if (!strncmp(commands.c_str(), CMDSTR_SERVICE_START.c_str(), CMDSTR_SERVICE_START.size()) ||
211 !strncmp(commands.c_str(), CMDSTR_SERVICE_KILL.c_str(), CMDSTR_SERVICE_KILL.size()) ||
212 !strncmp(commands.c_str(), CMDSTR_GENERATE_KEY.c_str(), CMDSTR_GENERATE_KEY.size())) {
213 client.CtrlServiceWork(commands.c_str());
214 return 0;
215 }
216 if (isPullServer && Base::ProgramMutex(SERVER_NAME.c_str(), true) == 0) {
217 // default pullup, just default listenstr.If want to customer listen-string, please use 'hdc -m -s lanip:port'
218 HdcServer::PullupServer(serverListenString.c_str());
219 uv_sleep(300); // give time to start serverForClient,at least 200ms
220 }
221 client.Initial(connectKey);
222 client.ExecuteCommand(commands.c_str());
223 return 0;
224 }
225
ParseServerListenString(string & serverListenString,char * optarg)226 bool ParseServerListenString(string &serverListenString, char *optarg)
227 {
228 if (strlen(optarg) > strlen("0000::0000:0000:0000:0000:65535")) {
229 Base::PrintMessage("Unknown content of parament '-s'");
230 return false;
231 }
232 char buf[BUF_SIZE_TINY] = "";
233 if (strcpy_s(buf, sizeof(buf), optarg) != 0) {
234 Base::PrintMessage("strcpy_s error %d", errno);
235 return false;
236 }
237 char *p = strrchr(buf, ':');
238 if (!p) { // Only port
239 if (strlen(buf) > 5) {
240 Base::PrintMessage("The port-string's length must < 5");
241 return false;
242 }
243 size_t len = strlen(buf);
244 for (size_t i = 0; i < len; i++) {
245 if (isdigit(buf[i]) == 0) {
246 Base::PrintMessage("The port must be digit buf:%s", buf);
247 return false;
248 }
249 }
250 int port = atoi(buf);
251 if (port <= 0 || port > MAX_IP_PORT) {
252 Base::PrintMessage("Port range incorrect");
253 return false;
254 }
255 (void)snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "::ffff:127.0.0.1:%d", port);
256 serverListenString = buf;
257 } else {
258 *p = '\0';
259 char *str = p + 1;
260 size_t len = strlen(str);
261 for (size_t i = 0; i < len; i++) {
262 if (isdigit(str[i]) == 0) {
263 Base::PrintMessage("The port must be digit str:%s", str);
264 return false;
265 }
266 }
267 int port = atoi(p + 1);
268 sockaddr_in addrv4;
269 sockaddr_in6 addrv6;
270
271 if ((port <= 0 || port > MAX_IP_PORT)) {
272 Base::PrintMessage("-s content port incorrect.");
273 return false;
274 }
275
276 if (uv_ip4_addr(buf, port, &addrv4) == 0) {
277 serverListenString = IPV4_MAPPING_PREFIX;
278 serverListenString += optarg;
279 } else if (uv_ip6_addr(buf, port, &addrv6) == 0) {
280 serverListenString = optarg;
281 } else {
282 Base::PrintMessage("-s content IP incorrect.");
283 return false;
284 }
285 }
286 return true;
287 }
288
GetCommandlineOptions(int optArgc,const char * optArgv[])289 bool GetCommandlineOptions(int optArgc, const char *optArgv[])
290 {
291 int ch = 0;
292 bool needExit = false;
293 opterr = 0;
294 // get option parameters first
295 while ((ch = getopt(optArgc, const_cast<char *const*>(optArgv), "hvpfmncs:Sd:t:l:")) != -1) {
296 switch (ch) {
297 case 'h': {
298 string usage = Hdc::TranslateCommand::Usage();
299 if (optind < optArgc && optind >= 0 && string(optArgv[optind]) == "verbose") {
300 usage = Hdc::TranslateCommand::Verbose();
301 }
302 fprintf(stderr, "%s", usage.c_str());
303 needExit = true;
304 return needExit;
305 }
306 case 'v': {
307 string ver = Base::GetVersion();
308 fprintf(stdout, "%s\n", ver.c_str());
309 needExit = true;
310 return needExit;
311 }
312 case 'f': { // [not-publish]
313 break;
314 }
315 case 'l': {
316 int logLevel = atoi(optarg);
317 if (logLevel < 0 || logLevel > LOG_LAST) {
318 Base::PrintMessage("Loglevel error!");
319 needExit = true;
320 return needExit;
321 }
322 g_isCustomLoglevel = true;
323 Base::SetLogLevel(logLevel);
324 break;
325 }
326 case 'm': { // [not-publish] is server mode,or client mode
327 g_isServerMode = true;
328 break;
329 }
330 case 'n': {
331 g_containerInOut = "-n";
332 break;
333 }
334 case 'c': {
335 g_containerInOut = "-c";
336 break;
337 }
338 case 'p': { // [not-publish] not pullup server
339 g_isPullServer = false;
340 break;
341 }
342 case 't': { // key
343 if (strlen(optarg) > MAX_CONNECTKEY_SIZE) {
344 Base::PrintMessage("Sizeo of of parament '-t' %d is too long", strlen(optarg));
345 needExit = true;
346 return needExit;
347 }
348 g_connectKey = optarg;
349 break;
350 }
351 case 's': {
352 if (!Hdc::ParseServerListenString(g_serverListenString, optarg)) {
353 needExit = true;
354 return needExit;
355 }
356 break;
357 }
358 case 'S': {
359 g_externalCmd = true;
360 break;
361 }
362 case 'd': // [Undisclosed parameters] debug mode
363 g_isPcDebugRun = true;
364 if (optarg[0] == 't') {
365 g_isTCPorUSB = true;
366 } else if (optarg[0] == 'u') {
367 g_isTCPorUSB = false;
368 } else {
369 Base::PrintMessage("Unknown debug parameters");
370 needExit = true;
371 return needExit;
372 }
373 g_isTestMethod = atoi(optarg + 1);
374 break;
375 case '?':
376 break;
377 default: {
378 Base::PrintMessage("Unknown parameters");
379 needExit = true;
380 return needExit;
381 }
382 }
383 }
384 return needExit;
385 }
386
InitServerAddr(void)387 void InitServerAddr(void)
388 {
389 int port;
390 do {
391 char *env = getenv(ENV_SERVER_PORT.c_str());
392 if (!env) {
393 port = DEFAULT_PORT;
394 break;
395 }
396
397 size_t len = strlen(env);
398 size_t maxLen = 5;
399 if (len > maxLen) {
400 fprintf(stderr, "OHOS_HDC_SERVER_PORT %s is too long for the (0, 65535] range\n", env);
401 return;
402 }
403
404 for (size_t i = 0; i < len; i++) {
405 if (isdigit(env[i]) == 0) {
406 fprintf(stderr, "OHOS_HDC_SERVER_PORT %s is not digit\n", env);
407 return;
408 }
409 }
410
411 port = atoi(env);
412 if (port > 65535 || port <= 0) {
413 fprintf(stderr, "OHOS_HDC_SERVER_PORT %s is not in (0, 65535] range\n", env);
414 return;
415 }
416 } while (0);
417
418 g_serverListenString = DEFAULT_SERVER_ADDR_IP;
419 g_serverListenString += ":";
420 g_serverListenString += std::to_string(port);
421 }
422
RunExternalClient(string & str,string & connectKey,string & containerInOut)423 void RunExternalClient(string &str, string &connectKey, string &containerInOut)
424 {
425 ExtClient extClient;
426 extClient.connectKey = connectKey;
427 extClient.containerInOut = containerInOut;
428 extClient.Init();
429 extClient.ExecuteCommand(str);
430 }
431 }
432
433 #ifndef UNIT_TEST
434 // hdc -l4 -m -s ip:port|hdc -l4 -m
435 // hdc -l4 - s ip:port list targets
main(int argc,const char * argv[])436 int main(int argc, const char *argv[])
437 {
438 string options;
439 string commands;
440 Hdc::SplitOptionAndCommand(argc, argv, options, commands);
441 uv_setup_args(argc, const_cast<char **>(argv));
442 int optArgc = 0;
443 char **optArgv = Base::SplitCommandToArgs(options.c_str(), &optArgc);
444 bool cmdOptionResult;
445
446 InitServerAddr();
447 cmdOptionResult = GetCommandlineOptions(optArgc, const_cast<const char **>(optArgv));
448 delete[](reinterpret_cast<char*>(optArgv));
449 if (cmdOptionResult) {
450 return 0;
451 }
452 if (g_isServerMode) {
453 // -m server.Run alone in the background, no -s will be listen loopback address
454 Hdc::RunServerMode(g_serverListenString);
455 } else if (g_isPcDebugRun) {
456 Hdc::RunPcDebugMode(g_isPullServer, g_isTCPorUSB, g_isTestMethod);
457 } else {
458 if (!g_isCustomLoglevel) {
459 Base::SetLogLevel(LOG_INFO);
460 }
461 if (!ExtClient::SharedLibraryExist()) {
462 Hdc::RunClientMode(commands, g_serverListenString, g_connectKey, g_isPullServer);
463 Hdc::Base::RemoveLogCache();
464 return 0;
465 }
466 string str = "list targets";
467 if (!strncmp(commands.c_str(), CMDSTR_LIST_TARGETS.c_str(), CMDSTR_LIST_TARGETS.size())) {
468 string lista = "list targets -a";
469 if (!strncmp(commands.c_str(), lista.c_str(), lista.size())) {
470 str = "list targets -v";
471 } else {
472 str = commands;
473 }
474 Hdc::RunExternalClient(str, g_connectKey, g_containerInOut);
475 Hdc::RunClientMode(str, g_serverListenString, g_connectKey, g_isPullServer);
476 } else if (!strncmp(commands.c_str(), CMDSTR_SOFTWARE_VERSION.c_str(), CMDSTR_SOFTWARE_VERSION.size()) ||
477 !strncmp(commands.c_str(), CMDSTR_SOFTWARE_HELP.c_str(), CMDSTR_SOFTWARE_HELP.size()) ||
478 !strncmp(commands.c_str(), CMDSTR_TARGET_DISCOVER.c_str(), CMDSTR_TARGET_DISCOVER.size()) ||
479 !strncmp(commands.c_str(), CMDSTR_SERVICE_START.c_str(), CMDSTR_SERVICE_START.size()) ||
480 !strncmp(commands.c_str(), CMDSTR_SERVICE_KILL.c_str(), CMDSTR_SERVICE_KILL.size()) ||
481 !strncmp(commands.c_str(), CMDSTR_WAIT_FOR.c_str(), CMDSTR_WAIT_FOR.size())) {
482 Hdc::RunExternalClient(commands, g_connectKey, g_containerInOut);
483 Hdc::RunClientMode(commands, g_serverListenString, g_connectKey, g_isPullServer);
484 } else if (!strncmp(commands.c_str(), CMDSTR_CONNECT_TARGET.c_str(), CMDSTR_CONNECT_TARGET.size()) ||
485 !strncmp(commands.c_str(), CMDSTR_TARGET_MODE.c_str(), CMDSTR_TARGET_MODE.size()) || g_externalCmd) {
486 Hdc::RunExternalClient(commands, g_connectKey, g_containerInOut);
487 } else {
488 g_show = false;
489 Hdc::RunExternalClient(str, g_connectKey, g_containerInOut);
490 Hdc::RunClientMode(str, g_serverListenString, g_connectKey, g_isPullServer);
491 g_show = true;
492 if (g_connectKey.empty()) {
493 if (g_lists.size() == 0) {
494 Base::PrintMessage("No any target");
495 } else if (g_lists.size() == 1) {
496 auto iter = g_lists.begin();
497 g_connectKey = iter->first;
498 } else {
499 Base::PrintMessage("Specify one target");
500 }
501 }
502 if (g_lists[g_connectKey] == "external") {
503 Hdc::RunExternalClient(commands, g_connectKey, g_containerInOut);
504 } else if (g_lists[g_connectKey] == "hdc") {
505 Hdc::RunClientMode(commands, g_serverListenString, g_connectKey, g_isPullServer);
506 }
507 }
508 }
509 WRITE_LOG(LOG_DEBUG, "!!!!!!!!!Main finish main");
510 Hdc::Base::RemoveLogCache();
511 return 0;
512 }
513 #endif // no UNIT_TEST
514