1cac7dca0Sopenharmony_ci// Copyright (c) 2023 Huawei Device Co., Ltd. 2cac7dca0Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 3cac7dca0Sopenharmony_ci// you may not use this file except in compliance with the License. 4cac7dca0Sopenharmony_ci// You may obtain a copy of the License at 5cac7dca0Sopenharmony_ci// 6cac7dca0Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 7cac7dca0Sopenharmony_ci// 8cac7dca0Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 9cac7dca0Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 10cac7dca0Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11cac7dca0Sopenharmony_ci// See the License for the specific language governing permissions and 12cac7dca0Sopenharmony_ci// limitations under the License. 13cac7dca0Sopenharmony_ci 14cac7dca0Sopenharmony_ciuse std::ffi::c_void; 15cac7dca0Sopenharmony_ciuse std::fs::File; 16cac7dca0Sopenharmony_ciuse std::mem::{size_of, zeroed}; 17cac7dca0Sopenharmony_ciuse std::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle}; 18cac7dca0Sopenharmony_ciuse std::ptr::null_mut; 19cac7dca0Sopenharmony_ciuse std::sync::atomic::{AtomicUsize, Ordering}; 20cac7dca0Sopenharmony_ciuse std::sync::{Arc, Mutex}; 21cac7dca0Sopenharmony_ciuse std::{fmt, io}; 22cac7dca0Sopenharmony_ci 23cac7dca0Sopenharmony_ciuse crate::sys::winapi::{ 24cac7dca0Sopenharmony_ci NtCreateFile, NtDeviceIoControlFile, RtlNtStatusToDosError, SetFileCompletionNotificationModes, 25cac7dca0Sopenharmony_ci FILE_OPEN, FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SKIP_SET_EVENT_ON_HANDLE, HANDLE, 26cac7dca0Sopenharmony_ci INVALID_HANDLE_VALUE, IO_STATUS_BLOCK, IO_STATUS_BLOCK_0, NTSTATUS, OBJECT_ATTRIBUTES, 27cac7dca0Sopenharmony_ci STATUS_NOT_FOUND, STATUS_PENDING, STATUS_SUCCESS, SYNCHRONIZE, UNICODE_STRING, 28cac7dca0Sopenharmony_ci}; 29cac7dca0Sopenharmony_ciuse crate::sys::windows::iocp::CompletionPort; 30cac7dca0Sopenharmony_ci 31cac7dca0Sopenharmony_cipub const POLL_RECEIVE: u32 = 0x0001; 32cac7dca0Sopenharmony_cipub const POLL_RECEIVE_EXPEDITED: u32 = 0x0002; 33cac7dca0Sopenharmony_cipub const POLL_SEND: u32 = 0x0004; 34cac7dca0Sopenharmony_cipub const POLL_DISCONNECT: u32 = 0x0008; 35cac7dca0Sopenharmony_cipub const POLL_ABORT: u32 = 0x0010; 36cac7dca0Sopenharmony_cipub const POLL_LOCAL_CLOSE: u32 = 0x0020; 37cac7dca0Sopenharmony_cipub const POLL_ACCEPT: u32 = 0x0080; 38cac7dca0Sopenharmony_cipub const POLL_CONNECT_FAIL: u32 = 0x0100; 39cac7dca0Sopenharmony_ci 40cac7dca0Sopenharmony_cipub const ALL_EVENTS: u32 = POLL_RECEIVE 41cac7dca0Sopenharmony_ci | POLL_RECEIVE_EXPEDITED 42cac7dca0Sopenharmony_ci | POLL_SEND 43cac7dca0Sopenharmony_ci | POLL_DISCONNECT 44cac7dca0Sopenharmony_ci | POLL_ACCEPT 45cac7dca0Sopenharmony_ci | POLL_LOCAL_CLOSE 46cac7dca0Sopenharmony_ci | POLL_ABORT 47cac7dca0Sopenharmony_ci | POLL_CONNECT_FAIL; 48cac7dca0Sopenharmony_ci 49cac7dca0Sopenharmony_ciconst AFD_ATTRIBUTES: OBJECT_ATTRIBUTES = OBJECT_ATTRIBUTES { 50cac7dca0Sopenharmony_ci Length: size_of::<OBJECT_ATTRIBUTES>() as u32, 51cac7dca0Sopenharmony_ci RootDirectory: 0, 52cac7dca0Sopenharmony_ci ObjectName: &OBJ_NAME as *const _ as *mut _, 53cac7dca0Sopenharmony_ci Attributes: 0, 54cac7dca0Sopenharmony_ci SecurityDescriptor: null_mut(), 55cac7dca0Sopenharmony_ci SecurityQualityOfService: null_mut(), 56cac7dca0Sopenharmony_ci}; 57cac7dca0Sopenharmony_ciconst OBJ_NAME: UNICODE_STRING = UNICODE_STRING { 58cac7dca0Sopenharmony_ci Length: (AFD_HELPER_NAME.len() * size_of::<u16>()) as u16, 59cac7dca0Sopenharmony_ci MaximumLength: (AFD_HELPER_NAME.len() * size_of::<u16>()) as u16, 60cac7dca0Sopenharmony_ci Buffer: AFD_HELPER_NAME.as_ptr() as *mut _, 61cac7dca0Sopenharmony_ci}; 62cac7dca0Sopenharmony_ciconst AFD_HELPER_NAME: &[u16] = &[ 63cac7dca0Sopenharmony_ci '\\' as _, 'D' as _, 'e' as _, 'v' as _, 'i' as _, 'c' as _, 'e' as _, '\\' as _, 'A' as _, 64cac7dca0Sopenharmony_ci 'f' as _, 'd' as _, '\\' as _, 'Y' as _, 'l' as _, 'o' as _, 'n' as _, 'g' as _, 65cac7dca0Sopenharmony_ci]; 66cac7dca0Sopenharmony_ci 67cac7dca0Sopenharmony_cistatic NEXT_TOKEN: AtomicUsize = AtomicUsize::new(0); 68cac7dca0Sopenharmony_ciconst IOCTL_AFD_POLL: u32 = 0x00012024; 69cac7dca0Sopenharmony_ci 70cac7dca0Sopenharmony_ci#[link(name = "ntdll")] 71cac7dca0Sopenharmony_ciextern "system" { 72cac7dca0Sopenharmony_ci fn NtCancelIoFileEx( 73cac7dca0Sopenharmony_ci FileHandle: HANDLE, 74cac7dca0Sopenharmony_ci IoRequestToCancel: *mut IO_STATUS_BLOCK, 75cac7dca0Sopenharmony_ci IoStatusBlock: *mut IO_STATUS_BLOCK, 76cac7dca0Sopenharmony_ci ) -> NTSTATUS; 77cac7dca0Sopenharmony_ci} 78cac7dca0Sopenharmony_ci 79cac7dca0Sopenharmony_ci/// Asynchronous file descriptor 80cac7dca0Sopenharmony_ci/// Implementing a single file handle to monitor multiple Io operations using 81cac7dca0Sopenharmony_ci/// the IO multiplexing model. 82cac7dca0Sopenharmony_ci#[derive(Debug)] 83cac7dca0Sopenharmony_cipub struct Afd { 84cac7dca0Sopenharmony_ci fd: File, 85cac7dca0Sopenharmony_ci} 86cac7dca0Sopenharmony_ci 87cac7dca0Sopenharmony_ciimpl Afd { 88cac7dca0Sopenharmony_ci /// Creates a new Afd and add it to CompletionPort 89cac7dca0Sopenharmony_ci fn new(cp: &CompletionPort) -> io::Result<Afd> { 90cac7dca0Sopenharmony_ci let mut afd_device_handle: HANDLE = INVALID_HANDLE_VALUE; 91cac7dca0Sopenharmony_ci let mut io_status_block = IO_STATUS_BLOCK { 92cac7dca0Sopenharmony_ci Anonymous: IO_STATUS_BLOCK_0 { Status: 0 }, 93cac7dca0Sopenharmony_ci Information: 0, 94cac7dca0Sopenharmony_ci }; 95cac7dca0Sopenharmony_ci 96cac7dca0Sopenharmony_ci let fd = unsafe { 97cac7dca0Sopenharmony_ci let status = NtCreateFile( 98cac7dca0Sopenharmony_ci &mut afd_device_handle as *mut _, 99cac7dca0Sopenharmony_ci SYNCHRONIZE, 100cac7dca0Sopenharmony_ci &AFD_ATTRIBUTES as *const _ as *mut _, 101cac7dca0Sopenharmony_ci &mut io_status_block, 102cac7dca0Sopenharmony_ci null_mut(), 103cac7dca0Sopenharmony_ci 0, 104cac7dca0Sopenharmony_ci FILE_SHARE_READ | FILE_SHARE_WRITE, 105cac7dca0Sopenharmony_ci FILE_OPEN, 106cac7dca0Sopenharmony_ci 0, 107cac7dca0Sopenharmony_ci null_mut(), 108cac7dca0Sopenharmony_ci 0, 109cac7dca0Sopenharmony_ci ); 110cac7dca0Sopenharmony_ci 111cac7dca0Sopenharmony_ci if status != STATUS_SUCCESS { 112cac7dca0Sopenharmony_ci let raw_error = io::Error::from_raw_os_error(RtlNtStatusToDosError(status) as i32); 113cac7dca0Sopenharmony_ci 114cac7dca0Sopenharmony_ci let msg = format!("Failed to open \\Device\\Afd\\Ylong: {raw_error}"); 115cac7dca0Sopenharmony_ci return Err(io::Error::new(raw_error.kind(), msg)); 116cac7dca0Sopenharmony_ci } 117cac7dca0Sopenharmony_ci 118cac7dca0Sopenharmony_ci File::from_raw_handle(afd_device_handle as RawHandle) 119cac7dca0Sopenharmony_ci }; 120cac7dca0Sopenharmony_ci 121cac7dca0Sopenharmony_ci let token = NEXT_TOKEN.fetch_add(2, Ordering::Relaxed) + 2; 122cac7dca0Sopenharmony_ci let afd = Afd { fd }; 123cac7dca0Sopenharmony_ci // Add Afd to CompletionPort 124cac7dca0Sopenharmony_ci cp.add_handle(token, &afd.fd)?; 125cac7dca0Sopenharmony_ci 126cac7dca0Sopenharmony_ci syscall!( 127cac7dca0Sopenharmony_ci SetFileCompletionNotificationModes( 128cac7dca0Sopenharmony_ci afd_device_handle, 129cac7dca0Sopenharmony_ci FILE_SKIP_SET_EVENT_ON_HANDLE as u8, 130cac7dca0Sopenharmony_ci ), 131cac7dca0Sopenharmony_ci afd 132cac7dca0Sopenharmony_ci ) 133cac7dca0Sopenharmony_ci } 134cac7dca0Sopenharmony_ci 135cac7dca0Sopenharmony_ci /// System call 136cac7dca0Sopenharmony_ci pub(crate) unsafe fn poll( 137cac7dca0Sopenharmony_ci &self, 138cac7dca0Sopenharmony_ci info: &mut AfdPollInfo, 139cac7dca0Sopenharmony_ci iosb: *mut IO_STATUS_BLOCK, 140cac7dca0Sopenharmony_ci overlapped: *mut c_void, 141cac7dca0Sopenharmony_ci ) -> io::Result<bool> { 142cac7dca0Sopenharmony_ci let afd_info = (info as *mut AfdPollInfo).cast::<c_void>(); 143cac7dca0Sopenharmony_ci (*iosb).Anonymous.Status = STATUS_PENDING; 144cac7dca0Sopenharmony_ci 145cac7dca0Sopenharmony_ci let status = NtDeviceIoControlFile( 146cac7dca0Sopenharmony_ci self.fd.as_raw_handle() as HANDLE, 147cac7dca0Sopenharmony_ci 0, 148cac7dca0Sopenharmony_ci None, 149cac7dca0Sopenharmony_ci overlapped, 150cac7dca0Sopenharmony_ci iosb, 151cac7dca0Sopenharmony_ci IOCTL_AFD_POLL, 152cac7dca0Sopenharmony_ci afd_info, 153cac7dca0Sopenharmony_ci size_of::<AfdPollInfo>() as u32, 154cac7dca0Sopenharmony_ci afd_info, 155cac7dca0Sopenharmony_ci size_of::<AfdPollInfo>() as u32, 156cac7dca0Sopenharmony_ci ); 157cac7dca0Sopenharmony_ci 158cac7dca0Sopenharmony_ci match status { 159cac7dca0Sopenharmony_ci STATUS_SUCCESS => Ok(true), 160cac7dca0Sopenharmony_ci // this is expected. 161cac7dca0Sopenharmony_ci STATUS_PENDING => Ok(false), 162cac7dca0Sopenharmony_ci _ => Err(io::Error::from_raw_os_error( 163cac7dca0Sopenharmony_ci RtlNtStatusToDosError(status) as i32 164cac7dca0Sopenharmony_ci )), 165cac7dca0Sopenharmony_ci } 166cac7dca0Sopenharmony_ci } 167cac7dca0Sopenharmony_ci 168cac7dca0Sopenharmony_ci /// System call to cancel File HANDLE. 169cac7dca0Sopenharmony_ci pub(crate) unsafe fn cancel(&self, iosb: *mut IO_STATUS_BLOCK) -> io::Result<()> { 170cac7dca0Sopenharmony_ci if (*iosb).Anonymous.Status != STATUS_PENDING { 171cac7dca0Sopenharmony_ci return Ok(()); 172cac7dca0Sopenharmony_ci } 173cac7dca0Sopenharmony_ci 174cac7dca0Sopenharmony_ci let mut cancel_iosb = IO_STATUS_BLOCK { 175cac7dca0Sopenharmony_ci Anonymous: IO_STATUS_BLOCK_0 { Status: 0 }, 176cac7dca0Sopenharmony_ci Information: 0, 177cac7dca0Sopenharmony_ci }; 178cac7dca0Sopenharmony_ci let status = NtCancelIoFileEx(self.fd.as_raw_handle() as HANDLE, iosb, &mut cancel_iosb); 179cac7dca0Sopenharmony_ci match status { 180cac7dca0Sopenharmony_ci STATUS_SUCCESS | STATUS_NOT_FOUND => Ok(()), 181cac7dca0Sopenharmony_ci _ => Err(io::Error::from_raw_os_error( 182cac7dca0Sopenharmony_ci RtlNtStatusToDosError(status) as i32 183cac7dca0Sopenharmony_ci )), 184cac7dca0Sopenharmony_ci } 185cac7dca0Sopenharmony_ci } 186cac7dca0Sopenharmony_ci} 187cac7dca0Sopenharmony_ci 188cac7dca0Sopenharmony_ci/// A group which contains Afds. 189cac7dca0Sopenharmony_ci#[derive(Debug)] 190cac7dca0Sopenharmony_cipub(crate) struct AfdGroup { 191cac7dca0Sopenharmony_ci cp: Arc<CompletionPort>, 192cac7dca0Sopenharmony_ci afd_group: Mutex<Vec<Arc<Afd>>>, 193cac7dca0Sopenharmony_ci} 194cac7dca0Sopenharmony_ci 195cac7dca0Sopenharmony_ci/// Up to 32 Arc points per Afd. 196cac7dca0Sopenharmony_ciconst POLL_GROUP__MAX_GROUP_SIZE: usize = 32; 197cac7dca0Sopenharmony_ci 198cac7dca0Sopenharmony_ciimpl AfdGroup { 199cac7dca0Sopenharmony_ci /// Creates a new AfdGroup. 200cac7dca0Sopenharmony_ci pub(crate) fn new(cp: Arc<CompletionPort>) -> AfdGroup { 201cac7dca0Sopenharmony_ci AfdGroup { 202cac7dca0Sopenharmony_ci afd_group: Mutex::new(Vec::new()), 203cac7dca0Sopenharmony_ci cp, 204cac7dca0Sopenharmony_ci } 205cac7dca0Sopenharmony_ci } 206cac7dca0Sopenharmony_ci 207cac7dca0Sopenharmony_ci /// Gets a new point to File. 208cac7dca0Sopenharmony_ci pub(crate) fn acquire(&self) -> io::Result<Arc<Afd>> { 209cac7dca0Sopenharmony_ci let mut afd_group = self.afd_group.lock().unwrap(); 210cac7dca0Sopenharmony_ci 211cac7dca0Sopenharmony_ci // When the last File has more than 32 Arc Points, creates a new File. 212cac7dca0Sopenharmony_ci // If the vec len is not zero, then last always returns some 213cac7dca0Sopenharmony_ci if afd_group.len() == 0 214cac7dca0Sopenharmony_ci || Arc::strong_count(afd_group.last().unwrap()) > POLL_GROUP__MAX_GROUP_SIZE 215cac7dca0Sopenharmony_ci { 216cac7dca0Sopenharmony_ci let arc = Arc::new(Afd::new(&self.cp)?); 217cac7dca0Sopenharmony_ci afd_group.push(arc); 218cac7dca0Sopenharmony_ci } 219cac7dca0Sopenharmony_ci 220cac7dca0Sopenharmony_ci match afd_group.last() { 221cac7dca0Sopenharmony_ci Some(arc) => Ok(arc.clone()), 222cac7dca0Sopenharmony_ci None => unreachable!( 223cac7dca0Sopenharmony_ci "Cannot acquire afd, {:#?}, afd_group: {:#?}", 224cac7dca0Sopenharmony_ci self, afd_group 225cac7dca0Sopenharmony_ci ), 226cac7dca0Sopenharmony_ci } 227cac7dca0Sopenharmony_ci } 228cac7dca0Sopenharmony_ci 229cac7dca0Sopenharmony_ci /// Delete Afd that is no longer in use from AfdGroup. 230cac7dca0Sopenharmony_ci pub(crate) fn release_unused_afd(&self) { 231cac7dca0Sopenharmony_ci let mut afd_group = self.afd_group.lock().unwrap(); 232cac7dca0Sopenharmony_ci afd_group.retain(|g| Arc::strong_count(g) > 1); 233cac7dca0Sopenharmony_ci } 234cac7dca0Sopenharmony_ci} 235cac7dca0Sopenharmony_ci 236cac7dca0Sopenharmony_ci#[repr(C)] 237cac7dca0Sopenharmony_cipub struct AfdPollInfo { 238cac7dca0Sopenharmony_ci pub timeout: i64, 239cac7dca0Sopenharmony_ci pub number_of_handles: u32, 240cac7dca0Sopenharmony_ci pub exclusive: u32, 241cac7dca0Sopenharmony_ci pub handles: [AfdPollHandleInfo; 1], 242cac7dca0Sopenharmony_ci} 243cac7dca0Sopenharmony_ci 244cac7dca0Sopenharmony_ciimpl AfdPollInfo { 245cac7dca0Sopenharmony_ci pub(crate) fn zeroed() -> AfdPollInfo { 246cac7dca0Sopenharmony_ci unsafe { zeroed() } 247cac7dca0Sopenharmony_ci } 248cac7dca0Sopenharmony_ci} 249cac7dca0Sopenharmony_ci 250cac7dca0Sopenharmony_ciimpl fmt::Debug for AfdPollInfo { 251cac7dca0Sopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 252cac7dca0Sopenharmony_ci f.debug_struct("AfdPollInfo").finish() 253cac7dca0Sopenharmony_ci } 254cac7dca0Sopenharmony_ci} 255cac7dca0Sopenharmony_ci 256cac7dca0Sopenharmony_ci#[repr(C)] 257cac7dca0Sopenharmony_ci#[derive(Debug)] 258cac7dca0Sopenharmony_cipub struct AfdPollHandleInfo { 259cac7dca0Sopenharmony_ci /// SockState base_socket 260cac7dca0Sopenharmony_ci pub handle: HANDLE, 261cac7dca0Sopenharmony_ci pub events: u32, 262cac7dca0Sopenharmony_ci pub status: NTSTATUS, 263cac7dca0Sopenharmony_ci} 264cac7dca0Sopenharmony_ci 265cac7dca0Sopenharmony_ciunsafe impl Send for AfdPollHandleInfo {} 266