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
This commit is contained in:
Jeong, YunWon authored and GitHub committed 2026-09-19 15:18:00 +09:00
1 parent 0c5a47bae5
commit a7c0500a42
6 files changed
+356 -45

No files matched your search

+1
View File
@@ -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",
+46 -9
View File
@@ -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
}
+122 -2
View File
@@ -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<String, u32> {
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::<windows_sys::Win32::Devices::Bluetooth::SOCKADDR_BTH>()) };
(bth.btAddr, bth.port)
}
/// `setbdaddr`: six hex octets separated by `:`.
#[cfg(windows)]
pub fn parse_bdaddr(name: &str) -> Option<u64> {
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)
)
}
+2
View File
@@ -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;
+9 -10
View File
@@ -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)]
+176 -24
View File
@@ -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<PyModule>) -> 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)
}