use netstat2::{AddressFamilyFlags, ProtocolFlags, ProtocolSocketInfo}; use tauri::Manager; use sysinfo::{System, SystemExt, Pid, PidExt, ProcessExt}; use serde::{Serialize, Deserialize}; use crate::{ errors::*, config::AppConfig, state::AppState, }; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] pub struct Client { pub pid: u32, pub exe: String, } async fn get_associated_pids(local_port: u16) -> Result, netstat2::error::Error> { let state = crate::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_string_lossy().into_owned(), }; clients.push(Some(client)); } if clients.is_empty() { clients.push(None); } Ok(clients) }