From a7c0500a4277902c0f89349c7ee8002038791b83 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" <69878+youknowone@users.noreply.github.com> Date: Sat, 19 Sep 2026 15:18:00 +0900 Subject: [PATCH] host_env: export remaining Windows socket and fault constants (#8736) * host_env: export remaining Windows socket and fault constants Publish AF_HYPERV/AF_BLUETOOTH, HV_* GUIDs, SIO_TCP_SET_ACK_FREQUENCY, EXCEPTION_CONTINUE_SEARCH, and winreg ERROR_FILE_NOT_FOUND/INVALID_DATA. os.socket pack/unpack Hyper-V and RFCOMM addresses through host_env. Assisted-by: Claude * socket: publish HV_GUID_* as string attributes Assisted-by: Claude * host_env: cast SIO_TCP_SET_ACK_FREQUENCY to i32 The WinSock constant is u32 and does not fit i32 without a wrapping cast. Socket module attributes are i32. Assisted-by: Claude * socket: use socklen_t width for Windows SockAddr::new Windows socklen_t is i32; a u32 cast does not match socket2. Assisted-by: Claude * socket: drop unused Windows AF_* imports from c AF_BTH, AF_IRDA, and AF_SNA are published via host_socket pyattr and are not read through the Windows c alias module. Assisted-by: Claude * host_env: export Windows faulthandler exception codes Route stdlib _EXCEPTION_* pyattrs and exception_description through named host_env constants instead of hex literals. Assisted-by: Claude --- crates/host_env/Cargo.toml | 1 + crates/host_env/src/faulthandler.rs | 55 ++++++-- crates/host_env/src/socket.rs | 124 ++++++++++++++++- crates/host_env/src/winreg.rs | 2 + crates/stdlib/src/faulthandler.rs | 19 ++- crates/stdlib/src/socket.rs | 200 ++++++++++++++++++++++++---- 6 files changed, 356 insertions(+), 45 deletions(-) diff --git a/crates/host_env/Cargo.toml b/crates/host_env/Cargo.toml index 407b748c8..133297a3f 100644 --- a/crates/host_env/Cargo.toml +++ b/crates/host_env/Cargo.toml @@ -81,6 +81,7 @@ memchr.workspace = true junction = { workspace = true } schannel = { workspace = true } windows-sys = { workspace = true, features = [ + "Win32_Devices_Bluetooth", "Win32_Foundation", "Win32_Globalization", "Win32_NetworkManagement_IpHelper", diff --git a/crates/host_env/src/faulthandler.rs b/crates/host_env/src/faulthandler.rs index 5b1935916..1e4257a9b 100644 --- a/crates/host_env/src/faulthandler.rs +++ b/crates/host_env/src/faulthandler.rs @@ -490,18 +490,55 @@ pub fn ignore_exception(code: u32) -> bool { #[cfg(windows)] pub fn exception_description(code: u32) -> Option<&'static str> { match code { - 0xC0000005 => Some("access violation"), - 0xC000008C => Some("float divide by zero"), - 0xC0000091 => Some("float overflow"), - 0xC0000094 => Some("int divide by zero"), - 0xC0000095 => Some("integer overflow"), - 0xC0000006 => Some("page error"), - 0xC00000FD => Some("stack overflow"), - 0xC000001D => Some("illegal instruction"), + EXCEPTION_ACCESS_VIOLATION => Some("access violation"), + EXCEPTION_FLT_DIVIDE_BY_ZERO => Some("float divide by zero"), + EXCEPTION_FLT_OVERFLOW => Some("float overflow"), + EXCEPTION_INT_DIVIDE_BY_ZERO => Some("int divide by zero"), + EXCEPTION_INT_OVERFLOW => Some("integer overflow"), + EXCEPTION_IN_PAGE_ERROR => Some("page error"), + EXCEPTION_STACK_OVERFLOW => Some("stack overflow"), + EXCEPTION_ILLEGAL_INSTRUCTION => Some("illegal instruction"), _ => None, } } +/// `EXCEPTION_CONTINUE_SEARCH`: this handler only reports; later +/// handlers decide the process fate. +#[cfg(windows)] +pub const EXCEPTION_CONTINUE_SEARCH: i32 = + windows_sys::Win32::System::Diagnostics::Debug::EXCEPTION_CONTINUE_SEARCH; + +#[cfg(windows)] +pub const EXCEPTION_ACCESS_VIOLATION: u32 = + windows_sys::Win32::Foundation::EXCEPTION_ACCESS_VIOLATION as u32; +#[cfg(windows)] +pub const EXCEPTION_FLT_DIVIDE_BY_ZERO: u32 = + windows_sys::Win32::Foundation::EXCEPTION_FLT_DIVIDE_BY_ZERO as u32; +#[cfg(windows)] +pub const EXCEPTION_FLT_OVERFLOW: u32 = + windows_sys::Win32::Foundation::EXCEPTION_FLT_OVERFLOW as u32; +#[cfg(windows)] +pub const EXCEPTION_INT_DIVIDE_BY_ZERO: u32 = + windows_sys::Win32::Foundation::EXCEPTION_INT_DIVIDE_BY_ZERO as u32; +#[cfg(windows)] +pub const EXCEPTION_INT_OVERFLOW: u32 = + windows_sys::Win32::Foundation::EXCEPTION_INT_OVERFLOW as u32; +#[cfg(windows)] +pub const EXCEPTION_IN_PAGE_ERROR: u32 = + windows_sys::Win32::Foundation::EXCEPTION_IN_PAGE_ERROR as u32; +#[cfg(windows)] +pub const EXCEPTION_STACK_OVERFLOW: u32 = + windows_sys::Win32::Foundation::EXCEPTION_STACK_OVERFLOW as u32; +#[cfg(windows)] +pub const EXCEPTION_ILLEGAL_INSTRUCTION: u32 = + windows_sys::Win32::Foundation::EXCEPTION_ILLEGAL_INSTRUCTION as u32; +#[cfg(windows)] +pub const EXCEPTION_NONCONTINUABLE: u32 = + windows_sys::Win32::System::SystemServices::EXCEPTION_NONCONTINUABLE; +#[cfg(windows)] +pub const EXCEPTION_NONCONTINUABLE_EXCEPTION: u32 = + windows_sys::Win32::Foundation::EXCEPTION_NONCONTINUABLE_EXCEPTION as u32; + #[cfg(windows)] pub unsafe fn exception_code(exc_info: *mut EXCEPTION_POINTERS) -> u32 { let record = unsafe { &*(*exc_info).ExceptionRecord }; @@ -511,5 +548,5 @@ pub unsafe fn exception_code(exc_info: *mut EXCEPTION_POINTERS) -> u32 { #[cfg(windows)] #[inline] pub fn is_access_violation(code: u32) -> bool { - code == 0xC0000005 + code == EXCEPTION_ACCESS_VIOLATION } diff --git a/crates/host_env/src/socket.rs b/crates/host_env/src/socket.rs index aee53261c..c6b091dda 100644 --- a/crates/host_env/src/socket.rs +++ b/crates/host_env/src/socket.rs @@ -571,8 +571,8 @@ pub use windows_sys::Win32::Networking::WinSock::{ SIO_LOOPBACK_FAST_PATH, SIO_RCVALL, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_REUSEADDR, SO_SNDBUF, SO_TYPE, SO_USELOOPBACK, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET, SOCK_STREAM, SOCKET_ERROR as SOCKET_ERROR_CODE, SOL_SOCKET, - SOMAXCONN, TCP_NODELAY, WSAEBADF, WSAECONNRESET, WSAENOTSOCK, WSAEWOULDBLOCK, getprotobyname, - getservbyname, getservbyport, getsockopt, setsockopt, + SOMAXCONN, TCP_NODELAY, WSAEBADF, WSAECONNABORTED, WSAECONNRESET, WSAENOTSOCK, WSAEWOULDBLOCK, + getprotobyname, getservbyname, getservbyport, getsockopt, setsockopt, }; #[cfg(windows)] @@ -953,3 +953,123 @@ pub fn uuid_to_string_w(guid: &windows_sys::core::GUID) -> Result { unsafe { RpcStringFreeW(&mut raw) }; Ok(text) } + +/// Address families the Windows SDK exposes beyond the older MSVC census. +#[cfg(windows)] +pub const AF_SNA: i32 = 11; +#[cfg(windows)] +pub const AF_IRDA: i32 = 26; +#[cfg(windows)] +pub const AF_HYPERV: i32 = windows_sys::Win32::Networking::WinSock::AF_HYPERV as i32; +#[cfg(windows)] +pub const AF_BLUETOOTH: i32 = windows_sys::Win32::Devices::Bluetooth::AF_BTH as i32; +#[cfg(windows)] +pub const AF_BTH: i32 = AF_BLUETOOTH; +#[cfg(windows)] +pub const BTHPROTO_RFCOMM: i32 = windows_sys::Win32::Devices::Bluetooth::BTHPROTO_RFCOMM as i32; + +/// `hvsocket.h`: the only protocol an `AF_HYPERV` socket is opened with. +#[cfg(windows)] +pub const HV_PROTOCOL_RAW: i32 = 1; +#[cfg(windows)] +pub const HVSOCKET_CONNECT_TIMEOUT: i32 = 0x01; +#[cfg(windows)] +pub const HVSOCKET_CONNECT_TIMEOUT_MAX: i32 = 300_000; +#[cfg(windows)] +pub const HVSOCKET_CONNECTED_SUSPEND: i32 = 0x04; +#[cfg(windows)] +pub const HVSOCKET_ADDRESS_FLAG_PASSTHRU: i32 = 0x01; +#[cfg(windows)] +pub const HV_GUID_ZERO: &str = "00000000-0000-0000-0000-000000000000"; +#[cfg(windows)] +pub const HV_GUID_WILDCARD: &str = "00000000-0000-0000-0000-000000000000"; +#[cfg(windows)] +pub const HV_GUID_BROADCAST: &str = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"; +#[cfg(windows)] +pub const HV_GUID_CHILDREN: &str = "90DB8B89-0D35-4F79-8CE9-49EA0AC8B7CD"; +#[cfg(windows)] +pub const HV_GUID_LOOPBACK: &str = "E0E16197-DD56-4A10-9195-5EE7A155A838"; +#[cfg(windows)] +pub const HV_GUID_PARENT: &str = "A42E7CDA-D03F-480C-9CC2-A4DE20ABB878"; + +#[cfg(windows)] +pub const SIO_TCP_SET_ACK_FREQUENCY: i32 = + windows_sys::Win32::Networking::WinSock::SIO_TCP_SET_ACK_FREQUENCY as i32; + +/// `SOCKADDR_HV` (`hvsocket.h`). +#[cfg(windows)] +#[repr(C)] +#[derive(Clone, Copy)] +pub struct SockaddrHv { + pub family: u16, + pub reserved: u16, + pub vm_id: windows_sys::core::GUID, + pub service_id: windows_sys::core::GUID, +} + +#[cfg(windows)] +pub fn sockaddr_hv( + vm_id: windows_sys::core::GUID, + service_id: windows_sys::core::GUID, +) -> SockaddrHv { + SockaddrHv { + family: AF_HYPERV as u16, + reserved: 0, + vm_id, + service_id, + } +} + +/// `SOCKADDR_BTH`. +#[cfg(windows)] +pub fn sockaddr_bth_rfcomm( + bd_addr: u64, + port: u32, +) -> windows_sys::Win32::Devices::Bluetooth::SOCKADDR_BTH { + windows_sys::Win32::Devices::Bluetooth::SOCKADDR_BTH { + addressFamily: AF_BTH as u16, + btAddr: bd_addr, + serviceClassId: Default::default(), + port, + } +} + +#[cfg(windows)] +pub fn unpack_sockaddr_bth(ptr: *const u8) -> (u64, u32) { + let bth = unsafe { &*(ptr.cast::()) }; + (bth.btAddr, bth.port) +} + +/// `setbdaddr`: six hex octets separated by `:`. +#[cfg(windows)] +pub fn parse_bdaddr(name: &str) -> Option { + let mut parts = name.split(':'); + let mut value = 0u64; + for _ in 0..6 { + let part = parts.next()?; + if part.is_empty() || part.len() > 2 { + return None; + } + let octet = u8::from_str_radix(part, 16).ok()?; + value = (value << 8) | u64::from(octet); + } + if parts.next().is_some() { + return None; + } + Some(value) +} + +/// `makebdaddr`: `XX:XX:XX:XX:XX:XX`, most significant octet first. +#[cfg(windows)] +pub fn format_bdaddr(bdaddr: u64) -> String { + let octet = |i: u32| (bdaddr >> (8 * i)) & 0xFF; + alloc::format!( + "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", + octet(5), + octet(4), + octet(3), + octet(2), + octet(1), + octet(0) + ) +} diff --git a/crates/host_env/src/winreg.rs b/crates/host_env/src/winreg.rs index a8bc56b14..6678b7b68 100644 --- a/crates/host_env/src/winreg.rs +++ b/crates/host_env/src/winreg.rs @@ -24,6 +24,8 @@ use windows_sys::Win32::{ pub type HKEY = Registry::HKEY; pub const ERROR_MORE_DATA: u32 = Foundation::ERROR_MORE_DATA; pub const ERROR_INVALID_HANDLE: u32 = Foundation::ERROR_INVALID_HANDLE; +pub const ERROR_FILE_NOT_FOUND: u32 = Foundation::ERROR_FILE_NOT_FOUND; +pub const ERROR_INVALID_DATA: u32 = Foundation::ERROR_INVALID_DATA; pub const HKEY_CLASSES_ROOT: HKEY = Registry::HKEY_CLASSES_ROOT; pub const HKEY_CURRENT_USER: HKEY = Registry::HKEY_CURRENT_USER; pub const HKEY_LOCAL_MACHINE: HKEY = Registry::HKEY_LOCAL_MACHINE; diff --git a/crates/stdlib/src/faulthandler.rs b/crates/stdlib/src/faulthandler.rs index 3fbb8391b..bf79cc74b 100644 --- a/crates/stdlib/src/faulthandler.rs +++ b/crates/stdlib/src/faulthandler.rs @@ -467,16 +467,14 @@ mod decl { unsafe extern "system" fn faulthandler_exc_handler( exc_info: *mut host_faulthandler::ExceptionPointers, ) -> i32 { - const EXCEPTION_CONTINUE_SEARCH: i32 = 0; - if !FATAL_ERROR.enabled.load(Ordering::Relaxed) { - return EXCEPTION_CONTINUE_SEARCH; + return host_faulthandler::EXCEPTION_CONTINUE_SEARCH; } let code = unsafe { host_faulthandler::exception_code(exc_info) }; if faulthandler_ignore_exception(code) { - return EXCEPTION_CONTINUE_SEARCH; + return host_faulthandler::EXCEPTION_CONTINUE_SEARCH; } let fd = FATAL_ERROR.fd.load(Ordering::Relaxed); @@ -498,7 +496,7 @@ mod decl { let all_threads = FATAL_ERROR.all_threads.load(Ordering::Relaxed); faulthandler_dump_traceback(fd, all_threads); - EXCEPTION_CONTINUE_SEARCH + host_faulthandler::EXCEPTION_CONTINUE_SEARCH } // faulthandler_enable @@ -1005,23 +1003,24 @@ mod decl { // Windows-specific constants #[cfg(windows)] #[pyattr] - const _EXCEPTION_ACCESS_VIOLATION: u32 = 0xC0000005; + const _EXCEPTION_ACCESS_VIOLATION: u32 = host_faulthandler::EXCEPTION_ACCESS_VIOLATION; #[cfg(windows)] #[pyattr] - const _EXCEPTION_INT_DIVIDE_BY_ZERO: u32 = 0xC0000094; + const _EXCEPTION_INT_DIVIDE_BY_ZERO: u32 = host_faulthandler::EXCEPTION_INT_DIVIDE_BY_ZERO; #[cfg(windows)] #[pyattr] - const _EXCEPTION_STACK_OVERFLOW: u32 = 0xC00000FD; + const _EXCEPTION_STACK_OVERFLOW: u32 = host_faulthandler::EXCEPTION_STACK_OVERFLOW; #[cfg(windows)] #[pyattr] - const _EXCEPTION_NONCONTINUABLE: u32 = 0x00000001; + const _EXCEPTION_NONCONTINUABLE: u32 = host_faulthandler::EXCEPTION_NONCONTINUABLE; #[cfg(windows)] #[pyattr] - const _EXCEPTION_NONCONTINUABLE_EXCEPTION: u32 = 0xC0000025; + const _EXCEPTION_NONCONTINUABLE_EXCEPTION: u32 = + host_faulthandler::EXCEPTION_NONCONTINUABLE_EXCEPTION; #[cfg(windows)] #[derive(FromArgs)] diff --git a/crates/stdlib/src/socket.rs b/crates/stdlib/src/socket.rs index ce0275d37..34092607c 100644 --- a/crates/stdlib/src/socket.rs +++ b/crates/stdlib/src/socket.rs @@ -32,6 +32,8 @@ mod _socket { use rustpython_host_env::socket as host_socket; #[cfg(windows)] use rustpython_host_env::windows as host_windows; + #[cfg(windows)] + use rustpython_host_env::windows::ToWideString; #[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")] pub(crate) fn module_exec(vm: &VirtualMachine, module: &Py) -> PyResult<()> { @@ -61,28 +63,28 @@ mod _socket { #[cfg(windows)] mod c { pub(super) use rustpython_host_env::socket::{ - AF_APPLETALK, AF_DECnet, AF_INET, AF_INET6, AF_IPX, AF_LINK, AF_UNSPEC, AI_ADDRCONFIG, - AI_ALL, AI_CANONNAME, AI_NUMERICHOST, AI_NUMERICSERV, AI_PASSIVE, AI_V4MAPPED, - EAI_AGAIN, EAI_BADFLAGS, EAI_FAIL, EAI_FAMILY, EAI_MEMORY, EAI_NODATA, EAI_NONAME, - EAI_SERVICE, EAI_SOCKTYPE, INADDR_ANY, INADDR_BROADCAST, INADDR_LOOPBACK, INADDR_NONE, - IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_HDRINCL, IP_MULTICAST_IF, IP_MULTICAST_LOOP, - IP_MULTICAST_TTL, IP_OPTIONS, IP_RECVDSTADDR, IP_TOS, IP_TTL, IPPORT_RESERVED, - IPPROTO_AH, IPPROTO_DSTOPTS, IPPROTO_EGP, IPPROTO_ESP, IPPROTO_FRAGMENT, IPPROTO_GGP, - IPPROTO_HOPOPTS, IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_IDP, IPPROTO_IGMP, IPPROTO_IP, - IPPROTO_IP as IPPROTO_IPIP, IPPROTO_IPV4, IPPROTO_IPV6, IPPROTO_ND, IPPROTO_NONE, - IPPROTO_PIM, IPPROTO_PUP, IPPROTO_RAW, IPPROTO_ROUTING, IPPROTO_TCP, IPPROTO_UDP, - IPV6_CHECKSUM, IPV6_DONTFRAG, IPV6_HOPLIMIT, IPV6_HOPOPTS, IPV6_JOIN_GROUP, - IPV6_LEAVE_GROUP, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, - IPV6_PKTINFO, IPV6_RECVRTHDR, IPV6_RECVTCLASS, IPV6_RTHDR, IPV6_TCLASS, - IPV6_UNICAST_HOPS, IPV6_V6ONLY, MSG_BCAST, MSG_CTRUNC, MSG_DONTROUTE, MSG_MCAST, - MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL, NI_DGRAM, NI_MAXHOST, NI_MAXSERV, - NI_NAMEREQD, NI_NOFQDN, NI_NUMERICHOST, NI_NUMERICSERV, RCVALL_IPLEVEL, RCVALL_OFF, - RCVALL_ON, RCVALL_SOCKETLEVELONLY, SD_BOTH as SHUT_RDWR, SD_RECEIVE as SHUT_RD, - SD_SEND as SHUT_WR, SIO_KEEPALIVE_VALS, SIO_LOOPBACK_FAST_PATH, SIO_RCVALL, - SO_BROADCAST, SO_ERROR, SO_EXCLUSIVEADDRUSE, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, - SO_RCVBUF, SO_REUSEADDR, SO_SNDBUF, SO_TYPE, SO_USELOOPBACK, SOCK_DGRAM, SOCK_RAW, - SOCK_RDM, SOCK_SEQPACKET, SOCK_STREAM, SOL_SOCKET, SOMAXCONN, TCP_NODELAY, WSAEBADF, - WSAENOTSOCK, WSAEWOULDBLOCK, getprotobyname, getservbyname, getservbyport, + AF_APPLETALK, AF_BLUETOOTH, AF_DECnet, AF_HYPERV, AF_INET, AF_INET6, AF_IPX, AF_LINK, + AF_UNSPEC, AI_ADDRCONFIG, AI_ALL, AI_CANONNAME, AI_NUMERICHOST, AI_NUMERICSERV, + AI_PASSIVE, AI_V4MAPPED, EAI_AGAIN, EAI_BADFLAGS, EAI_FAIL, EAI_FAMILY, EAI_MEMORY, + EAI_NODATA, EAI_NONAME, EAI_SERVICE, EAI_SOCKTYPE, INADDR_ANY, INADDR_BROADCAST, + INADDR_LOOPBACK, INADDR_NONE, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_HDRINCL, + IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_OPTIONS, IP_RECVDSTADDR, + IP_TOS, IP_TTL, IPPORT_RESERVED, IPPROTO_AH, IPPROTO_DSTOPTS, IPPROTO_EGP, IPPROTO_ESP, + IPPROTO_FRAGMENT, IPPROTO_GGP, IPPROTO_HOPOPTS, IPPROTO_ICMP, IPPROTO_ICMPV6, + IPPROTO_IDP, IPPROTO_IGMP, IPPROTO_IP, IPPROTO_IP as IPPROTO_IPIP, IPPROTO_IPV4, + IPPROTO_IPV6, IPPROTO_ND, IPPROTO_NONE, IPPROTO_PIM, IPPROTO_PUP, IPPROTO_RAW, + IPPROTO_ROUTING, IPPROTO_TCP, IPPROTO_UDP, IPV6_CHECKSUM, IPV6_DONTFRAG, IPV6_HOPLIMIT, + IPV6_HOPOPTS, IPV6_JOIN_GROUP, IPV6_LEAVE_GROUP, IPV6_MULTICAST_HOPS, + IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_PKTINFO, IPV6_RECVRTHDR, IPV6_RECVTCLASS, + IPV6_RTHDR, IPV6_TCLASS, IPV6_UNICAST_HOPS, IPV6_V6ONLY, MSG_BCAST, MSG_CTRUNC, + MSG_DONTROUTE, MSG_MCAST, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL, NI_DGRAM, + NI_MAXHOST, NI_MAXSERV, NI_NAMEREQD, NI_NOFQDN, NI_NUMERICHOST, NI_NUMERICSERV, + RCVALL_IPLEVEL, RCVALL_OFF, RCVALL_ON, RCVALL_SOCKETLEVELONLY, SD_BOTH as SHUT_RDWR, + SD_RECEIVE as SHUT_RD, SD_SEND as SHUT_WR, SIO_KEEPALIVE_VALS, SIO_LOOPBACK_FAST_PATH, + SIO_RCVALL, SO_BROADCAST, SO_ERROR, SO_EXCLUSIVEADDRUSE, SO_KEEPALIVE, SO_LINGER, + SO_OOBINLINE, SO_RCVBUF, SO_REUSEADDR, SO_SNDBUF, SO_TYPE, SO_USELOOPBACK, SOCK_DGRAM, + SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET, SOCK_STREAM, SOL_SOCKET, SOMAXCONN, TCP_NODELAY, + WSAEBADF, WSAENOTSOCK, WSAEWOULDBLOCK, getprotobyname, getservbyname, getservbyport, }; } // constants @@ -823,10 +825,31 @@ mod _socket { #[cfg(windows)] #[pyattr] use host_socket::{ - IPPROTO_CBT, IPPROTO_ICLFXBM, IPPROTO_IGP, IPPROTO_L2TP, IPPROTO_PGM, IPPROTO_RDP, - IPPROTO_SCTP, IPPROTO_ST, + AF_BLUETOOTH, AF_HYPERV, AF_IRDA, AF_SNA, BTHPROTO_RFCOMM, HV_PROTOCOL_RAW, + HVSOCKET_ADDRESS_FLAG_PASSTHRU, HVSOCKET_CONNECT_TIMEOUT, HVSOCKET_CONNECT_TIMEOUT_MAX, + HVSOCKET_CONNECTED_SUSPEND, IPPROTO_CBT, IPPROTO_ICLFXBM, IPPROTO_IGP, IPPROTO_L2TP, + IPPROTO_PGM, IPPROTO_RDP, IPPROTO_SCTP, IPPROTO_ST, SIO_TCP_SET_ACK_FREQUENCY, }; + #[cfg(windows)] + #[pyattr] + const HV_GUID_ZERO: &str = host_socket::HV_GUID_ZERO; + #[cfg(windows)] + #[pyattr] + const HV_GUID_WILDCARD: &str = host_socket::HV_GUID_WILDCARD; + #[cfg(windows)] + #[pyattr] + const HV_GUID_BROADCAST: &str = host_socket::HV_GUID_BROADCAST; + #[cfg(windows)] + #[pyattr] + const HV_GUID_CHILDREN: &str = host_socket::HV_GUID_CHILDREN; + #[cfg(windows)] + #[pyattr] + const HV_GUID_LOOPBACK: &str = host_socket::HV_GUID_LOOPBACK; + #[cfg(windows)] + #[pyattr] + const HV_GUID_PARENT: &str = host_socket::HV_GUID_PARENT; + #[pyattr] fn error(vm: &VirtualMachine) -> PyTypeRef { vm.ctx.exceptions.os_error.to_owned() @@ -1184,6 +1207,108 @@ mod _socket { } Ok(addr6.into()) } + #[cfg(windows)] + family if family == c::AF_HYPERV => { + if self.proto.load() != host_socket::HV_PROTOCOL_RAW { + return Err(vm + .new_os_error(format!( + "{caller}(): unsupported AF_HYPERV protocol: {}", + self.proto.load() + )) + .into()); + } + let tuple: PyTupleRef = addr.downcast().map_err(|obj| { + vm.new_type_error(format!( + "{caller}(): AF_HYPERV address must be tuple, not {}", + obj.class().name() + )) + })?; + if tuple.len() != 2 { + return Err(vm + .new_type_error( + "AF_HYPERV address must be a str tuple (vm_id, service_id)", + ) + .into()); + } + let vm_id: PyStrRef = tuple[0].clone().downcast().map_err(|_| { + vm.new_type_error( + "AF_HYPERV address must be a str tuple (vm_id, service_id)", + ) + })?; + let service_id: PyStrRef = tuple[1].clone().downcast().map_err(|_| { + vm.new_type_error( + "AF_HYPERV address must be a str tuple (vm_id, service_id)", + ) + })?; + let vm_wide = vm_id.as_wtf8().to_wide_cstring().map_err(|_| { + vm.new_value_error(format!( + "{caller}(): AF_HYPERV address vm_id is not a valid UUID string" + )) + })?; + let service_wide = service_id.as_wtf8().to_wide_cstring().map_err(|_| { + vm.new_value_error(format!( + "{caller}(): AF_HYPERV address service_id is not a valid UUID string" + )) + })?; + let vm_guid = host_socket::uuid_from_string_w(&vm_wide).map_err(|_| { + vm.new_value_error(format!( + "{caller}(): AF_HYPERV address vm_id is not a valid UUID string" + )) + })?; + let service_guid = + host_socket::uuid_from_string_w(&service_wide).map_err(|_| { + vm.new_value_error(format!( + "{caller}(): AF_HYPERV address service_id is not a valid UUID string" + )) + })?; + let hv = host_socket::sockaddr_hv(vm_guid, service_guid); + let mut storage: host_socket::raw::SockAddrStorage = + unsafe { core::mem::zeroed() }; + unsafe { + core::ptr::write(core::ptr::from_mut(&mut storage).cast(), hv); + } + Ok(unsafe { + host_socket::raw::SockAddr::new(storage, core::mem::size_of_val(&hv) as _) + }) + } + #[cfg(windows)] + family if family == c::AF_BLUETOOTH => { + if self.proto.load() != host_socket::BTHPROTO_RFCOMM { + return Err(vm + .new_os_error(format!("{caller}(): unknown Bluetooth protocol")) + .into()); + } + let tuple: PyTupleRef = addr + .downcast() + .map_err(|_| vm.new_os_error(format!("{caller}(): wrong format")))?; + if tuple.len() != 2 { + return Err(vm.new_os_error(format!("{caller}(): wrong format")).into()); + } + let name: PyStrRef = tuple[0] + .clone() + .downcast() + .map_err(|_| vm.new_os_error(format!("{caller}(): wrong format")))?; + let channel = i64::try_from_object(vm, tuple[1].clone()) + .map_err(|_| vm.new_os_error(format!("{caller}(): wrong format")))?; + let name = name + .try_into_utf8(vm) + .map_err(|_| vm.new_os_error(format!("{caller}(): wrong format")))?; + let name = name.as_str(); + if name.contains('\0') { + return Err(vm.new_os_error(format!("{caller}(): wrong format")).into()); + } + let bd_addr = host_socket::parse_bdaddr(name) + .ok_or_else(|| vm.new_os_error("bad bluetooth address"))?; + let bth = host_socket::sockaddr_bth_rfcomm(bd_addr, channel as u32); + let mut storage: host_socket::raw::SockAddrStorage = + unsafe { core::mem::zeroed() }; + unsafe { + core::ptr::write(core::ptr::from_mut(&mut storage).cast(), bth); + } + Ok(unsafe { + host_socket::raw::SockAddr::new(storage, core::mem::size_of_val(&bth) as _) + }) + } #[cfg(target_os = "linux")] c::AF_CAN => { let tuple: PyTupleRef = addr.downcast().map_err(|obj| { @@ -2316,6 +2441,33 @@ mod _socket { .into(); } } + #[cfg(windows)] + { + let family = addr.family() as i32; + if family == c::AF_HYPERV { + let hv = unsafe { &*(addr.as_ptr() as *const host_socket::SockaddrHv) }; + let vm_id = host_socket::uuid_to_string_w(&hv.vm_id).unwrap_or_default(); + let service_id = host_socket::uuid_to_string_w(&hv.service_id).unwrap_or_default(); + return vm + .ctx + .new_tuple(vec![ + vm.ctx.new_str(vm_id).into(), + vm.ctx.new_str(service_id).into(), + ]) + .into(); + } + if family == c::AF_BLUETOOTH { + let (bd_addr, port) = host_socket::unpack_sockaddr_bth(addr.as_ptr().cast()); + let name = host_socket::format_bdaddr(bd_addr); + return vm + .ctx + .new_tuple(vec![ + vm.ctx.new_str(name).into(), + vm.ctx.new_int(port).into(), + ]) + .into(); + } + } // TODO: support more address families (String::new(), 0).to_pyobject(vm) }