EvanZhu0721 / 公开仓库
SBMS
SBMS complete the calculation rules for the default logical desktop topology relationship and the physical dimensions of the displays in the Windows multi-screen collaboration system.
文件
../ bininputuiconfig.rs81.2 KBcontrol.rs4.1 KBcontroller.rs43.6 KBdiagnostics.rs24.2 KBdisplay.rs29.8 KBgeometry.rs21.4 KBgpu_renderer.rs37.4 KBinput.rs79.7 KBlaunch_broker.rs10.3 KBlib.rs350 Blimits.rs714 Bmain.rs24.4 KBmapping.rs46.5 KBnetwork.rs9.2 KBrenderer.rs20.6 KBsession_gate.rs14.9 KBsunshine.rs12.2 KBui.rs68.5 KBvirtual_display.rs7.2 KBwin32_flyout.rs3.4 KBwin32_tray.rs22.3 KBwindow_migration.rs43.8 KBsrc/network.rs9.2 KB
1
use std::mem::{MaybeUninit, size_of};2
use std::net::Ipv4Addr;3
4
use windows::Win32::Foundation::{ERROR_BUFFER_OVERFLOW, ERROR_NO_DATA, NO_ERROR};5
use windows::Win32::NetworkManagement::IpHelper::{6
GAA_FLAG_INCLUDE_GATEWAYS, GAA_FLAG_SKIP_ANYCAST, GAA_FLAG_SKIP_DNS_SERVER,7
GAA_FLAG_SKIP_MULTICAST, GET_ADAPTERS_ADDRESSES_FLAGS, GetAdaptersAddresses,8
IF_TYPE_ETHERNET_CSMACD, IF_TYPE_FASTETHER, IF_TYPE_FASTETHER_FX, IF_TYPE_GIGABITETHERNET,9
IF_TYPE_IEEE80211, IF_TYPE_PPP, IF_TYPE_PROP_VIRTUAL, IF_TYPE_SOFTWARE_LOOPBACK,10
IF_TYPE_TUNNEL, IF_TYPE_WWANPP, IF_TYPE_WWANPP2, IP_ADAPTER_ADDRESSES_LH,11
IP_ADAPTER_GATEWAY_ADDRESS_LH,12
};13
use windows::Win32::NetworkManagement::Ndis::IfOperStatusUp;14
use windows::Win32::Networking::WinSock::{15
AF_INET, IpDadStateDeprecated, IpDadStatePreferred, SOCKADDR_IN, SOCKET_ADDRESS,16
};17
18
#[derive(Clone, Copy, Debug, Eq, PartialEq)]19
struct LanIpv4Candidate {20
address: Ipv4Addr,21
interface_type: u32,22
has_gateway: bool,23
has_physical_address: bool,24
dad_rank: u8,25
metric: u32,26
}27
28
pub(crate) fn preferred_lan_ipv4() -> Result<Option<Ipv4Addr>, String> {29
let flags = GET_ADAPTERS_ADDRESSES_FLAGS(30
GAA_FLAG_INCLUDE_GATEWAYS.031
| GAA_FLAG_SKIP_ANYCAST.032
| GAA_FLAG_SKIP_MULTICAST.033
| GAA_FLAG_SKIP_DNS_SERVER.0,34
);35
let mut required_bytes = 0_u32;36
let sizing_status =37
unsafe { GetAdaptersAddresses(AF_INET.0.into(), flags, None, None, &mut required_bytes) };38
if sizing_status == ERROR_NO_DATA.0 || (sizing_status == NO_ERROR.0 && required_bytes == 0) {39
return Ok(None);40
}41
if sizing_status != ERROR_BUFFER_OVERFLOW.0 {42
return Err(format_windows_error(43
"Couldn’t size the network adapter list",44
sizing_status,45
));46
}47
48
for _ in 0..2 {49
let record_count = (required_bytes as usize).div_ceil(size_of::<IP_ADAPTER_ADDRESSES_LH>());50
let mut storage = Vec::<MaybeUninit<IP_ADAPTER_ADDRESSES_LH>>::with_capacity(record_count);51
storage.resize_with(record_count, MaybeUninit::uninit);52
let adapters = storage.as_mut_ptr().cast::<IP_ADAPTER_ADDRESSES_LH>();53
let status = unsafe {54
GetAdaptersAddresses(55
AF_INET.0.into(),56
flags,57
None,58
Some(adapters),59
&mut required_bytes,60
)61
};62
if status == ERROR_BUFFER_OVERFLOW.0 {63
continue;64
}65
if status == ERROR_NO_DATA.0 {66
return Ok(None);67
}68
if status != NO_ERROR.0 {69
return Err(format_windows_error(70
"Couldn’t enumerate network adapters",71
status,72
));73
}74
75
let mut candidates = Vec::new();76
let mut adapter = adapters;77
while let Some(current) = unsafe { adapter.as_ref() } {78
if current.OperStatus == IfOperStatusUp && !excluded_interface_type(current.IfType) {79
let has_gateway = has_usable_ipv4_gateway(current.FirstGatewayAddress);80
let has_physical_address = current.PhysicalAddressLength > 0;81
let mut unicast = current.FirstUnicastAddress;82
while let Some(address) = unsafe { unicast.as_ref() } {83
let dad_rank = if address.DadState == IpDadStatePreferred {84
Some(0)85
} else if address.DadState == IpDadStateDeprecated {86
Some(1)87
} else {88
None89
};90
if let Some(dad_rank) = dad_rank91
&& let Some(ipv4) = socket_address_ipv4(&address.Address)92
&& usable_lan_ipv4(ipv4)93
{94
candidates.push(LanIpv4Candidate {95
address: ipv4,96
interface_type: current.IfType,97
has_gateway,98
has_physical_address,99
dad_rank,100
metric: current.Ipv4Metric,101
});102
}103
unicast = address.Next;104
}105
}106
adapter = current.Next;107
}108
return Ok(select_lan_ipv4(&candidates));109
}110
111
Err("The network adapter list changed repeatedly while it was being read".into())112
}113
114
fn socket_address_ipv4(address: &SOCKET_ADDRESS) -> Option<Ipv4Addr> {115
if address.lpSockaddr.is_null()116
|| address.iSockaddrLength < i32::try_from(size_of::<SOCKADDR_IN>()).unwrap_or(i32::MAX)117
{118
return None;119
}120
let socket = unsafe { &*address.lpSockaddr.cast::<SOCKADDR_IN>() };121
if socket.sin_family != AF_INET {122
return None;123
}124
let octets = unsafe { socket.sin_addr.S_un.S_un_b };125
Some(Ipv4Addr::new(126
octets.s_b1,127
octets.s_b2,128
octets.s_b3,129
octets.s_b4,130
))131
}132
133
fn has_usable_ipv4_gateway(mut gateway: *mut IP_ADAPTER_GATEWAY_ADDRESS_LH) -> bool {134
while let Some(current) = unsafe { gateway.as_ref() } {135
if socket_address_ipv4(¤t.Address).is_some_and(usable_lan_ipv4) {136
return true;137
}138
gateway = current.Next;139
}140
false141
}142
143
fn format_windows_error(context: &str, code: u32) -> String {144
format!(145
"{context}: {}",146
std::io::Error::from_raw_os_error(code as i32)147
)148
}149
150
fn excluded_interface_type(interface_type: u32) -> bool {151
matches!(152
interface_type,153
IF_TYPE_PPP | IF_TYPE_SOFTWARE_LOOPBACK | IF_TYPE_PROP_VIRTUAL | IF_TYPE_TUNNEL154
)155
}156
157
fn physical_interface_rank(interface_type: u32) -> u8 {158
match interface_type {159
IF_TYPE_ETHERNET_CSMACD160
| IF_TYPE_FASTETHER161
| IF_TYPE_FASTETHER_FX162
| IF_TYPE_GIGABITETHERNET163
| IF_TYPE_IEEE80211164
| IF_TYPE_WWANPP165
| IF_TYPE_WWANPP2 => 0,166
_ => 1,167
}168
}169
170
fn usable_lan_ipv4(address: Ipv4Addr) -> bool {171
!address.is_unspecified()172
&& !address.is_loopback()173
&& !address.is_link_local()174
&& !address.is_multicast()175
&& !address.is_broadcast()176
}177
178
fn select_lan_ipv4(candidates: &[LanIpv4Candidate]) -> Option<Ipv4Addr> {179
candidates180
.iter()181
.min_by_key(|candidate| {182
(183
!candidate.has_gateway,184
!candidate.has_physical_address,185
physical_interface_rank(candidate.interface_type),186
candidate.dad_rank,187
candidate.metric,188
candidate.address.octets(),189
)190
})191
.map(|candidate| candidate.address)192
}193
194
#[cfg(test)]195
mod tests {196
use super::*;197
198
const ETHERNET: u32 = IF_TYPE_ETHERNET_CSMACD;199
200
fn candidate(201
address: [u8; 4],202
interface_type: u32,203
has_gateway: bool,204
has_physical_address: bool,205
preferred: bool,206
metric: u32,207
) -> LanIpv4Candidate {208
LanIpv4Candidate {209
address: Ipv4Addr::from(address),210
interface_type,211
has_gateway,212
has_physical_address,213
dad_rank: u8::from(!preferred),214
metric,215
}216
}217
218
#[test]219
fn prefers_a_physical_gateway_over_virtual_or_gatewayless_interfaces() {220
let candidates = [221
candidate(222
[100, 109, 89, 106],223
IF_TYPE_PROP_VIRTUAL,224
true,225
true,226
true,227
1,228
),229
candidate([192, 168, 50, 9], ETHERNET, false, true, true, 5),230
candidate([192, 168, 5, 71], ETHERNET, true, true, true, 25),231
];232
233
assert_eq!(234
select_lan_ipv4(&candidates),235
Some(Ipv4Addr::new(192, 168, 5, 71))236
);237
}238
239
#[test]240
fn metric_breaks_ties_between_physical_gateway_interfaces() {241
let candidates = [242
candidate([192, 168, 1, 20], ETHERNET, true, true, true, 35),243
candidate([192, 168, 5, 71], IF_TYPE_IEEE80211, true, true, true, 10),244
];245
246
assert_eq!(247
select_lan_ipv4(&candidates),248
Some(Ipv4Addr::new(192, 168, 5, 71))249
);250
}251
252
#[test]253
fn preferred_address_wins_over_deprecated_address_on_the_same_adapter() {254
let candidates = [255
candidate([192, 168, 5, 60], ETHERNET, true, true, false, 5),256
candidate([192, 168, 5, 71], ETHERNET, true, true, true, 25),257
];258
259
assert_eq!(260
select_lan_ipv4(&candidates),261
Some(Ipv4Addr::new(192, 168, 5, 71))262
);263
}264
265
#[test]266
fn rejects_non_lan_ipv4_special_ranges() {267
for address in [268
Ipv4Addr::UNSPECIFIED,269
Ipv4Addr::LOCALHOST,270
Ipv4Addr::new(169, 254, 1, 1),271
Ipv4Addr::new(224, 0, 0, 1),272
Ipv4Addr::BROADCAST,273
] {274
assert!(!usable_lan_ipv4(address), "{address}");275
}276
assert!(usable_lan_ipv4(Ipv4Addr::new(192, 168, 5, 71)));277
}278
279
#[test]280
fn live_scan_never_returns_a_filtered_address() {281
if let Some(address) = preferred_lan_ipv4().expect("Windows adapter scan should succeed") {282
println!("preferred LAN IPv4: {address}");283
assert!(usable_lan_ipv4(address));284
}285
}286
}287