144 lines
4.5 KiB
Rust
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)
|
|
}
|
|
}
|