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