Skip to content

Commit cabd819

Browse files
authored
Merge pull request #60 from GyulyVGC/lighten-deps
Lighten the dependency tree on Windows and macOS
2 parents a058499 + 582a8cf commit cabd819

6 files changed

Lines changed: 68 additions & 61 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
All releases with the relative changes are documented in this file.
44

5+
## [UNRELEASED]
6+
### Changed
7+
- Lighten the dependency tree: drop `byteorder` on macOS, and use `windows-sys` instead of `windows` on Windows ([#60](https://github.com/GyulyVGC/listeners/pull/60))
8+
59
## [0.6.1] - 2026-08-02
610
### Fixed
711
- Correctly report IPv4-mapped IPv6 addresses on macOS ([#57](https://github.com/GyulyVGC/listeners/pull/57) — fixes [#56](https://github.com/GyulyVGC/listeners/issues/56))

Cargo.toml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,13 @@ print_stdout = "warn"
2424
print_stderr = "warn"
2525

2626
[target.'cfg(target_os = "windows")'.dependencies]
27-
windows = { version = "0.62", features = [
27+
windows-sys = { version = "0.61", features = [
2828
"Win32_Foundation",
2929
"Win32_System_Diagnostics_ToolHelp",
3030
"Win32_System_Threading",
3131
"Win32_NetworkManagement_IpHelper"
3232
] }
3333

34-
[target.'cfg(target_os = "macos")'.dependencies]
35-
byteorder = "1.5"
36-
3734
[target.'cfg(target_os = "linux")'.dependencies]
3835
rustix = {version = "1.1", features = ["fs"]}
3936

src/platform/macos/c_socket_fd_info.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use std::ffi::{c_char, c_int, c_longlong, c_short, c_uchar, c_uint, c_ushort};
22
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
33

4-
use byteorder::{ByteOrder, NetworkEndian};
5-
64
use crate::platform::macos::proto_listener::ProtoListener;
75
use crate::{Protocol, SocketState};
86

@@ -34,13 +32,13 @@ impl CSocketFdInfo {
3432
}
3533
};
3634

37-
let lport_bytes: [u8; 4] = i32::to_le_bytes(general_sock_info.insi_lport);
35+
let [lport_hi, lport_lo, ..] = i32::to_le_bytes(general_sock_info.insi_lport);
3836
let local_address = Self::get_local_addr(family, general_sock_info)?;
3937
let protocol = Self::get_protocol(family, transport_protocol)?;
4038

4139
let socket_info = ProtoListener::new(
4240
local_address,
43-
NetworkEndian::read_u16(&lport_bytes),
41+
u16::from_be_bytes([lport_hi, lport_lo]),
4442
protocol,
4543
state,
4644
);
@@ -82,10 +80,8 @@ impl CSocketFdInfo {
8280

8381
/// The 16-byte `ina_6` slot.
8482
fn v6_slot(sock_info: &InSockinfo) -> Ipv6Addr {
85-
let addr = unsafe { &sock_info.insi_laddr.ina_6.__u6_addr.__u6_addr8 };
86-
let mut ipv6_addr = [0_u16; 8];
87-
NetworkEndian::read_u16_into(addr, &mut ipv6_addr);
88-
Ipv6Addr::from(ipv6_addr)
83+
let addr = unsafe { sock_info.insi_laddr.ina_6.__u6_addr.__u6_addr8 };
84+
Ipv6Addr::from(addr)
8985
}
9086

9187
fn get_protocol(family: c_int, ip_protocol: c_int) -> crate::Result<Protocol> {

src/platform/windows/proto_listener.rs

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,19 @@ use crate::platform::windows::tcp_table::TcpTable;
66
use crate::platform::windows::tcp6_table::Tcp6Table;
77
use std::collections::HashMap;
88
use std::collections::hash_map::Entry;
9+
use std::ffi::CStr;
910
use std::mem::size_of;
1011
use std::mem::zeroed;
1112
use std::net::{IpAddr, SocketAddr};
1213
use std::os::windows::ffi::OsStringExt;
1314
use std::path::Path;
14-
use windows::Win32::Foundation::CloseHandle;
15-
use windows::Win32::System::Diagnostics::ToolHelp::{
15+
use windows_sys::Win32::Foundation::{CloseHandle, FALSE, HANDLE, INVALID_HANDLE_VALUE};
16+
use windows_sys::Win32::System::Diagnostics::ToolHelp::{
1617
CreateToolhelp32Snapshot, PROCESSENTRY32, Process32First, Process32Next, TH32CS_SNAPPROCESS,
1718
};
18-
use windows::Win32::System::Threading::{
19-
OpenProcess, PROCESS_NAME_FORMAT, PROCESS_QUERY_LIMITED_INFORMATION, QueryFullProcessImageNameW,
19+
use windows_sys::Win32::System::Threading::{
20+
OpenProcess, PROCESS_NAME_WIN32, PROCESS_QUERY_LIMITED_INFORMATION, QueryFullProcessImageNameW,
2021
};
21-
use windows::core::PCSTR;
22-
use windows::core::PWSTR;
2322

2423
use super::udp_table::UdpTable;
2524
use super::udp6_table::Udp6Table;
@@ -149,27 +148,46 @@ impl PidNamePathCache {
149148
}
150149
}
151150

151+
fn is_invalid(handle: HANDLE) -> bool {
152+
handle.is_null() || handle == INVALID_HANDLE_VALUE
153+
}
154+
155+
/// Takes a snapshot of the running processes.
156+
fn process_snapshot() -> Option<HANDLE> {
157+
let handle = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
158+
(!is_invalid(handle)).then_some(handle)
159+
}
160+
161+
/// Reads the `szExeFile` field of a process entry.
162+
///
163+
/// Returns `None` if the field isn't NUL-terminated or isn't valid UTF-8.
164+
fn exe_file(process: &PROCESSENTRY32) -> Option<String> {
165+
let raw = &process.szExeFile;
166+
// SAFETY: `c_char` and `u8` share their layout, and the length is taken from the
167+
// array itself, so the read stays within `szExeFile` even if the OS didn't
168+
// NUL-terminate it.
169+
let bytes = unsafe { std::slice::from_raw_parts(raw.as_ptr().cast::<u8>(), raw.len()) };
170+
let name = CStr::from_bytes_until_nul(bytes).ok()?;
171+
name.to_str().ok().map(str::to_owned)
172+
}
173+
152174
fn pname(pid: u32) -> Option<String> {
153-
let h = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0).ok()? };
175+
let dw_size = u32::try_from(size_of::<PROCESSENTRY32>()).ok()?;
176+
let h = process_snapshot()?;
154177

155178
let mut process = unsafe { zeroed::<PROCESSENTRY32>() };
156-
process.dwSize = u32::try_from(size_of::<PROCESSENTRY32>()).ok()?;
179+
process.dwSize = dw_size;
157180

158181
let mut result = None;
159182

160-
if unsafe { Process32First(h, &raw mut process) }.is_ok() {
183+
if unsafe { Process32First(h, &raw mut process) } != FALSE {
161184
loop {
162185
if process.th32ProcessID == pid {
163-
let name = unsafe {
164-
PCSTR(process.szExeFile.as_ptr().cast::<u8>())
165-
.to_string()
166-
.ok()?
167-
};
168-
result = Some(name);
186+
result = exe_file(&process);
169187
break;
170188
}
171189

172-
if unsafe { Process32Next(h, &raw mut process) }.is_err() {
190+
if unsafe { Process32Next(h, &raw mut process) } == FALSE {
173191
break;
174192
}
175193
}
@@ -184,10 +202,8 @@ fn pname(pid: u32) -> Option<String> {
184202

185203
fn ppath(pid: u32) -> String {
186204
unsafe {
187-
let Ok(handle) = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid) else {
188-
return String::new();
189-
};
190-
if handle.is_invalid() {
205+
let handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
206+
if is_invalid(handle) {
191207
return String::new();
192208
}
193209

@@ -196,13 +212,13 @@ fn ppath(pid: u32) -> String {
196212

197213
let result = QueryFullProcessImageNameW(
198214
handle,
199-
PROCESS_NAME_FORMAT(0),
200-
PWSTR(buffer.as_mut_ptr()),
215+
PROCESS_NAME_WIN32,
216+
buffer.as_mut_ptr(),
201217
&raw mut size,
202218
);
203219
let _ = CloseHandle(handle);
204220

205-
if result.is_err() {
221+
if result == FALSE {
206222
return String::new();
207223
}
208224

@@ -214,25 +230,24 @@ fn ppath(pid: u32) -> String {
214230
fn pname_collect() -> HashMap<u32, String> {
215231
let mut ret_val = HashMap::default();
216232

217-
let Ok(h) = (unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }) else {
233+
let Ok(dw_size) = u32::try_from(size_of::<PROCESSENTRY32>()) else {
218234
return ret_val;
219235
};
220-
221-
let mut process = unsafe { zeroed::<PROCESSENTRY32>() };
222-
let Ok(dw_size) = u32::try_from(size_of::<PROCESSENTRY32>()) else {
236+
let Some(h) = process_snapshot() else {
223237
return ret_val;
224238
};
239+
240+
let mut process = unsafe { zeroed::<PROCESSENTRY32>() };
225241
process.dwSize = dw_size;
226242

227-
if unsafe { Process32First(h, &raw mut process) }.is_ok() {
243+
if unsafe { Process32First(h, &raw mut process) } != FALSE {
228244
loop {
229-
if let Ok(name) = unsafe { PCSTR(process.szExeFile.as_ptr().cast::<u8>()).to_string() }
230-
{
245+
if let Some(name) = exe_file(&process) {
231246
let id = process.th32ProcessID;
232247
ret_val.insert(id, name);
233248
}
234249

235-
if unsafe { Process32Next(h, &raw mut process) }.is_err() {
250+
if unsafe { Process32Next(h, &raw mut process) } == FALSE {
236251
break;
237252
}
238253
}

src/platform/windows/socket_table.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
use std::ffi::{c_ulong, c_void};
22
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
33

4-
use super::statics::UDP_TABLE_OWNER_PID;
54
use crate::Protocol;
65
use crate::SocketState;
76
use crate::platform::target_os::proto_listener::ProtoListener;
8-
use crate::platform::windows::statics::{
9-
AF_INET, AF_INET6, ERROR_INSUFFICIENT_BUFFER, NO_ERROR, TCP_TABLE_OWNER_PID_ALL,
10-
};
7+
use crate::platform::windows::statics::{AF_INET, AF_INET6};
118
use crate::platform::windows::tcp_table::TcpTable;
129
use crate::platform::windows::tcp6_table::Tcp6Table;
1310
use crate::platform::windows::udp_table::UdpTable;
1411
use crate::platform::windows::udp6_table::Udp6Table;
15-
use windows::Win32::NetworkManagement::IpHelper::{GetExtendedTcpTable, GetExtendedUdpTable};
12+
use windows_sys::Win32::Foundation::{ERROR_INSUFFICIENT_BUFFER, FALSE, NO_ERROR};
13+
use windows_sys::Win32::NetworkManagement::IpHelper::{
14+
GetExtendedTcpTable, GetExtendedUdpTable, TCP_TABLE_OWNER_PID_ALL, UDP_TABLE_OWNER_PID,
15+
};
1616

1717
pub(super) trait SocketTable {
1818
fn get_table() -> crate::Result<Vec<u8>>;
@@ -180,9 +180,9 @@ fn get_udp_table(address_family: c_ulong) -> crate::Result<Vec<u8>> {
180180
let mut table_size: c_ulong = 0;
181181
let mut err_code = unsafe {
182182
GetExtendedUdpTable(
183-
None,
183+
std::ptr::null_mut(),
184184
&raw mut table_size,
185-
false,
185+
FALSE,
186186
address_family,
187187
UDP_TABLE_OWNER_PID,
188188
0,
@@ -194,9 +194,9 @@ fn get_udp_table(address_family: c_ulong) -> crate::Result<Vec<u8>> {
194194
table = Vec::<u8>::with_capacity(table_size as usize);
195195
err_code = unsafe {
196196
GetExtendedUdpTable(
197-
Some(table.as_mut_ptr().cast::<c_void>()),
197+
table.as_mut_ptr().cast::<c_void>(),
198198
&raw mut table_size,
199-
false,
199+
FALSE,
200200
address_family,
201201
UDP_TABLE_OWNER_PID,
202202
0,
@@ -218,9 +218,9 @@ fn get_tcp_table(address_family: c_ulong) -> crate::Result<Vec<u8>> {
218218
let mut table_size: c_ulong = 0;
219219
let mut err_code = unsafe {
220220
GetExtendedTcpTable(
221-
None,
221+
std::ptr::null_mut(),
222222
&raw mut table_size,
223-
false,
223+
FALSE,
224224
address_family,
225225
TCP_TABLE_OWNER_PID_ALL,
226226
0,
@@ -232,9 +232,9 @@ fn get_tcp_table(address_family: c_ulong) -> crate::Result<Vec<u8>> {
232232
table = Vec::<u8>::with_capacity(table_size as usize);
233233
err_code = unsafe {
234234
GetExtendedTcpTable(
235-
Some(table.as_mut_ptr().cast::<c_void>()),
235+
table.as_mut_ptr().cast::<c_void>(),
236236
&raw mut table_size,
237-
false,
237+
FALSE,
238238
address_family,
239239
TCP_TABLE_OWNER_PID_ALL,
240240
0,

src/platform/windows/statics.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
use std::ffi::c_ulong;
2-
use windows::Win32::NetworkManagement::IpHelper::{TCP_TABLE_CLASS, UDP_TABLE_CLASS};
32

4-
pub(super) const TCP_TABLE_OWNER_PID_ALL: TCP_TABLE_CLASS = TCP_TABLE_CLASS(5);
5-
pub(super) const UDP_TABLE_OWNER_PID: UDP_TABLE_CLASS = UDP_TABLE_CLASS(1);
6-
pub(super) const ERROR_INSUFFICIENT_BUFFER: c_ulong = 0x7A;
7-
pub(super) const NO_ERROR: c_ulong = 0;
83
pub(super) const AF_INET: c_ulong = 2;
94
pub(super) const AF_INET6: c_ulong = 23;

0 commit comments

Comments
 (0)