use std::path::{Path, PathBuf}; use sysinfo::{System, SystemExt, Pid, PidExt, ProcessExt}; use serde::{Serialize, Deserialize}; use std::os::windows::io::AsRawHandle; #[cfg(windows)] use { tokio::net::windows::named_pipe::NamedPipeServer, windows::Win32::{ Foundation::HANDLE, System::Pipes::GetNamedPipeClientProcessId, }, }; #[cfg(unix)] use tokio::net::UnixStream; use crate::errors::*; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] pub struct Client { pub pid: u32, pub exe: Option, } #[cfg(unix)] pub fn get_client_parent(stream: &UnixStream) -> Result { let pid = stream.peer_cred()?; get_process_parent_info(pid)? } #[cfg(windows)] pub fn get_client_parent(stream: &NamedPipeServer) -> Result { let raw_handle = stream.as_raw_handle(); let mut pid = 0u32; let handle = HANDLE(raw_handle as _); unsafe { GetNamedPipeClientProcessId(handle, &mut pid as *mut u32)? }; get_process_parent_info(pid) } fn get_process_parent_info(pid: u32) -> Result { let sys_pid = Pid::from_u32(pid); let mut sys = System::new(); sys.refresh_process(sys_pid); let proc = sys.process(sys_pid) .ok_or(ClientInfoError::ProcessNotFound)?; let parent_pid_sys = proc.parent() .ok_or(ClientInfoError::ParentPidNotFound)?; sys.refresh_process(parent_pid_sys); let parent = sys.process(parent_pid_sys) .ok_or(ClientInfoError::ParentProcessNotFound)?; let exe = match parent.exe() { p if p == Path::new("") => None, p => Some(PathBuf::from(p)), }; Ok(Client { pid: parent_pid_sys.as_u32(), exe }) } // async fn get_associated_pids(local_port: u16) -> Result, netstat2::error::Error> { // let state = APP.get().unwrap().state::(); // let AppConfig { // listen_addr: app_listen_addr, // listen_port: app_listen_port, // .. // } = *state.config.read().await; // let sockets_iter = netstat2::iterate_sockets_info( // AddressFamilyFlags::IPV4, // ProtocolFlags::TCP // )?; // for item in sockets_iter { // let sock_info = item?; // let proto_info = match sock_info.protocol_socket_info { // ProtocolSocketInfo::Tcp(tcp_info) => tcp_info, // ProtocolSocketInfo::Udp(_) => {continue;} // }; // if proto_info.local_port == local_port // && proto_info.remote_port == app_listen_port // && proto_info.local_addr == app_listen_addr // && proto_info.remote_addr == app_listen_addr // { // return Ok(sock_info.associated_pids) // } // } // Ok(vec![]) // } // Theoretically, on some systems, multiple processes can share a socket // pub async fn get_clients(local_port: u16) -> Result>, ClientInfoError> { // let mut clients = Vec::new(); // let mut sys = System::new(); // for p in get_associated_pids(local_port).await? { // let pid = Pid::from_u32(p); // sys.refresh_process(pid); // let proc = sys.process(pid) // .ok_or(ClientInfoError::ProcessNotFound)?; // let client = Client { // pid: p, // exe: proc.exe().to_path_buf(), // }; // clients.push(Some(client)); // } // if clients.is_empty() { // clients.push(None); // } // Ok(clients) // }