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 
16 /// provide C interface to C++ for calling
17 pub mod ffi;
18 use hilog_rust::{debug, error, hilog, HiLogLabel, LogType};
19 use libc::c_int;
20 use std::{ffi::{CString, c_char}, thread::sleep, time::Duration};
21 const LOG_LABEL: HiLogLabel = HiLogLabel {
22     log_type: LogType::LogCore,
23     domain: 0xD002700,
24     tag: "StreamSession"
25 };
26 const MAX_PACKET_BUF_SIZE: usize = 256;
27 const SEND_RETRY_LIMIT: i32 = 32;
28 const SEND_RETRY_SLEEP_TIME: u64 = 10000;
29 const RET_ERR: i32 = -1;
30 
31 #[repr(C)]
32 pub struct StreamSession {
33     module_type: i32,
34     fd: i32,
35     uid : i32,
36     pid: i32,
37     token_type: i32,
38 }
39 
40 impl Default for StreamSession {
default() -> Self41     fn default() -> Self {
42         Self {
43             module_type: RET_ERR,
44             fd: RET_ERR,
45             uid: RET_ERR,
46             pid: RET_ERR,
47             token_type: RET_ERR,
48         }
49     }
50 }
51 
52 impl StreamSession {
as_ref<'a>(object: *const Self) -> Option<&'a Self>53     fn as_ref<'a>(object: *const Self) -> Option<&'a Self> {
54         // SAFETY: as_ref has already done no-null verification inside
55         unsafe {
56             object.as_ref()
57         }
58     }
as_mut<'a>(object: *mut Self) -> Option<&'a mut Self>59     fn as_mut<'a>(object: *mut Self) -> Option<&'a mut Self> {
60         // SAFETY: as_mut has already done no-null verification inside
61         unsafe {
62             object.as_mut()
63         }
64     }
uid(&self) -> i3265     fn uid(&self) -> i32 {
66         self.uid
67     }
68 
pid(&self) -> i3269     fn pid(&self) -> i32 {
70         self.pid
71     }
72 
module_type(&self) -> i3273     fn module_type(&self) -> i32 {
74         self.module_type
75     }
76 
session_fd(&self) -> i3277     fn session_fd(&self) -> i32 {
78         self.fd
79     }
80 
set_token_type(&mut self, style: i32)81     fn set_token_type(&mut self, style: i32) {
82         self.token_type = style
83     }
84 
set_uid(&mut self, uid: i32)85     fn set_uid(&mut self, uid: i32) {
86         self.uid = uid
87     }
88 
set_pid(&mut self, pid: i32)89     fn set_pid(&mut self, pid: i32) {
90         self.pid = pid
91     }
92 
set_fd(&mut self, fd: i32)93     fn set_fd(&mut self, fd: i32) {
94         self.fd = fd
95     }
96 
token_type(&self) -> i3297     fn token_type(&self) -> i32 {
98         self.token_type
99     }
100 
session_close(&mut self)101     fn session_close(&mut self) {
102         debug!(LOG_LABEL, "Enter fd_:{}.", self.fd);
103         if self.fd >= 0 {
104             // SAFETY: call unsafe function
105             unsafe {
106                 libc::close(self.fd as c_int);
107             }
108             self.fd = RET_ERR;
109         }
110     }
111 
session_send_msg(&self, buf: *const c_char, size: usize) -> bool112     fn session_send_msg(&self, buf: *const c_char, size: usize) -> bool {
113         if buf.is_null() {
114             error!(LOG_LABEL, "buf is null");
115             return false;
116         }
117         if size == 0 || size > MAX_PACKET_BUF_SIZE {
118             error!(LOG_LABEL, "size is either equal to 0 or greater than MAX_PACKET_BUF_SIZE, size: {}", size);
119             return false;
120         }
121         if self.fd < 0 {
122             error!(LOG_LABEL, "The fd is less than 0, fd: {}", self.fd);
123             return false;
124         }
125         let mut idx: usize = 0;
126         let mut retry_count: i32 = 0;
127         let buf_size = size;
128         let mut rem_size = buf_size;
129         while rem_size > 0 && retry_count < SEND_RETRY_LIMIT {
130             retry_count += 1;
131             // SAFETY: call extern libc library function
132             let count = unsafe {
133                 libc::send(self.fd as c_int, buf.add(idx) as *const libc::c_void, rem_size,
134                 libc::MSG_DONTWAIT | libc::MSG_NOSIGNAL)
135             };
136             // SAFETY: call extern libc library function
137             let errno = unsafe {
138                 *libc::__errno_location()
139             };
140             if count < 0 {
141                 if errno == libc::EAGAIN || errno == libc::EINTR || errno == libc::EWOULDBLOCK {
142                     sleep(Duration::from_micros(SEND_RETRY_SLEEP_TIME));
143                     error!(LOG_LABEL, "Continue for errno EAGAIN|EINTR|EWOULDBLOCK, errno:{}", errno);
144                     continue;
145                 }
146                 error!(LOG_LABEL, "Send return failed,error:{} fd:{}", errno, self.fd);
147                 return false;
148             }
149             idx += count as usize;
150             rem_size -= count as usize;
151             if rem_size > 0 {
152                 sleep(Duration::from_micros(SEND_RETRY_SLEEP_TIME));
153             }
154         }
155         if retry_count >= SEND_RETRY_LIMIT || rem_size != 0 {
156             error!(LOG_LABEL, "Send too many times:{}/{},size:{}/{} fd:{}",
157                 retry_count, SEND_RETRY_LIMIT, idx, buf_size, self.fd);
158             return false;
159         }
160         true
161     }
162 }
163