1 /*
2 * Copyright (C) 2023 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 use super::parser::ParsedCommand;
16 use super::server;
17
18 use hdc::common::base;
19 use hdc::common::base::Base;
20 use hdc::config::{self, HdcCommand};
21 use hdc::transfer;
22 use hdc::utils;
23 #[allow(unused)]
24 use hdc::utils::hdc_log::*;
25 use libc::exit;
26 use std::time::Duration;
27
28 use std::env;
29 use std::io::{self, Error, ErrorKind, Write};
30 #[cfg(not(target_os = "windows"))]
31 use std::os::fd::AsRawFd;
32
33 #[cfg(featrue = "host")]
34 extern crate ylong_runtime_static as ylong_runtime;
35 #[cfg(not(target_os = "windows"))]
36 use ylong_runtime::io::AsyncReadExt;
37 use ylong_runtime::io::AsyncWriteExt;
38 use ylong_runtime::net::{SplitWriteHalf, TcpStream};
39
40 #[cfg(target_os = "windows")]
41 use crate::tty_utility::*;
42
43 #[cfg(target_os = "windows")]
44 extern "C" {
getchnull45 fn getch() -> libc::c_int;
46 }
47
48
49 #[allow(unused)]
50 pub struct Client {
51 command: HdcCommand,
52 params: Vec<String>,
53 connect_key: String,
54 wr: SplitWriteHalf,
55 }
56
57 pub async fn run_client_mode(parsed_cmd: ParsedCommand) -> io::Result<()> {
58 match parsed_cmd.command {
59 Some(HdcCommand::KernelServerStart) => {
60 if parsed_cmd.parameters.contains(&"-r".to_string()) {
61 server::server_kill().await;
62 }
63 server::server_fork(parsed_cmd.server_addr.clone(), parsed_cmd.log_level).await;
64 return Ok(());
65 }
66 Some(HdcCommand::KernelServerKill) => {
67 server::server_kill().await;
68 if parsed_cmd.parameters.contains(&"-r".to_string()) {
69 server::server_fork(parsed_cmd.server_addr.clone(), parsed_cmd.log_level).await;
70 }
71 return Ok(());
72 }
73 _ => {}
74 };
75
76 if parsed_cmd.launch_server && Base::program_mutex(base::GLOBAL_SERVER_NAME, true) {
77 server::server_fork(parsed_cmd.server_addr.clone(), parsed_cmd.log_level).await;
78 }
79
80 // TODO: other cmd before initial client
81
82 let mut client = Client::new(parsed_cmd).await?;
83
84 if let Err(e) = client.handshake().await {
85 hdc::error!("handshake with server failed: {e:?}");
86 return Err(e);
87 }
88 client.execute_command().await
89 }
90
91 impl Client {
92 pub async fn new(parsed_cmd: ParsedCommand) -> io::Result<Self> {
93 let Some(command) = parsed_cmd.command else {
94 return Err(Error::new(ErrorKind::Other, "command is None"));
95 };
96 let connect_key = auto_connect_key(parsed_cmd.connect_key, command);
97
98 let stream = match TcpStream::connect(parsed_cmd.server_addr).await {
99 Ok(stream) => stream,
100 Err(_) => return Err(Error::new(ErrorKind::Other, "Connect to server failed")),
101 };
102
103 let (rd, wr) = stream.into_split();
104
105 transfer::ChannelMap::start(rd).await;
106
107 Ok(Self {
108 command,
109 params: parsed_cmd.parameters,
110 connect_key,
111 wr,
112 })
113 }
114
115 async fn execute_command(&mut self) -> io::Result<()> {
116 let entire_cmd = self.params.join(" ");
117 hdc::debug!("execute command params: {}", &entire_cmd);
118
119 match self.command {
120 HdcCommand::KernelTargetList
121 | HdcCommand::KernelTargetConnect
122 | HdcCommand::UnityHilog => self.general_task().await,
123 HdcCommand::FileInit | HdcCommand::FileCheck | HdcCommand::FileRecvInit => {
124 self.file_send_task().await
125 }
126 HdcCommand::AppInit => self.app_install_task().await,
127 HdcCommand::AppUninstall => self.app_uninstall_task().await,
128 HdcCommand::UnityRunmode
129 | HdcCommand::UnityReboot
130 | HdcCommand::UnityRemount => self.unity_task().await,
131 HdcCommand::UnityRootrun => self.unity_root_run_task().await,
132 HdcCommand::UnityExecute => self.shell_task().await,
133 HdcCommand::KernelWaitFor => self.wait_task().await,
134 HdcCommand::UnityBugreportInit => self.bug_report_task().await,
135 HdcCommand::ForwardInit
136 | HdcCommand::ForwardRportInit
137 | HdcCommand::ForwardList
138 | HdcCommand::ForwardRportList
139 | HdcCommand::ForwardRemove
140 | HdcCommand::ForwardRportRemove => {
141 self.forward_task().await
142 }
143 HdcCommand::JdwpList | HdcCommand::JdwpTrack => self.jdwp_task().await,
144 HdcCommand::KernelCheckServer => self.check_server_task().await,
145 _ => Err(Error::new(
146 ErrorKind::Other,
147 format!("unknown command: {}", self.command as u32),
148 )),
149 }
150 }
151
152 pub async fn handshake(&mut self) -> io::Result<()> {
153 let recv = self.recv().await?;
154 let msg = match std::str::from_utf8(&recv[..config::HANDSHAKE_MESSAGE.len()]) {
155 Ok(msg) => msg,
156 Err(err) => {
157 return Err(Error::new(ErrorKind::Other, format!("handshake from_utf8 error : {err}")));
158 }
159 };
160 if msg != config::HANDSHAKE_MESSAGE {
161 return Err(Error::new(ErrorKind::Other, "Recv server-hello failed"));
162 }
163 let buf = [
164 config::HANDSHAKE_MESSAGE.as_bytes(),
165 vec![0_u8; config::BANNER_SIZE - config::HANDSHAKE_MESSAGE.len()].as_slice(),
166 self.connect_key.as_bytes(),
167 vec![0_u8; config::KEY_MAX_SIZE - self.connect_key.len()].as_slice(),
168 ]
169 .concat();
170
171 self.send(buf.as_slice()).await;
172
173 Ok(())
174 }
175
176 async fn send(&mut self, buf: &[u8]) {
177 hdc::debug!("channel send buf: {:#?}", buf);
178 let msg = [u32::to_be_bytes(buf.len() as u32).as_slice(), buf].concat();
179 let _ = self.wr.write_all(msg.as_slice()).await;
180 }
181
182 async fn recv(&mut self) -> io::Result<Vec<u8>> {
183 hdc::debug!("channel recv buf");
184 transfer::ChannelMap::recv().await
185 }
186
187 async fn unity_task(&mut self) -> io::Result<()> {
188 self.send(self.params.join(" ").as_bytes()).await;
189 self.loop_recv().await
190 }
191
192 async fn wait_task(&mut self) -> io::Result<()> {
193 self.send(self.params.join(" ").as_bytes()).await;
194 self.loop_recv_waitfor().await
195 }
196
197 async fn unity_root_run_task(&mut self) -> io::Result<()> {
198 if self.params.len() >= 2 && self.params[1].starts_with("-r") {
199 self.params[1] = "r".to_string();
200 }
201 self.send(self.params.join(" ").as_bytes()).await;
202 self.loop_recv().await
203 }
204 async fn jdwp_task(&mut self) -> io::Result<()> {
205 self.send(self.params.join(" ").as_bytes()).await;
206 self.loop_recv().await
207 }
208
209
210 #[cfg(target_os = "windows")]
211 async fn shell_task(&mut self) -> io::Result<()> {
212 let cmd = match self.params.len() {
213 1 => "shell\0".to_string(),
214 _ => self.params.join(" "),
215 };
216
217 self.send(cmd.as_bytes()).await;
218
219 let _handle = ylong_runtime::spawn(async move {
220 loop {
221 match transfer::ChannelMap::recv().await {
222 Ok(recv) => {
223 let _ = utils::print_msg(recv).await;
224 }
225 Err(_) => {
226 std::process::exit(0);
227 }
228 }
229 }
230 });
231
232 loop {
233 let c = unsafe { getch() };
234
235 // 判断如果是ctrl_D,发送给serer端,client直接退出
236 if c == 0x4 {
237 self.send([c as u8].as_slice()).await;
238 break;
239 }
240
241 // win下的控制字符以0xe0开头,转换后发送给server,
242 if c == 0xe0 {
243 let control_code = convert_to_control_code();
244 self.send(control_code.as_slice()).await;
245 continue;
246 }
247
248 let unicode_byte = unicode_assemble(c);
249 hdc::info!("unicode_byte is {:?}", unicode_byte);
250 self.send(unicode_byte.as_slice()).await;
251 }
252 Ok(())
253 }
254
255 #[cfg(not(target_os = "windows"))]
256 async fn shell_task(&mut self) -> io::Result<()> {
257 let cmd = match self.params.len() {
258 1 => "shell\0".to_string(),
259 _ => self.params.join(" "),
260 };
261
262 self.send(cmd.as_bytes()).await;
263
264 let termios = setup_raw_terminal()?;
265 let termios_clone = termios;
266
267 let _handle = ylong_runtime::spawn(async move {
268 loop {
269 match transfer::ChannelMap::recv().await {
270 Ok(recv) => {
271 let _ = utils::print_msg(recv).await;
272 }
273 Err(_) => {
274 let _ = recover_terminal(termios_clone);
275
276 std::process::exit(0);
277 }
278 }
279 }
280 });
281
282 let mut buf = [0_u8; 1];
283 let mut stdin = ylong_runtime::io::stdin();
284
285 while let Ok(bytes) = stdin.read(&mut buf).await {
286 self.send(&buf[..bytes]).await;
287 if buf[..bytes].contains(&0x4_u8) {
288 break;
289 }
290 }
291
292 let _ = recover_terminal(termios);
293 Ok(())
294 }
295
296 async fn forward_task(&mut self) -> io::Result<()> {
297 if (self.command == HdcCommand::ForwardRemove
298 || self.command == HdcCommand::ForwardRportRemove)
299 && self.params.len() < 3
300 {
301 return Err(Error::new(
302 ErrorKind::Other,
303 "Too few arguments.".to_string()
304 ));
305 }
306 if (self.command == HdcCommand::ForwardInit
307 || self.command == HdcCommand::ForwardRportInit)
308 && self.params.len() < 3
309 {
310 return Err(Error::new(
311 ErrorKind::Other,
312 "Too few arguments.".to_string()
313 ));
314 }
315 self.send(self.params.join(" ").as_bytes()).await;
316 self.loop_recv().await
317 }
318
319 async fn general_task(&mut self) -> io::Result<()> {
320 self.send(self.params.join(" ").as_bytes()).await;
321 loop {
322 let recv = self.recv().await?;
323 hdc::debug!(
324 "general_task recv: {:#?}",
325 recv.iter()
326 .map(|c| format!("{c:02x}"))
327 .collect::<Vec<_>>()
328 .join(" ")
329 );
330 let _ = utils::print_msg(recv).await;
331 }
332 }
333
334 async fn bug_report_task(&mut self) -> io::Result<()> {
335 if self.params.len() <= 1 {
336 return self.general_task().await;
337 }
338 self.send(self.params.join(" ").as_bytes()).await;
339 let mut file = std::fs::File::create(self.params[1].as_str())?;
340 loop {
341 let recv = self.recv().await?;
342 file.write_all(&recv)?;
343 }
344 }
345
346 async fn file_send_task(&mut self) -> io::Result<()> {
347 let mut params = self.params.clone();
348 if self.command == HdcCommand::FileInit || self.command == HdcCommand::FileRecvInit {
349 let command_field_count = 2;
350 let current_dir = env::current_dir()?;
351 let mut s = current_dir.display().to_string();
352 s.push(Base::get_path_sep());
353 params.insert(command_field_count, "-cwd".to_string());
354 params.insert(command_field_count + 1, s.clone());
355 }
356
357 self.send(params.join(" ").as_bytes()).await;
358 self.loop_recv().await
359 }
360
361 async fn loop_recv(&mut self) -> io::Result<()> {
362 loop {
363 let recv = self.recv().await;
364 match recv {
365 Ok(recv) => {
366 hdc::debug!(
367 "recv: {:#?}",
368 recv.iter()
369 .map(|c| format!("{c:02x}"))
370 .collect::<Vec<_>>()
371 .join(" ")
372 );
373 match String::from_utf8(recv) {
374 Ok(msg) => print!("{msg}"),
375 Err(err) => return Err(Error::new(ErrorKind::Other, format!("recv data to str failed, {err}"))),
376 }
377 }
378 Err(e) => {
379 return Err(e);
380 }
381 }
382 }
383 }
384
385 async fn loop_recv_waitfor(&mut self) -> io::Result<()> {
386 loop {
387 let recv = self.recv().await;
388 match recv {
389 Ok(recv) => {
390 hdc::debug!(
391 "recv: {:#?}",
392 recv.iter()
393 .map(|c| format!("{c:02x}"))
394 .collect::<Vec<_>>()
395 .join(" ")
396 );
397 if let HdcCommand::KernelWaitFor = self.command {
398 let wait_for = "No connected target\r\n".to_string();
399 if wait_for == String::from_utf8(recv).expect("invalid UTF-8") {
400 self.send(self.params.join(" ").as_bytes()).await;
401 hdc::debug!("WaitFor sleep a second");
402 let wait_interval = 1000;
403 ylong_runtime::time::sleep(Duration::from_millis(wait_interval)).await;
404 } else {
405 hdc::debug!("exit client");
406 unsafe {
407 exit(0);
408 }
409 }
410 }
411 }
412 Err(e) => {
413 return Err(e);
414 }
415 }
416 }
417 }
418
419 async fn app_install_task(&mut self) -> io::Result<()> {
420 let mut params = self.params.clone();
421 let command_field_count = 1;
422 let current_dir = env::current_dir()?;
423 let mut s = current_dir.display().to_string();
424 s.push(Base::get_path_sep());
425 params.insert(command_field_count, "-cwd".to_string());
426 params.insert(command_field_count + 1, s.clone());
427
428 self.send(params.join(" ").as_bytes()).await;
429
430 loop {
431 let recv = self.recv().await;
432 match recv {
433 Ok(recv) => {
434 hdc::debug!(
435 "app_install_task recv: {:#?}",
436 recv.iter()
437 .map(|c| format!("{c:02x}"))
438 .collect::<Vec<_>>()
439 .join(" ")
440 );
441 match String::from_utf8(recv) {
442 Ok(msg) => print!("{}", msg),
443 Err(e) => return Err(io::Error::new(io::ErrorKind::Other, format!("{e}"))),
444 }
445 }
446 Err(e) => {
447 return Err(e);
448 }
449 }
450 }
451 }
452
453 async fn app_uninstall_task(&mut self) -> io::Result<()> {
454 let params = self.params.clone();
455 self.send(params.join(" ").as_bytes()).await;
456
457 loop {
458 let recv = self.recv().await;
459 match recv {
460 Ok(recv) => {
461 hdc::debug!(
462 "app_uninstall_task recv: {:#?}",
463 recv.iter()
464 .map(|c| format!("{c:02x}"))
465 .collect::<Vec<_>>()
466 .join(" ")
467 );
468 match String::from_utf8(recv) {
469 Ok(msg) => println!("{msg}"),
470 Err(e) => {
471 return Err(io::Error::new(io::ErrorKind::Other, format!("{e}")));
472 }
473 }
474 }
475 Err(e) => {
476 return Err(e);
477 }
478 }
479 }
480 }
481
482 async fn check_server_task(&mut self) -> io::Result<()> {
483 let params = self.params.clone();
484 self.send(params.join(" ").as_bytes()).await;
485
486 let recv = self.recv().await;
487 match recv {
488 Ok(recv) => {
489 hdc::debug!(
490 "check_server_task recv: {:#?}",
491 recv.iter()
492 .map(|c| format!("{c:02x}"))
493 .collect::<Vec<_>>()
494 .join(" ")
495 );
496
497 const CMD_U8_LEN: usize = 2;
498 if recv.len() < CMD_U8_LEN {
499 return Err(Error::new(io::ErrorKind::Other, "recv failed"));
500 }
501
502 let (cmd_slice, version_slice) = recv.split_at(CMD_U8_LEN);
503 let Ok(cmd) = HdcCommand::try_from(u16::from_le_bytes(cmd_slice.try_into().unwrap_or_default()) as u32)
504 else {
505 return Err(Error::new(io::ErrorKind::Other, "HdcCommand::try_from failed"));
506 };
507 if HdcCommand::KernelCheckServer != cmd {
508 return Err(Error::new(io::ErrorKind::Other, "recv cmd error"));
509 }
510 match String::from_utf8(version_slice.to_vec()) {
511 Ok(s_ver) => println!("Client version:{}, server version:{}", config::get_version(), s_ver),
512 Err(err) => {
513 return Err(Error::new(io::ErrorKind::Other, format!("from_utf8 failed, {err}")));
514 }
515 }
516 Ok(())
517 }
518 Err(e) => Err(e),
519 }
520 }
521 }
522
auto_connect_keynull523 fn auto_connect_key(key: String, cmd: HdcCommand) -> String {
524 match cmd {
525 HdcCommand::ClientVersion
526 | HdcCommand::KernelHelp
527 | HdcCommand::KernelTargetDiscover
528 | HdcCommand::KernelTargetList
529 | HdcCommand::KernelCheckServer
530 | HdcCommand::KernelTargetConnect
531 | HdcCommand::KernelCheckDevice
532 | HdcCommand::KernelServerKill => "".to_string(),
533 _ => {
534 if key.is_empty() {
535 "any".to_string()
536 } else {
537 key
538 }
539 }
540 }
541 }
542
543 #[cfg(not(target_os = "windows"))]
setup_raw_terminalnull544 fn setup_raw_terminal() -> io::Result<libc::termios> {
545 unsafe {
546 let tty;
547 let fd = if libc::isatty(libc::STDIN_FILENO) == 1 {
548 libc::STDIN_FILENO
549 } else {
550 tty = std::fs::File::open("/dev/tty")?;
551 tty.as_raw_fd()
552 };
553
554 let mut ptr = core::mem::MaybeUninit::uninit();
555
556 if libc::tcgetattr(fd, ptr.as_mut_ptr()) == 0 {
557 let termios = ptr.assume_init();
558 let mut termios_copy = termios;
559 let c_oflag = termios.c_oflag;
560 libc::cfmakeraw(&mut termios_copy);
561 termios_copy.c_oflag = c_oflag;
562
563 if libc::tcsetattr(fd, libc::TCSADRAIN, &termios_copy) == 0 {
564 return Ok(termios);
565 }
566 }
567 }
568
569 Err(io::Error::last_os_error())
570 }
571
572 #[cfg(not(target_os = "windows"))]
recover_terminalnull573 fn recover_terminal(termios: libc::termios) -> io::Result<()> {
574 unsafe {
575 let tty;
576 let fd = if libc::isatty(libc::STDIN_FILENO) == 1 {
577 libc::STDIN_FILENO
578 } else {
579 tty = std::fs::File::open("/dev/tty")?;
580 tty.as_raw_fd()
581 };
582 if libc::tcsetattr(fd, libc::TCSADRAIN, &termios) == 0 {
583 Ok(())
584 } else {
585 Err(io::Error::last_os_error())
586 }
587 }
588 }
589