Skip to content

Commit 1752eb1

Browse files
committed
get process parsing nettop output on macOS (very WIP)
1 parent c70f946 commit 1752eb1

2 files changed

Lines changed: 90 additions & 38 deletions

File tree

src/gui/pages/overview_page.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ fn col_process<'a>(sniffer: &Sniffer) -> Column<'a, Message, StyleType> {
413413
.iter()
414414
.map(|&(_, (d, _))| d)
415415
.max_by(|d1, d2| d1.compare(&d2, SortType::Ascending, chart_type))
416-
.unwrap();
416+
.unwrap_or_default();
417417

418418
for (process, (data_info, handle)) in &entries {
419419
let content = simpler_bar(

src/networking/manage_packets.rs

Lines changed: 89 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ use iced::widget::image::Handle;
2525
use image::{GenericImageView, RgbaImage};
2626
use objc::{class, msg_send, sel, sel_impl};
2727
use std::fmt::Write;
28+
use std::path::Path;
29+
use std::process::Command;
2830

2931
include!(concat!(env!("OUT_DIR"), "/services.rs"));
3032

@@ -266,7 +268,7 @@ pub fn modify_or_insert_in_map(
266268
) -> (TrafficDirection, Service, String, Option<Handle>) {
267269
let mut traffic_direction = TrafficDirection::default();
268270
let mut service = Service::Unknown;
269-
let mut process = "-".to_string();
271+
let mut process = "?".to_string();
270272
let mut picon = None;
271273

272274
if !info_traffic_msg.map.contains_key(key) {
@@ -287,43 +289,40 @@ pub fn modify_or_insert_in_map(
287289
service = get_service(key, traffic_direction, my_interface_addresses);
288290
// determine process
289291
if let Some(local_port) = get_local_port(key, traffic_direction) {
290-
let processes = listeners::get_processes_by_port(local_port);
291-
process = processes
292-
.into_iter()
293-
.flatten()
294-
.next()
295-
.map_or("?".to_string(), |p| {
296-
let path = get_executable_path(p.pid as i32);
297-
let mut image: Option<iced::widget::Image> = None;
298-
println!("Process: {} (PID: {})", p.name, p.pid);
299-
if let Some(app_path) = path {
300-
println!("--> Exe path: {}", app_path);
301-
if let Some(bundle_path) = find_app_bundle_path(&app_path) {
302-
println!("--> Bundle path: {}", bundle_path);
303-
if let Some(tiff) = get_icon_tiff_bytes(&bundle_path) {
304-
let img =
305-
image::load_from_memory(&tiff).expect("Failed to decode image");
306-
// resize the image
307-
let resized =
308-
img.resize_exact(64, 64, image::imageops::FilterType::Lanczos3);
309-
let (width, height) = resized.dimensions();
310-
println!("--> Icon size: {}x{}", width, height);
311-
// crop the image
312-
let sub =
313-
image::imageops::crop_imm(&resized, 6, 6, 52, 52).to_image();
314-
let (width, height) = sub.dimensions();
315-
println!("--> Cropped icon size: {}x{}", width, height);
316-
317-
picon = Some(iced::widget::image::Handle::from_rgba(
318-
width,
319-
height,
320-
sub.into_raw(),
321-
));
322-
}
323-
}
292+
let processes = get_processes();
293+
let pid = processes.get(&local_port).unwrap_or(&0);
294+
let path = get_executable_path(*pid as i32);
295+
let mut image: Option<iced::widget::Image> = None;
296+
// println!("Process: {} (PID: {})", path, p.pid);
297+
if let Some(app_path) = path {
298+
process = Path::new(&app_path)
299+
.file_name()
300+
.unwrap_or_default()
301+
.to_string_lossy()
302+
.to_string();
303+
// println!("--> Exe path: {}", app_path);
304+
if let Some(bundle_path) = find_app_bundle_path(&app_path) {
305+
// println!("--> Bundle path: {}", bundle_path);
306+
if let Some(tiff) = get_icon_tiff_bytes(&bundle_path) {
307+
let img = image::load_from_memory(&tiff).expect("Failed to decode image");
308+
// resize the image
309+
let resized =
310+
img.resize_exact(64, 64, image::imageops::FilterType::Lanczos3);
311+
let (width, height) = resized.dimensions();
312+
// println!("--> Icon size: {}x{}", width, height);
313+
// crop the image
314+
let sub = image::imageops::crop_imm(&resized, 6, 6, 52, 52).to_image();
315+
let (width, height) = sub.dimensions();
316+
// println!("--> Cropped icon size: {}x{}", width, height);
317+
318+
picon = Some(iced::widget::image::Handle::from_rgba(
319+
width,
320+
height,
321+
sub.into_raw(),
322+
));
324323
}
325-
p.name
326-
});
324+
}
325+
}
327326
}
328327
}
329328

@@ -378,6 +377,59 @@ pub fn modify_or_insert_in_map(
378377
)
379378
}
380379

380+
fn get_processes() -> HashMap<u16, u32> {
381+
let output = Command::new("nettop")
382+
.args(&["-n", "-L", "1", "-J", ""])
383+
.output()
384+
.unwrap();
385+
386+
if !output.status.success() {
387+
return HashMap::new();
388+
}
389+
390+
let stdout = String::from_utf8_lossy(&output.stdout);
391+
392+
let mut map = HashMap::new();
393+
let mut current_pid: Option<u32> = None;
394+
395+
for line in stdout.lines() {
396+
let line = line.trim().trim_end_matches(',');
397+
398+
if line.is_empty() {
399+
continue;
400+
}
401+
402+
// Detect process line: processName.PID
403+
if let Some(dot_pos) = line.rfind('.') {
404+
let pid_str = &line[dot_pos + 1..];
405+
if let Ok(pid) = pid_str.parse::<u32>() {
406+
current_pid = Some(pid);
407+
continue;
408+
}
409+
}
410+
411+
// Parse connection line
412+
if let Some(pid) = current_pid {
413+
// Expect format like: tcp4 192.168.1.102:64694<->172.64.155.209:443
414+
if let Some(space_pos) = line.find(' ') {
415+
let addr = &line[space_pos + 1..];
416+
if let Some((local, _remote)) = addr.split_once("<->") {
417+
// Extract port from local address (skip if wildcard)
418+
if let Some((_ip, port_str)) = local.rsplit_once(':') {
419+
if port_str != "*" {
420+
if let Ok(port) = port_str.parse::<u16>() {
421+
map.insert(port, pid);
422+
}
423+
}
424+
}
425+
}
426+
}
427+
}
428+
}
429+
430+
map
431+
}
432+
381433
unsafe extern "C" {
382434
fn proc_pidpath(pid: c_int, buffer: *mut libc::c_void, buffersize: u32) -> c_int;
383435
}

0 commit comments

Comments
 (0)