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 { let mut encoded = raw.encode_utf16().collect::>(); encoded.push(0); unsafe { let mut p = null_mut::(); 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::((*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::() 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::(); let other_4 = *ptr::from_ref(&other.native).cast::(); 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::(); let other_6 = *ptr::from_ref(&other.native).cast::(); return self_6.sin6_addr.u.Word == other_6.sin6_addr.u.Word; }, _ => return false, } } } impl Hash for WindowsAddressAny { fn hash(&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::(); 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::(); 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 { 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(&self, state: &mut H) { self.any.hash(state) } }