• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 crate::auth;
16 use crate::config::*;
17 use crate::host_app::HostAppTask;
18 
19 use hdc::common::hdcfile::HdcFile;
20 use hdc::config::{self, HdcCommand};
21 use hdc::transfer;
22 use hdc::utils;
23 
24 use std::collections::HashMap;
25 use std::io::{self, Error, ErrorKind};
26 use std::sync::Arc;
27 
28 use ylong_runtime::net::SplitReadHalf;
29 use ylong_runtime::net::TcpStream;
30 use ylong_runtime::sync::{Mutex, RwLock};
31 
32 #[derive(Debug, Clone)]
33 pub struct TaskInfo {
34     pub command: HdcCommand,
35     pub connect_key: String,
36     pub channel_id: u32,
37     pub params: Vec<String>,
38 }
39 
channel_task_dispatch(task_info: TaskInfo) -> io::Result<()>40 pub async fn channel_task_dispatch(task_info: TaskInfo) -> io::Result<()> {
41     hdc::debug!(
42         "in channel_task_dispatch, task_info={:#?}",
43         task_info.clone()
44     );
45 
46     match task_info.command {
47         HdcCommand::UnityRunmode | HdcCommand::UnityRootrun => {
48             hdc::trace!("dispatch to runmode task");
49             channel_unity_task(task_info).await?
50         }
51         HdcCommand::UnityExecute | HdcCommand::ShellInit | HdcCommand::ShellData => {
52             hdc::trace!("dispatch to shell task");
53             channel_shell_task(task_info).await?
54         }
55         HdcCommand::KernelTargetConnect => {
56             hdc::trace!("dispatch to tconn task");
57             channel_connect_task(task_info).await?;
58         }
59         HdcCommand::KernelTargetList => {
60             hdc::trace!("dispatch to list task");
61             channel_list_targets_task(task_info).await?;
62         }
63         HdcCommand::KernelChannelClose => {
64             hdc::trace!("dispatch to close task");
65             transfer::TcpMap::end(task_info.channel_id).await;
66         }
67         HdcCommand::FileInit
68         | HdcCommand::FileBegin
69         | HdcCommand::FileData
70         | HdcCommand::FileCheck
71         | HdcCommand::FileFinish
72         | HdcCommand::AppInit
73         | HdcCommand::AppBegin
74         | HdcCommand::AppData
75         | HdcCommand::AppFinish
76         | HdcCommand::AppUninstall => {
77             channel_file_task(task_info).await?;
78         }
79         HdcCommand::UnityHilog => {
80             channel_hilog_task(task_info).await?;
81         }
82         HdcCommand::UnityBugreportInit => {
83             channel_bug_report_task(task_info).await?;
84         }
85         _ => {
86             hdc::info!("get unknown command {:#?}", task_info.command);
87             return Err(Error::new(ErrorKind::Other, "command not found"));
88         }
89     }
90     Ok(())
91 }
92 
channel_hilog_task(task_info: TaskInfo) -> io::Result<()>93 async fn channel_hilog_task(task_info: TaskInfo) -> io::Result<()> {
94     let session_id =
95         get_valid_session_id(task_info.connect_key.clone(), task_info.channel_id).await?;
96     let payload = if task_info.params.len() > 1 && task_info.params[1] == "-h" {
97         vec![104]
98     } else {
99         vec![0]
100     };
101     transfer::put(
102         session_id,
103         TaskMessage {
104             channel_id: task_info.channel_id,
105             command: HdcCommand::UnityHilog,
106             payload: payload,
107         },
108     )
109     .await;
110     Ok(())
111 }
112 
channel_bug_report_task(task_info: TaskInfo) -> io::Result<()>113 async fn channel_bug_report_task(task_info: TaskInfo) -> io::Result<()> {
114     let session_id =
115         get_valid_session_id(task_info.connect_key.clone(), task_info.channel_id).await?;
116     transfer::put(
117         session_id,
118         TaskMessage {
119             channel_id: task_info.channel_id,
120             command: HdcCommand::UnityBugreportInit,
121             payload: vec![],
122         },
123     )
124     .await;
125     Ok(())
126 }
127 
channel_file_task(task_info: TaskInfo) -> io::Result<()>128 async fn channel_file_task(task_info: TaskInfo) -> io::Result<()> {
129     let session_id =
130         get_valid_session_id(task_info.connect_key.clone(), task_info.channel_id).await?;
131     let opt = admin_session(ActionType::Query(session_id)).await;
132     if opt.is_none() {
133         admin_session(ActionType::Add(HdcSession::new(
134             session_id,
135             String::from(""),
136             NodeType::Daemon,
137             ConnectType::Tcp,
138         )))
139         .await;
140     }
141     let opt = admin_session(ActionType::Query(session_id)).await;
142 
143     let arc = opt.unwrap();
144     let mut session = arc.lock().await;
145     if let std::collections::hash_map::Entry::Vacant(e) =
146         session.map_tasks.entry(task_info.channel_id)
147     {
148         match task_info.command {
149             HdcCommand::AppInit | HdcCommand::AppUninstall => {
150                 let mut task = HostAppTask::new(session_id, task_info.channel_id);
151                 task.transfer.server_or_daemon = true;
152                 e.insert(Arc::new(Mutex::new(task)));
153             }
154             HdcCommand::FileInit => {
155                 let mut task = HdcFile::new(session_id, task_info.channel_id);
156                 task.transfer.server_or_daemon = true;
157                 e.insert(Arc::new(Mutex::new(task)));
158             }
159             _ => {
160                 println!("other tasks");
161             }
162         }
163     }
164     let task = session.map_tasks.get(&task_info.channel_id).unwrap();
165     let task_ = &mut task.lock().await;
166     let cmd_idx = match task_info.command {
167         HdcCommand::AppInit
168         | HdcCommand::AppBegin
169         | HdcCommand::AppData
170         | HdcCommand::AppFinish
171         | HdcCommand::AppUninstall => 1,
172         _ => 2,
173     };
174     let cmd = task_info.params[cmd_idx..]
175         .iter()
176         .map(|s| s.trim_end_matches('\0'))
177         .collect::<Vec<_>>()
178         .join(" ")
179         .into_bytes();
180     let _ = task_.command_dispatch(task_info.command, &cmd[..], cmd.len() as u16);
181 
182     Ok(())
183 }
184 
channel_unity_task(task_info: TaskInfo) -> io::Result<()>185 async fn channel_unity_task(task_info: TaskInfo) -> io::Result<()> {
186     let session_id = match ConnectMap::get_session_id(task_info.connect_key.clone()).await {
187         Some(seid) => seid,
188         None => return Err(Error::new(ErrorKind::Other, "session not found")),
189     };
190     let cmd = task_info.params[1..]
191         .iter()
192         .map(|s| s.trim_end_matches('\0'))
193         .collect::<Vec<_>>()
194         .join(" ")
195         .into_bytes();
196     transfer::put(
197         session_id,
198         TaskMessage {
199             channel_id: task_info.channel_id,
200             command: task_info.command,
201             payload: cmd,
202         },
203     )
204     .await;
205     Ok(())
206 }
207 
channel_shell_task(task_info: TaskInfo) -> io::Result<()>208 async fn channel_shell_task(task_info: TaskInfo) -> io::Result<()> {
209     let session_id =
210         get_valid_session_id(task_info.connect_key.clone(), task_info.channel_id).await?;
211     match task_info.command {
212         HdcCommand::UnityExecute => {
213             let cmd = task_info.params[1..]
214                 .iter()
215                 .map(|s| s.trim_end_matches('\0'))
216                 .collect::<Vec<_>>()
217                 .join(" ")
218                 .into_bytes();
219             transfer::put(
220                 session_id,
221                 TaskMessage {
222                     channel_id: task_info.channel_id,
223                     command: task_info.command,
224                     payload: cmd,
225                 },
226             )
227             .await;
228         }
229         HdcCommand::ShellInit => {
230             transfer::put(
231                 session_id,
232                 TaskMessage {
233                     channel_id: task_info.channel_id,
234                     command: task_info.command,
235                     payload: vec![0],
236                 },
237             )
238             .await;
239         }
240         HdcCommand::ShellData => {
241             let payload = task_info.params.join("").into_bytes();
242             transfer::put(
243                 session_id,
244                 TaskMessage {
245                     channel_id: task_info.channel_id,
246                     command: task_info.command,
247                     payload,
248                 },
249             )
250             .await;
251         }
252         _ => {}
253     }
254 
255     Ok(())
256 }
257 
channel_connect_task(task_info: TaskInfo) -> io::Result<()>258 async fn channel_connect_task(task_info: TaskInfo) -> io::Result<()> {
259     if task_info.params.len() < 2 || task_info.params[1].len() <= 1 {}
260     let connect_key = task_info.params[1].trim_end_matches('\0').to_string();
261     if ConnectMap::get(connect_key.clone()).await.is_some() {
262         let ret = transfer::send_channel_msg(
263             task_info.channel_id,
264             transfer::EchoLevel::INFO,
265             "Target is connected, repeat operation".to_string(),
266         )
267         .await;
268         transfer::TcpMap::end(task_info.channel_id).await;
269         return ret;
270     }
271     match TcpStream::connect(connect_key.clone()).await {
272         Err(_) => {
273             let ret = transfer::send_channel_msg(
274                 task_info.channel_id,
275                 transfer::EchoLevel::FAIL,
276                 "Connect to daemon failed".to_string(),
277             )
278             .await;
279             transfer::TcpMap::end(task_info.channel_id).await;
280             return ret;
281         }
282         Ok(stream) => {
283             let session_id = utils::get_pseudo_random_u32();
284             let (mut rd, wr) = stream.into_split();
285             transfer::TcpMap::start(session_id, wr).await;
286 
287             match auth::handshake_with_daemon(
288                 connect_key.clone(),
289                 session_id,
290                 task_info.channel_id,
291                 &mut rd,
292             )
293             .await
294             {
295                 Ok((dev_name, version)) => {
296                     ConnectMap::put(
297                         connect_key.clone(),
298                         DaemonInfo {
299                             session_id,
300                             conn_type: config::ConnectType::Tcp,
301                             conn_status: ConnectStatus::Connected,
302                             dev_name,
303                             version,
304                         },
305                     )
306                     .await;
307                 }
308                 Err(e) => {
309                     let _ = transfer::send_channel_msg(
310                         task_info.channel_id,
311                         transfer::EchoLevel::FAIL,
312                         e.to_string(),
313                     )
314                     .await;
315                     transfer::TcpMap::end(task_info.channel_id).await;
316                     return Ok(());
317                 }
318             };
319 
320             ylong_runtime::spawn(tcp_handle_deamon(rd, session_id, connect_key));
321             return transfer::send_channel_msg(
322                 task_info.channel_id,
323                 transfer::EchoLevel::INFO,
324                 "Connect OK".to_string(),
325             )
326             .await;
327         }
328     }
329 }
330 
channel_list_targets_task(task_info: TaskInfo) -> io::Result<()>331 async fn channel_list_targets_task(task_info: TaskInfo) -> io::Result<()> {
332     let is_full = task_info.params.contains(&"-v".to_string());
333     let target_list = ConnectMap::get_list(is_full).await;
334     let msg = if target_list.is_empty() {
335         "[Empty]".to_string()
336     } else {
337         target_list.join("\n")
338     };
339     let _ = transfer::send_channel_msg(task_info.channel_id, transfer::EchoLevel::RAW, msg).await?;
340     transfer::TcpMap::end(task_info.channel_id).await;
341     Ok(())
342 }
343 
tcp_handle_deamon( mut rd: SplitReadHalf, session_id: u32, connect_key: String, ) -> io::Result<()>344 async fn tcp_handle_deamon(
345     mut rd: SplitReadHalf,
346     session_id: u32,
347     connect_key: String,
348 ) -> io::Result<()> {
349     loop {
350         match transfer::tcp::unpack_task_message(&mut rd).await {
351             Ok(task_message) => {
352                 hdc::info!(
353                     "in tcp_handle_deamon, recv cmd: {:#?}, payload len: {}",
354                     task_message.command,
355                     task_message.payload.len(),
356                 );
357                 if let Err(e) = session_task_dispatch(task_message, session_id).await {
358                     hdc::error!("dispatch task failed: {}", e.to_string());
359                 }
360             }
361             Err(e) => {
362                 hdc::warn!("unpack task failed: {}", e.to_string());
363                 ConnectMap::remove(connect_key).await;
364                 return Err(e);
365             }
366         };
367     }
368 }
369 
session_task_dispatch(task_message: TaskMessage, session_id: u32) -> io::Result<()>370 async fn session_task_dispatch(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
371     match task_message.command {
372         HdcCommand::KernelEchoRaw | HdcCommand::UnityBugreportData => {
373             transfer::send_channel_data(task_message.channel_id, task_message.payload).await;
374         }
375         HdcCommand::KernelChannelClose => {
376             session_channel_close(task_message, session_id).await?;
377         }
378         HdcCommand::AppBegin
379         | HdcCommand::AppData
380         | HdcCommand::AppFinish
381         | HdcCommand::FileInit
382         | HdcCommand::FileBegin
383         | HdcCommand::FileData
384         | HdcCommand::FileCheck
385         | HdcCommand::FileFinish => {
386             session_file_task(task_message, session_id).await?;
387         }
388         _ => {}
389     }
390     Ok(())
391 }
392 
session_file_task(task_message: TaskMessage, session_id: u32) -> io::Result<()>393 async fn session_file_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
394     let channel_id = task_message.channel_id;
395     let command = task_message.command;
396     let opt = admin_session(ActionType::Query(session_id)).await;
397     if opt.is_none() {
398         admin_session(ActionType::Add(HdcSession::new(
399             session_id,
400             String::from(""),
401             NodeType::Server,
402             ConnectType::Tcp,
403         )))
404         .await;
405     }
406     let opt = admin_session(ActionType::Query(session_id)).await;
407 
408     let arc = opt.unwrap();
409     let mut session = arc.lock().await;
410     if let std::collections::hash_map::Entry::Vacant(e) = session.map_tasks.entry(channel_id) {
411         match command {
412             HdcCommand::AppBegin => {
413                 let mut task = HostAppTask::new(session_id, channel_id);
414                 task.transfer.server_or_daemon = true;
415                 e.insert(Arc::new(Mutex::new(task)));
416             }
417             HdcCommand::FileInit => {
418                 let mut task = HdcFile::new(session_id, channel_id);
419                 task.transfer.server_or_daemon = true;
420                 e.insert(Arc::new(Mutex::new(task)));
421             }
422             _ => {
423                 println!("other tasks");
424             }
425         }
426     }
427     let task = session.map_tasks.get(&channel_id).unwrap();
428     let task_ = &mut task.lock().await;
429     let cmd = task_message.payload;
430     let _ = task_.command_dispatch(command, &cmd[..], cmd.len() as u16);
431 
432     Ok(())
433 }
434 
session_channel_close(task_message: TaskMessage, session_id: u32) -> io::Result<()>435 async fn session_channel_close(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
436     if task_message.payload[0] > 0 {
437         let message = TaskMessage {
438             channel_id: task_message.channel_id,
439             command: HdcCommand::KernelChannelClose,
440             payload: vec![task_message.payload[0] - 1],
441         };
442         transfer::put(session_id, message).await;
443     }
444     hdc::info!("recv channel close");
445     transfer::TcpMap::end(task_message.channel_id).await;
446     Ok(())
447 }
448 
449 #[allow(unused)]
450 #[derive(Default)]
451 enum ConnectStatus {
452     #[default]
453     Unknown = 0,
454     Ready,
455     Connected,
456     Offline,
457 }
458 
459 #[allow(unused)]
460 #[derive(Default)]
461 struct DaemonInfo {
462     pub session_id: u32,
463     pub conn_type: config::ConnectType,
464     pub conn_status: ConnectStatus,
465     pub dev_name: String,
466     pub version: String,
467 }
468 
469 type DaemonInfo_ = Arc<Mutex<DaemonInfo>>;
470 type ConnectMap_ = Arc<RwLock<HashMap<String, DaemonInfo_>>>;
471 
472 pub struct ConnectMap {}
473 impl ConnectMap {
get_instance() -> ConnectMap_474     fn get_instance() -> ConnectMap_ {
475         static mut CONNECT_TYPE_MAP: Option<ConnectMap_> = None;
476         unsafe {
477             CONNECT_TYPE_MAP
478                 .get_or_insert_with(|| Arc::new(RwLock::new(HashMap::new())))
479                 .clone()
480         }
481     }
482 
remove(connect_key: String)483     async fn remove(connect_key: String) {
484         let instance = Self::get_instance();
485         let mut map = instance.write().await;
486         map.remove(&connect_key);
487     }
488 
put(connect_key: String, daemon_info: DaemonInfo)489     async fn put(connect_key: String, daemon_info: DaemonInfo) {
490         let instance = Self::get_instance();
491         let mut map = instance.write().await;
492         map.insert(connect_key, Arc::new(Mutex::new(daemon_info)));
493     }
494 
get(connect_key: String) -> Option<DaemonInfo_>495     async fn get(connect_key: String) -> Option<DaemonInfo_> {
496         let instance = Self::get_instance();
497         let map = instance.read().await;
498         let key = if connect_key.as_str() == "any" && map.keys().len() == 1 {
499             map.keys().last().unwrap()
500         } else {
501             &connect_key
502         };
503         match map.get(key) {
504             Some(daemon_info) => Some(daemon_info.clone()),
505             None => None,
506         }
507     }
508 
get_list(is_full: bool) -> Vec<String>509     async fn get_list(is_full: bool) -> Vec<String> {
510         let instance = Self::get_instance();
511         let map = instance.read().await;
512         let mut list = vec![];
513         for (key, info) in map.iter() {
514             if is_full {
515                 let mut output = vec![key.as_str()];
516                 let guard = info.lock().await;
517                 output.push(match guard.conn_type {
518                     ConnectType::Tcp => "TCP",
519                     ConnectType::Usb(_) => "USB",
520                     ConnectType::Uart => "UART",
521                     ConnectType::Bt => "BT",
522                 });
523                 output.push(match guard.conn_status {
524                     ConnectStatus::Connected => "Connected",
525                     ConnectStatus::Ready => "Ready",
526                     ConnectStatus::Offline => "Offline",
527                     ConnectStatus::Unknown => "Unknown",
528                 });
529                 if guard.dev_name.is_empty() {
530                     output.push("unknown...");
531                 } else {
532                     let dev_name = guard.dev_name.as_str();
533                     output.push(dev_name);
534                 };
535                 output.push("hdc");
536                 list.push(output.join("\t"));
537             } else {
538                 list.push(key.to_owned());
539             }
540         }
541         list
542     }
543 
get_session_id(connect_key: String) -> Option<u32>544     pub async fn get_session_id(connect_key: String) -> Option<u32> {
545         let daemon_info = Self::get(connect_key).await?;
546         let guard = daemon_info.lock().await;
547         Some(guard.session_id)
548     }
549 }
550 
get_valid_session_id(connect_key: String, channel_id: u32) -> io::Result<u32>551 async fn get_valid_session_id(connect_key: String, channel_id: u32) -> io::Result<u32> {
552     match ConnectMap::get_session_id(connect_key).await {
553         Some(session_id) => Ok(session_id),
554         None => {
555             transfer::send_channel_msg(
556                 channel_id,
557                 transfer::EchoLevel::FAIL,
558                 "Not match target founded, check connect-key please".to_string(),
559             )
560             .await?;
561             transfer::TcpMap::end(channel_id).await;
562             return Err(Error::new(ErrorKind::Other, "session not found"));
563         }
564     }
565 }
566