diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index d5a35a325..756603bd5 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -824,6 +824,8 @@ class GeneralModuleTests(unittest.TestCase): # TODO: RUSTPYTHON @unittest.expectedFailure @unittest.skipUnless(_socket is not None, 'need _socket module') + # TODO: RUSTPYTHON gc.is_tracked not implemented + @unittest.expectedFailure def test_socket_type(self): self.assertTrue(gc.is_tracked(_socket.socket)) with self.assertRaisesRegex(TypeError, "immutable"): diff --git a/crates/stdlib/src/socket.rs b/crates/stdlib/src/socket.rs index 1350209a9..aaa28a19c 100644 --- a/crates/stdlib/src/socket.rs +++ b/crates/stdlib/src/socket.rs @@ -226,6 +226,48 @@ mod _socket { #[pyattr] use c::{AF_SYSTEM, PF_SYSTEM, SYSPROTO_CONTROL, TCP_KEEPALIVE}; + // RFC3542 IPv6 socket options for macOS (netinet6/in6.h) + // Not available in libc, define manually + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_RECVHOPLIMIT: i32 = 37; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_RECVRTHDR: i32 = 38; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_RECVHOPOPTS: i32 = 39; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_RECVDSTOPTS: i32 = 40; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_USE_MIN_MTU: i32 = 42; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_RECVPATHMTU: i32 = 43; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_PATHMTU: i32 = 44; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_NEXTHOP: i32 = 48; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_HOPOPTS: i32 = 49; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_DSTOPTS: i32 = 50; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_RTHDR: i32 = 51; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_RTHDRDSTOPTS: i32 = 57; + #[cfg(target_vendor = "apple")] + #[pyattr] + const IPV6_RTHDR_TYPE_0: i32 = 0; + #[cfg(windows)] #[pyattr] use c::{ @@ -491,6 +533,7 @@ mod _socket { target_os = "dragonfly", target_os = "freebsd", target_os = "linux", + target_vendor = "apple", windows ))] #[pyattr] @@ -1597,6 +1640,38 @@ mod _socket { Ok(()) } + #[pymethod] + fn __del__(&self, vm: &VirtualMachine) { + // Emit ResourceWarning if socket is still open + if self.sock.read().is_some() { + let laddr = if let Ok(sock) = self.sock() + && let Ok(addr) = sock.local_addr() + && let Ok(repr) = get_addr_tuple(&addr, vm).repr(vm) + { + format!(", laddr={}", repr.as_str()) + } else { + String::new() + }; + + let msg = format!( + "unclosed ", + self.fileno(), + self.family.load(), + self.kind.load(), + self.proto.load(), + laddr + ); + let _ = crate::vm::warn::warn( + vm.ctx.new_str(msg), + Some(vm.ctx.exceptions.resource_warning.to_owned()), + 1, + None, + vm, + ); + } + let _ = self.close(); + } + #[pymethod] #[inline] fn detach(&self) -> i64 {