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 */ 15use super::parser::ParsedCommand; 16use super::server; 17 18use hdc::common::base; 19use hdc::common::base::Base; 20use hdc::config::{self, HdcCommand}; 21use hdc::transfer; 22use hdc::utils; 23#[allow(unused)] 24use hdc::utils::hdc_log::*; 25use libc::exit; 26use std::time::Duration; 27 28use std::env; 29use std::io::{self, Error, ErrorKind, Write}; 30#[cfg(not(target_os = "windows"))] 31use std::os::fd::AsRawFd; 32 33#[cfg(featrue = "host")] 34extern crate ylong_runtime_static as ylong_runtime; 35#[cfg(not(target_os = "windows"))] 36use ylong_runtime::io::AsyncReadExt; 37use ylong_runtime::io::AsyncWriteExt; 38use ylong_runtime::net::{SplitWriteHalf, TcpStream}; 39 40#[cfg(target_os = "windows")] 41use crate::tty_utility::*; 42 43#[cfg(target_os = "windows")] 44extern "C" { 45 fn getch() -> libc::c_int; 46} 47 48 49#[allow(unused)] 50pub struct Client { 51 command: HdcCommand, 52 params: Vec<String>, 53 connect_key: String, 54 wr: SplitWriteHalf, 55} 56 57pub 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 91impl 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 523fn 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"))] 544fn 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"))] 573fn 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