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