networks-2.rs/network/windows/src/address.rs
2026-03-10 17:10:14 +03:00

144 lines
4.5 KiB
Rust

use bgtu_networks_2_network_abstract::Address;
use crate::errors::{format_windows_err_code_result, throw_from_windows_err_code};
use std::ffi::OsString;
use std::hash::{Hash, Hasher};
use std::mem::size_of;
use std::mem::zeroed;
use std::os::windows::ffi::OsStringExt;
use std::ptr;
use std::ptr::{copy_nonoverlapping, null, null_mut};
use windows::Win32::Networking::WinSock::{
ADDRINFOW, AF_INET, AF_INET6, AF_UNSPEC, FreeAddrInfoW, GetAddrInfoW, SOCKADDR_IN,
SOCKADDR_IN6, SOCKADDR_STORAGE, WSAAddressToStringW, WSAGetLastError,
};
use windows::core::{PCWSTR, PWSTR};
#[derive(Clone, Copy)]
pub struct WindowsAddressAny {
pub(super) native: SOCKADDR_STORAGE,
}
impl Address for WindowsAddressAny {
fn parse(raw: &str) -> Result<Self, String> {
let mut encoded = raw.encode_utf16().collect::<Vec<_>>();
encoded.push(0);
unsafe {
let mut p = null_mut::<ADDRINFOW>();
if (0
!= GetAddrInfoW(
PCWSTR(encoded.as_slice().as_ptr()),
PCWSTR(null()),
None,
&mut p,
))
{
format_windows_err_code_result(WSAGetLastError())?;
}
let mut this = Self { native: zeroed() };
copy_nonoverlapping::<u8>((*p).ai_addr.cast(), ((&mut this.native) as *mut SOCKADDR_STORAGE).cast(), (*p).ai_addrlen);
FreeAddrInfoW(Some(p));
return Result::Ok(this);
}
}
fn to_string(&self) -> String {
let mut buffer = [0u16; 1024];
let mut buf_size = buffer.len() as u32;
unsafe {
if 0 != WSAAddressToStringW(
ptr::from_ref(&self.native).cast(),
size_of::<SOCKADDR_STORAGE>() as u32,
None,
PWSTR(buffer.as_mut_ptr()),
&mut buf_size,
) {
throw_from_windows_err_code(WSAGetLastError());
}
}
return OsString::from_wide(&buffer).to_string_lossy().into_owned();
}
}
impl PartialEq for WindowsAddressAny {
fn eq(&self, other: &Self) -> bool {
match self.native.ss_family {
AF_INET => {
if other.native.ss_family != AF_INET {
return false;
}
unsafe {
let self_4 = *ptr::from_ref(&self.native).cast::<SOCKADDR_IN>();
let other_4 = *ptr::from_ref(&other.native).cast::<SOCKADDR_IN>();
return self_4.sin_addr.S_un.S_addr == other_4.sin_addr.S_un.S_addr;
}
}
AF_INET6 => unsafe {
let self_6 = *ptr::from_ref(&self.native).cast::<SOCKADDR_IN6>();
let other_6 = *ptr::from_ref(&other.native).cast::<SOCKADDR_IN6>();
return self_6.sin6_addr.u.Word == other_6.sin6_addr.u.Word;
},
_ => return false,
}
}
}
impl Hash for WindowsAddressAny {
fn hash<H: Hasher>(&self, state: &mut H) {
match self.native.ss_family {
AF_INET => {
state.write_u16(self.native.ss_family.0);
unsafe {
let self_4 = *ptr::from_ref(&self.native).cast::<SOCKADDR_IN>();
state.write_u32(self_4.sin_addr.S_un.S_addr);
}
}
AF_INET6 => {
state.write_u16(self.native.ss_family.0);
unsafe {
let self_6 = *ptr::from_ref(&self.native).cast::<SOCKADDR_IN6>();
state.write(&self_6.sin6_addr.u.Byte);
}
}
_ => state.write_u16(AF_UNSPEC.0),
}
}
}
#[derive(Clone, Copy)]
pub struct WindowsAddressKnown {
pub(super) any: WindowsAddressAny,
}
impl Address for WindowsAddressKnown {
fn parse(raw: &str) -> Result<Self, String> {
let any = WindowsAddressAny::parse(raw)?;
match any.native.ss_family {
AF_INET | AF_INET6 => return Result::Ok(Self { any }),
_ => return Result::Err("Address resolved to unsupported AF".to_owned()),
}
}
fn to_string(&self) -> String {
return self.any.to_string();
}
}
impl PartialEq for WindowsAddressKnown {
fn eq(&self, other: &Self) -> bool {
return self.any == other.any;
}
}
impl Eq for WindowsAddressKnown {}
impl Hash for WindowsAddressKnown {
fn hash<H: Hasher>(&self, state: &mut H) {
self.any.hash(state)
}
}