1pub(crate) use _socket::module_def;
4
5#[cfg(feature = "ssl")]
6pub(super) use _socket::{PySocket, SelectKind, sock_select, timeout_error_msg};
7
8#[pymodule]
9mod _socket {
10 use crate::common::lock::{PyMappedRwLockReadGuard, PyRwLock, PyRwLockReadGuard};
11 use crate::vm::{
12 AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
13 builtins::{
14 PyBaseExceptionRef, PyListRef, PyModule, PyOSError, PyStrRef, PyTupleRef, PyTypeRef,
15 PyUtf8StrRef,
16 },
17 common::os::ErrorExt,
18 convert::{IntoPyException, ToPyObject, TryFromBorrowedObject, TryFromObject},
19 function::{
20 ArgBytesLike, ArgIntoFloat, ArgMemoryBuffer, ArgStrOrBytesLike, Either, FsPath,
21 OptionalArg, OptionalOption,
22 },
23 types::{Constructor, DefaultConstructor, Destructor, Initializer, Representable},
24 utils::ToCString,
25 };
26
27 pub(crate) fn module_exec(vm: &VirtualMachine, module: &Py<PyModule>) -> PyResult<()> {
28 #[cfg(windows)]
29 crate::vm::windows::init_winsock();
30
31 __module_exec(vm, module);
32 Ok(())
33 }
34 use core::{
35 mem::MaybeUninit,
36 net::{Ipv4Addr, Ipv6Addr, SocketAddr},
37 time::Duration,
38 };
39 use crossbeam_utils::atomic::AtomicCell;
40 use num_traits::ToPrimitive;
41 use socket2::Socket;
42 use std::{
43 ffi,
44 io::{self, Read, Write},
45 net::{self, Shutdown, ToSocketAddrs},
46 time::Instant,
47 };
48
49 #[cfg(unix)]
50 use libc as c;
51 #[cfg(windows)]
52 mod c {
53 pub use windows_sys::Win32::NetworkManagement::IpHelper::{if_indextoname, if_nametoindex};
54 pub use windows_sys::Win32::Networking::WinSock::{
55 INADDR_ANY, INADDR_BROADCAST, INADDR_LOOPBACK, INADDR_NONE,
56 };
57
58 pub use windows_sys::Win32::Networking::WinSock::{
59 AF_APPLETALK, AF_DECnet, AF_IPX, AF_LINK, AI_ADDRCONFIG, AI_ALL, AI_CANONNAME,
60 AI_NUMERICSERV, AI_V4MAPPED, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_HDRINCL,
61 IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_OPTIONS, IP_RECVDSTADDR,
62 IP_TOS, IP_TTL, IPPORT_RESERVED, IPPROTO_AH, IPPROTO_DSTOPTS, IPPROTO_EGP, IPPROTO_ESP,
63 IPPROTO_FRAGMENT, IPPROTO_GGP, IPPROTO_HOPOPTS, IPPROTO_ICMP, IPPROTO_ICMPV6,
64 IPPROTO_IDP, IPPROTO_IGMP, IPPROTO_IP, IPPROTO_IP as IPPROTO_IPIP, IPPROTO_IPV4,
65 IPPROTO_IPV6, IPPROTO_ND, IPPROTO_NONE, IPPROTO_PIM, IPPROTO_PUP, IPPROTO_RAW,
66 IPPROTO_ROUTING, IPPROTO_TCP, IPPROTO_UDP, IPV6_CHECKSUM, IPV6_DONTFRAG, IPV6_HOPLIMIT,
67 IPV6_HOPOPTS, IPV6_JOIN_GROUP, IPV6_LEAVE_GROUP, IPV6_MULTICAST_HOPS,
68 IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_PKTINFO, IPV6_RECVRTHDR, IPV6_RECVTCLASS,
69 IPV6_RTHDR, IPV6_TCLASS, IPV6_UNICAST_HOPS, IPV6_V6ONLY, MSG_BCAST, MSG_CTRUNC,
70 MSG_DONTROUTE, MSG_MCAST, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL, NI_DGRAM,
71 NI_MAXHOST, NI_MAXSERV, NI_NAMEREQD, NI_NOFQDN, NI_NUMERICHOST, NI_NUMERICSERV,
72 RCVALL_IPLEVEL, RCVALL_OFF, RCVALL_ON, RCVALL_SOCKETLEVELONLY, SD_BOTH as SHUT_RDWR,
73 SD_RECEIVE as SHUT_RD, SD_SEND as SHUT_WR, SIO_KEEPALIVE_VALS, SIO_LOOPBACK_FAST_PATH,
74 SIO_RCVALL, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_RCVBUF,
75 SO_REUSEADDR, SO_SNDBUF, SO_TYPE, SO_USELOOPBACK, SOCK_DGRAM, SOCK_RAW, SOCK_RDM,
76 SOCK_SEQPACKET, SOCK_STREAM, SOL_SOCKET, SOMAXCONN, TCP_NODELAY, WSAEBADF,
77 WSAECONNRESET, WSAENOTSOCK, WSAEWOULDBLOCK,
78 };
79 pub use windows_sys::Win32::Networking::WinSock::{
80 INVALID_SOCKET, SOCKET_ERROR, WSA_FLAG_OVERLAPPED, WSADuplicateSocketW,
81 WSAGetLastError, WSAIoctl, WSAPROTOCOL_INFOW, WSASocketW,
82 };
83 pub use windows_sys::Win32::Networking::WinSock::{
84 SO_REUSEADDR as SO_EXCLUSIVEADDRUSE, getprotobyname, getservbyname, getservbyport,
85 getsockopt, setsockopt,
86 };
87 pub use windows_sys::Win32::Networking::WinSock::{
88 WSA_NOT_ENOUGH_MEMORY as EAI_MEMORY, WSAEAFNOSUPPORT as EAI_FAMILY,
89 WSAEINVAL as EAI_BADFLAGS, WSAESOCKTNOSUPPORT as EAI_SOCKTYPE,
90 WSAHOST_NOT_FOUND as EAI_NODATA, WSAHOST_NOT_FOUND as EAI_NONAME,
91 WSANO_RECOVERY as EAI_FAIL, WSATRY_AGAIN as EAI_AGAIN,
92 WSATYPE_NOT_FOUND as EAI_SERVICE,
93 };
94 pub const IF_NAMESIZE: usize =
95 windows_sys::Win32::NetworkManagement::Ndis::IF_MAX_STRING_SIZE as _;
96 pub const AF_UNSPEC: i32 = windows_sys::Win32::Networking::WinSock::AF_UNSPEC as _;
97 pub const AF_INET: i32 = windows_sys::Win32::Networking::WinSock::AF_INET as _;
98 pub const AF_INET6: i32 = windows_sys::Win32::Networking::WinSock::AF_INET6 as _;
99 pub const AI_PASSIVE: i32 = windows_sys::Win32::Networking::WinSock::AI_PASSIVE as _;
100 pub const AI_NUMERICHOST: i32 =
101 windows_sys::Win32::Networking::WinSock::AI_NUMERICHOST as _;
102 pub const FROM_PROTOCOL_INFO: i32 = -1;
103 }
104 #[pyattr(name = "has_ipv6")]
106 const HAS_IPV6: bool = true;
107 #[pyattr]
108 use c::{
110 AF_INET, AF_INET6, AF_UNSPEC, INADDR_ANY, INADDR_LOOPBACK, INADDR_NONE, IPPROTO_ICMP,
111 IPPROTO_ICMPV6, IPPROTO_IP, IPPROTO_IPV6, IPPROTO_TCP, IPPROTO_TCP as SOL_TCP, IPPROTO_UDP,
112 MSG_CTRUNC, MSG_DONTROUTE, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL, NI_DGRAM, NI_MAXHOST,
113 NI_NAMEREQD, NI_NOFQDN, NI_NUMERICHOST, NI_NUMERICSERV, SHUT_RD, SHUT_RDWR, SHUT_WR,
114 SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_REUSEADDR,
115 SO_SNDBUF, SO_TYPE, SOCK_DGRAM, SOCK_STREAM, SOL_SOCKET, TCP_NODELAY,
116 };
117
118 #[cfg(not(target_os = "redox"))]
119 #[pyattr]
120 use c::{
121 AF_APPLETALK, AF_DECnet, AF_IPX, IPPROTO_AH, IPPROTO_DSTOPTS, IPPROTO_EGP, IPPROTO_ESP,
122 IPPROTO_FRAGMENT, IPPROTO_HOPOPTS, IPPROTO_IDP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_NONE,
123 IPPROTO_PIM, IPPROTO_PUP, IPPROTO_RAW, IPPROTO_ROUTING,
124 };
125
126 #[cfg(unix)]
127 #[pyattr]
128 use c::{AF_UNIX, SO_REUSEPORT};
129
130 #[pyattr]
131 use c::{AI_ADDRCONFIG, AI_NUMERICHOST, AI_NUMERICSERV, AI_PASSIVE};
132
133 #[cfg(not(target_os = "redox"))]
134 #[pyattr]
135 use c::{SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET};
136
137 #[cfg(target_os = "android")]
138 #[pyattr]
139 use c::{SOL_ATALK, SOL_AX25, SOL_IPX, SOL_NETROM, SOL_ROSE};
140
141 #[cfg(target_os = "freebsd")]
142 #[pyattr]
143 use c::SO_SETFIB;
144
145 #[cfg(target_os = "linux")]
146 #[pyattr]
147 use c::{
148 CAN_BCM, CAN_EFF_FLAG, CAN_EFF_MASK, CAN_ERR_FLAG, CAN_ERR_MASK, CAN_ISOTP, CAN_J1939,
149 CAN_RAW, CAN_RAW_ERR_FILTER, CAN_RAW_FD_FRAMES, CAN_RAW_FILTER, CAN_RAW_JOIN_FILTERS,
150 CAN_RAW_LOOPBACK, CAN_RAW_RECV_OWN_MSGS, CAN_RTR_FLAG, CAN_SFF_MASK, IPPROTO_MPTCP,
151 J1939_IDLE_ADDR, J1939_MAX_UNICAST_ADDR, J1939_NLA_BYTES_ACKED, J1939_NLA_PAD,
152 J1939_NO_ADDR, J1939_NO_NAME, J1939_NO_PGN, J1939_PGN_ADDRESS_CLAIMED,
153 J1939_PGN_ADDRESS_COMMANDED, J1939_PGN_MAX, J1939_PGN_PDU1_MAX, J1939_PGN_REQUEST,
154 SCM_J1939_DEST_ADDR, SCM_J1939_DEST_NAME, SCM_J1939_ERRQUEUE, SCM_J1939_PRIO,
155 SO_J1939_ERRQUEUE, SO_J1939_FILTER, SO_J1939_PROMISC, SO_J1939_SEND_PRIO, SOL_CAN_BASE,
156 SOL_CAN_RAW,
157 };
158
159 #[cfg(target_os = "linux")]
161 #[pyattr]
162 const CAN_BCM_TX_SETUP: i32 = 1;
163 #[cfg(target_os = "linux")]
164 #[pyattr]
165 const CAN_BCM_TX_DELETE: i32 = 2;
166 #[cfg(target_os = "linux")]
167 #[pyattr]
168 const CAN_BCM_TX_READ: i32 = 3;
169 #[cfg(target_os = "linux")]
170 #[pyattr]
171 const CAN_BCM_TX_SEND: i32 = 4;
172 #[cfg(target_os = "linux")]
173 #[pyattr]
174 const CAN_BCM_RX_SETUP: i32 = 5;
175 #[cfg(target_os = "linux")]
176 #[pyattr]
177 const CAN_BCM_RX_DELETE: i32 = 6;
178 #[cfg(target_os = "linux")]
179 #[pyattr]
180 const CAN_BCM_RX_READ: i32 = 7;
181 #[cfg(target_os = "linux")]
182 #[pyattr]
183 const CAN_BCM_TX_STATUS: i32 = 8;
184 #[cfg(target_os = "linux")]
185 #[pyattr]
186 const CAN_BCM_TX_EXPIRED: i32 = 9;
187 #[cfg(target_os = "linux")]
188 #[pyattr]
189 const CAN_BCM_RX_STATUS: i32 = 10;
190 #[cfg(target_os = "linux")]
191 #[pyattr]
192 const CAN_BCM_RX_TIMEOUT: i32 = 11;
193 #[cfg(target_os = "linux")]
194 #[pyattr]
195 const CAN_BCM_RX_CHANGED: i32 = 12;
196
197 #[cfg(target_os = "linux")]
199 #[pyattr]
200 const CAN_BCM_SETTIMER: i32 = 0x0001;
201 #[cfg(target_os = "linux")]
202 #[pyattr]
203 const CAN_BCM_STARTTIMER: i32 = 0x0002;
204 #[cfg(target_os = "linux")]
205 #[pyattr]
206 const CAN_BCM_TX_COUNTEVT: i32 = 0x0004;
207 #[cfg(target_os = "linux")]
208 #[pyattr]
209 const CAN_BCM_TX_ANNOUNCE: i32 = 0x0008;
210 #[cfg(target_os = "linux")]
211 #[pyattr]
212 const CAN_BCM_TX_CP_CAN_ID: i32 = 0x0010;
213 #[cfg(target_os = "linux")]
214 #[pyattr]
215 const CAN_BCM_RX_FILTER_ID: i32 = 0x0020;
216 #[cfg(target_os = "linux")]
217 #[pyattr]
218 const CAN_BCM_RX_CHECK_DLC: i32 = 0x0040;
219 #[cfg(target_os = "linux")]
220 #[pyattr]
221 const CAN_BCM_RX_NO_AUTOTIMER: i32 = 0x0080;
222 #[cfg(target_os = "linux")]
223 #[pyattr]
224 const CAN_BCM_RX_ANNOUNCE_RESUME: i32 = 0x0100;
225 #[cfg(target_os = "linux")]
226 #[pyattr]
227 const CAN_BCM_TX_RESET_MULTI_IDX: i32 = 0x0200;
228 #[cfg(target_os = "linux")]
229 #[pyattr]
230 const CAN_BCM_RX_RTR_FRAME: i32 = 0x0400;
231 #[cfg(target_os = "linux")]
232 #[pyattr]
233 const CAN_BCM_CAN_FD_FRAME: i32 = 0x0800;
234
235 #[cfg(all(target_os = "linux", target_env = "gnu"))]
236 #[pyattr]
237 use c::SOL_RDS;
238
239 #[cfg(target_os = "netbsd")]
240 #[pyattr]
241 use c::IPPROTO_VRRP;
242
243 #[cfg(target_vendor = "apple")]
244 #[pyattr]
245 use c::{AF_SYSTEM, PF_SYSTEM, SYSPROTO_CONTROL, TCP_KEEPALIVE};
246
247 #[cfg(target_vendor = "apple")]
250 #[pyattr]
251 const IPV6_RECVHOPLIMIT: i32 = 37;
252 #[cfg(target_vendor = "apple")]
253 #[pyattr]
254 const IPV6_RECVRTHDR: i32 = 38;
255 #[cfg(target_vendor = "apple")]
256 #[pyattr]
257 const IPV6_RECVHOPOPTS: i32 = 39;
258 #[cfg(target_vendor = "apple")]
259 #[pyattr]
260 const IPV6_RECVDSTOPTS: i32 = 40;
261 #[cfg(target_vendor = "apple")]
262 #[pyattr]
263 const IPV6_USE_MIN_MTU: i32 = 42;
264 #[cfg(target_vendor = "apple")]
265 #[pyattr]
266 const IPV6_RECVPATHMTU: i32 = 43;
267 #[cfg(target_vendor = "apple")]
268 #[pyattr]
269 const IPV6_PATHMTU: i32 = 44;
270 #[cfg(target_vendor = "apple")]
271 #[pyattr]
272 const IPV6_NEXTHOP: i32 = 48;
273 #[cfg(target_vendor = "apple")]
274 #[pyattr]
275 const IPV6_HOPOPTS: i32 = 49;
276 #[cfg(target_vendor = "apple")]
277 #[pyattr]
278 const IPV6_DSTOPTS: i32 = 50;
279 #[cfg(target_vendor = "apple")]
280 #[pyattr]
281 const IPV6_RTHDR: i32 = 51;
282 #[cfg(target_vendor = "apple")]
283 #[pyattr]
284 const IPV6_RTHDRDSTOPTS: i32 = 57;
285 #[cfg(target_vendor = "apple")]
286 #[pyattr]
287 const IPV6_RTHDR_TYPE_0: i32 = 0;
288
289 #[cfg(windows)]
290 #[pyattr]
291 use c::{
292 IPPORT_RESERVED, IPPROTO_IPV4, RCVALL_IPLEVEL, RCVALL_OFF, RCVALL_ON,
293 RCVALL_SOCKETLEVELONLY, SIO_KEEPALIVE_VALS, SIO_LOOPBACK_FAST_PATH, SIO_RCVALL,
294 SO_EXCLUSIVEADDRUSE,
295 };
296
297 #[cfg(not(windows))]
298 #[pyattr]
299 const IPPORT_RESERVED: i32 = 1024;
300
301 #[pyattr]
302 const IPPORT_USERRESERVED: i32 = 5000;
303
304 #[cfg(any(unix, target_os = "android"))]
305 #[pyattr]
306 use c::{
307 EAI_SYSTEM, MSG_EOR, SO_ACCEPTCONN, SO_DEBUG, SO_DONTROUTE, SO_RCVLOWAT, SO_RCVTIMEO,
308 SO_SNDLOWAT, SO_SNDTIMEO,
309 };
310
311 #[cfg(any(target_os = "android", target_os = "linux"))]
312 #[pyattr]
313 use c::{
314 ALG_OP_DECRYPT, ALG_OP_ENCRYPT, ALG_SET_AEAD_ASSOCLEN, ALG_SET_AEAD_AUTHSIZE, ALG_SET_IV,
315 ALG_SET_KEY, ALG_SET_OP, IP_DEFAULT_MULTICAST_LOOP, IP_RECVOPTS, IP_RETOPTS, IPV6_DSTOPTS,
316 IPV6_NEXTHOP, IPV6_PATHMTU, IPV6_RECVDSTOPTS, IPV6_RECVHOPLIMIT, IPV6_RECVHOPOPTS,
317 IPV6_RECVPATHMTU, IPV6_RTHDRDSTOPTS, NETLINK_CRYPTO, NETLINK_DNRTMSG, NETLINK_FIREWALL,
318 NETLINK_IP6_FW, NETLINK_NFLOG, NETLINK_ROUTE, NETLINK_USERSOCK, NETLINK_XFRM, SO_PASSSEC,
319 SO_PEERSEC, SOL_ALG,
320 };
321
322 #[cfg(any(target_os = "android", target_vendor = "apple"))]
323 #[pyattr]
324 use c::{AI_DEFAULT, AI_MASK, AI_V4MAPPED_CFG};
325
326 #[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
327 #[pyattr]
328 use c::MSG_NOTIFICATION;
329
330 #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
331 #[pyattr]
332 use c::TCP_USER_TIMEOUT;
333
334 #[cfg(any(unix, target_os = "android", windows))]
335 #[pyattr]
336 use c::{
337 INADDR_BROADCAST, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_IF,
338 IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF,
339 IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY,
340 };
341
342 #[cfg(any(unix, target_os = "android", windows))]
343 #[pyattr]
344 const INADDR_UNSPEC_GROUP: u32 = 0xe0000000;
345
346 #[cfg(any(unix, target_os = "android", windows))]
347 #[pyattr]
348 const INADDR_ALLHOSTS_GROUP: u32 = 0xe0000001;
349
350 #[cfg(any(unix, target_os = "android", windows))]
351 #[pyattr]
352 const INADDR_MAX_LOCAL_GROUP: u32 = 0xe00000ff;
353
354 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
355 #[pyattr]
356 use c::{
357 AF_ALG, AF_ASH, AF_ATMPVC, AF_ATMSVC, AF_AX25, AF_BRIDGE, AF_CAN, AF_ECONET, AF_IRDA,
358 AF_LLC, AF_NETBEUI, AF_NETLINK, AF_NETROM, AF_PACKET, AF_PPPOX, AF_RDS, AF_SECURITY,
359 AF_TIPC, AF_VSOCK, AF_WANPIPE, AF_X25, IP_TRANSPARENT, MSG_CONFIRM, MSG_ERRQUEUE,
360 MSG_FASTOPEN, MSG_MORE, PF_CAN, PF_PACKET, PF_RDS, SCM_CREDENTIALS, SO_BINDTODEVICE,
361 SO_MARK, SOL_IP, SOL_TIPC, SOL_UDP, TCP_CORK, TCP_DEFER_ACCEPT, TCP_LINGER2, TCP_QUICKACK,
362 TCP_SYNCNT, TCP_WINDOW_CLAMP,
363 };
364
365 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
367 #[pyattr]
368 const SO_VM_SOCKETS_BUFFER_SIZE: u32 = 0;
369
370 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
372 #[pyattr]
373 const SO_VM_SOCKETS_BUFFER_MIN_SIZE: u32 = 1;
374
375 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
377 #[pyattr]
378 const SO_VM_SOCKETS_BUFFER_MAX_SIZE: u32 = 2;
379
380 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
382 #[pyattr]
383 const VMADDR_CID_ANY: u32 = 0xffffffff; #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
387 #[pyattr]
388 const VMADDR_PORT_ANY: u32 = 0xffffffff; #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
392 #[pyattr]
393 const VMADDR_CID_HOST: u32 = 2;
394
395 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
397 #[pyattr]
398 const VM_SOCKETS_INVALID_VERSION: u32 = 0xffffffff; #[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))]
409 #[pyattr]
410 const SOL_IP: i32 = 0;
411
412 #[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))]
413 #[pyattr]
414 const SOL_UDP: i32 = 17;
415
416 #[cfg(any(target_os = "android", target_os = "linux", windows))]
417 #[pyattr]
418 use c::{IP_OPTIONS, IPV6_HOPOPTS, IPV6_RECVRTHDR, IPV6_RTHDR};
419
420 #[cfg(any(
421 target_os = "dragonfly",
422 target_os = "freebsd",
423 target_vendor = "apple"
424 ))]
425 #[pyattr]
426 use c::{IPPROTO_HELLO, IPPROTO_XTP, LOCAL_PEERCRED, MSG_EOF};
427
428 #[cfg(any(target_os = "netbsd", target_os = "openbsd", windows))]
429 #[pyattr]
430 use c::{MSG_BCAST, MSG_MCAST};
431
432 #[cfg(any(
433 target_os = "android",
434 target_os = "fuchsia",
435 target_os = "freebsd",
436 target_os = "linux"
437 ))]
438 #[pyattr]
439 use c::{IPPROTO_UDPLITE, TCP_CONGESTION};
440
441 #[cfg(any(
442 target_os = "android",
443 target_os = "fuchsia",
444 target_os = "freebsd",
445 target_os = "linux"
446 ))]
447 #[pyattr]
448 const UDPLITE_SEND_CSCOV: i32 = 10;
449
450 #[cfg(any(
451 target_os = "android",
452 target_os = "fuchsia",
453 target_os = "freebsd",
454 target_os = "linux"
455 ))]
456 #[pyattr]
457 const UDPLITE_RECV_CSCOV: i32 = 11;
458
459 #[cfg(any(
460 target_os = "android",
461 target_os = "fuchsia",
462 target_os = "linux",
463 target_os = "openbsd"
464 ))]
465 #[pyattr]
466 use c::AF_KEY;
467
468 #[cfg(any(
469 target_os = "android",
470 target_os = "fuchsia",
471 target_os = "linux",
472 target_os = "redox"
473 ))]
474 #[pyattr]
475 use c::SO_DOMAIN;
476
477 #[cfg(any(
478 target_os = "android",
479 target_os = "fuchsia",
480 all(
481 target_os = "linux",
482 any(
483 target_arch = "aarch64",
484 target_arch = "x86",
485 target_arch = "loongarch64",
486 target_arch = "mips",
487 target_arch = "powerpc",
488 target_arch = "powerpc64",
489 target_arch = "riscv64",
490 target_arch = "s390x",
491 target_arch = "x86_64"
492 )
493 ),
494 target_os = "redox"
495 ))]
496 #[pyattr]
497 use c::SO_PRIORITY;
498
499 #[cfg(any(
500 target_os = "dragonfly",
501 target_os = "freebsd",
502 target_os = "netbsd",
503 target_os = "openbsd"
504 ))]
505 #[pyattr]
506 use c::IPPROTO_MOBILE;
507
508 #[cfg(any(
509 target_os = "dragonfly",
510 target_os = "freebsd",
511 target_os = "netbsd",
512 target_vendor = "apple"
513 ))]
514 #[pyattr]
515 use c::SCM_CREDS;
516
517 #[cfg(any(
518 target_os = "freebsd",
519 target_os = "fuchsia",
520 target_os = "linux",
521 target_vendor = "apple"
522 ))]
523 #[pyattr]
524 use c::TCP_FASTOPEN;
525
526 #[cfg(any(
527 target_os = "android",
528 target_os = "freebsd",
529 target_os = "fuchsia",
530 all(
531 target_os = "linux",
532 any(
533 target_arch = "aarch64",
534 target_arch = "x86",
535 target_arch = "loongarch64",
536 target_arch = "mips",
537 target_arch = "powerpc",
538 target_arch = "powerpc64",
539 target_arch = "riscv64",
540 target_arch = "s390x",
541 target_arch = "x86_64"
542 )
543 ),
544 target_os = "redox"
545 ))]
546 #[pyattr]
547 use c::SO_PROTOCOL;
548
549 #[cfg(any(
550 target_os = "android",
551 target_os = "dragonfly",
552 target_os = "freebsd",
553 target_os = "linux",
554 target_vendor = "apple",
555 windows
556 ))]
557 #[pyattr]
558 use c::IPV6_DONTFRAG;
559
560 #[cfg(any(
561 target_os = "android",
562 target_os = "dragonfly",
563 target_os = "fuchsia",
564 target_os = "linux",
565 target_os = "redox"
566 ))]
567 #[pyattr]
568 use c::{SO_PASSCRED, SO_PEERCRED};
569
570 #[cfg(any(
571 target_os = "android",
572 target_os = "freebsd",
573 target_os = "fuchsia",
574 target_os = "linux",
575 target_os = "netbsd"
576 ))]
577 #[pyattr]
578 use c::TCP_INFO;
579
580 #[cfg(any(
581 target_os = "android",
582 target_os = "freebsd",
583 target_os = "fuchsia",
584 target_os = "linux",
585 target_vendor = "apple"
586 ))]
587 #[pyattr]
588 use c::IP_RECVTOS;
589
590 #[cfg(any(
591 target_os = "android",
592 target_os = "netbsd",
593 target_os = "redox",
594 target_vendor = "apple",
595 windows
596 ))]
597 #[pyattr]
598 use c::NI_MAXSERV;
599
600 #[cfg(any(
601 target_os = "dragonfly",
602 target_os = "freebsd",
603 target_os = "netbsd",
604 target_os = "openbsd",
605 target_vendor = "apple"
606 ))]
607 #[pyattr]
608 use c::{IPPROTO_EON, IPPROTO_IPCOMP};
609
610 #[cfg(any(
611 target_os = "dragonfly",
612 target_os = "freebsd",
613 target_os = "netbsd",
614 target_vendor = "apple",
615 windows
616 ))]
617 #[pyattr]
618 use c::IPPROTO_ND;
619
620 #[cfg(any(
621 target_os = "android",
622 target_os = "dragonfly",
623 target_os = "freebsd",
624 target_os = "linux",
625 target_vendor = "apple",
626 windows
627 ))]
628 #[pyattr]
629 use c::{IPV6_CHECKSUM, IPV6_HOPLIMIT};
630
631 #[cfg(any(
632 target_os = "android",
633 target_os = "freebsd",
634 target_os = "fuchsia",
635 target_os = "linux",
636 target_os = "netbsd"
637 ))]
638 #[pyattr]
639 use c::IPPROTO_SCTP; #[cfg(any(
642 target_os = "android",
643 target_os = "freebsd",
644 target_os = "fuchsia",
645 target_os = "linux",
646 target_vendor = "apple",
647 windows
648 ))]
649 #[pyattr]
650 use c::{AI_ALL, AI_V4MAPPED};
651
652 #[cfg(any(
653 target_os = "android",
654 target_os = "linux",
655 target_os = "netbsd",
656 target_os = "openbsd",
657 target_vendor = "apple",
658 windows
659 ))]
660 #[pyattr]
661 use c::EAI_NODATA;
662
663 #[cfg(any(
664 target_os = "dragonfly",
665 target_os = "freebsd",
666 target_os = "netbsd",
667 target_os = "openbsd",
668 target_vendor = "apple",
669 windows
670 ))]
671 #[pyattr]
672 use c::{
673 AF_LINK, IP_RECVDSTADDR, IPPROTO_GGP, IPV6_JOIN_GROUP, IPV6_LEAVE_GROUP, SO_USELOOPBACK,
674 };
675
676 #[cfg(any(
677 target_os = "android",
678 target_os = "dragonfly",
679 target_os = "freebsd",
680 target_os = "fuchsia",
681 target_os = "linux",
682 target_os = "netbsd",
683 target_os = "openbsd"
684 ))]
685 #[pyattr]
686 use c::{MSG_CMSG_CLOEXEC, MSG_NOSIGNAL};
687
688 #[cfg(any(
689 target_os = "android",
690 target_os = "dragonfly",
691 target_os = "freebsd",
692 target_os = "fuchsia",
693 target_os = "linux",
694 target_os = "netbsd",
695 target_os = "redox"
696 ))]
697 #[pyattr]
698 use c::TCP_KEEPIDLE;
699
700 #[cfg(any(
701 target_os = "android",
702 target_os = "dragonfly",
703 target_os = "freebsd",
704 target_os = "fuchsia",
705 target_os = "linux",
706 target_os = "netbsd",
707 target_vendor = "apple"
708 ))]
709 #[pyattr]
710 use c::{TCP_KEEPCNT, TCP_KEEPINTVL};
711
712 #[cfg(any(
713 target_os = "android",
714 target_os = "dragonfly",
715 target_os = "freebsd",
716 target_os = "fuchsia",
717 target_os = "linux",
718 target_os = "netbsd",
719 target_os = "openbsd",
720 target_os = "redox"
721 ))]
722 #[pyattr]
723 use c::{SOCK_CLOEXEC, SOCK_NONBLOCK};
724
725 #[cfg(any(
726 target_os = "android",
727 target_os = "dragonfly",
728 target_os = "freebsd",
729 target_os = "fuchsia",
730 target_os = "linux",
731 target_os = "netbsd",
732 target_os = "openbsd",
733 target_vendor = "apple"
734 ))]
735 #[pyattr]
736 use c::{
737 AF_ROUTE, AF_SNA, EAI_OVERFLOW, IPPROTO_GRE, IPPROTO_RSVP, IPPROTO_TP, IPV6_RECVPKTINFO,
738 MSG_DONTWAIT, SCM_RIGHTS, TCP_MAXSEG,
739 };
740
741 #[cfg(any(
742 target_os = "android",
743 target_os = "dragonfly",
744 target_os = "freebsd",
745 target_os = "linux",
746 target_os = "netbsd",
747 target_os = "openbsd",
748 target_vendor = "apple",
749 windows
750 ))]
751 #[pyattr]
752 use c::IPV6_PKTINFO;
753
754 #[cfg(any(
755 target_os = "android",
756 target_os = "freebsd",
757 target_os = "fuchsia",
758 target_os = "linux",
759 target_os = "netbsd",
760 target_os = "openbsd",
761 target_vendor = "apple",
762 windows
763 ))]
764 #[pyattr]
765 use c::AI_CANONNAME;
766
767 #[cfg(any(
768 target_os = "android",
769 target_os = "dragonfly",
770 target_os = "freebsd",
771 target_os = "fuchsia",
772 target_os = "linux",
773 target_os = "netbsd",
774 target_os = "openbsd",
775 target_vendor = "apple",
776 windows
777 ))]
778 #[pyattr]
779 use c::{
780 EAI_AGAIN, EAI_BADFLAGS, EAI_FAIL, EAI_FAMILY, EAI_MEMORY, EAI_NONAME, EAI_SERVICE,
781 EAI_SOCKTYPE, IP_HDRINCL, IP_TOS, IPV6_RECVTCLASS, IPV6_TCLASS, SOMAXCONN,
782 };
783
784 #[cfg(not(any(
785 target_os = "android",
786 target_os = "dragonfly",
787 target_os = "freebsd",
788 target_os = "fuchsia",
789 target_os = "linux",
790 target_os = "netbsd",
791 target_os = "openbsd",
792 target_vendor = "apple",
793 windows
794 )))]
795 #[pyattr]
796 const SOMAXCONN: i32 = 5; #[cfg(any(
802 target_os = "android",
803 target_os = "freebsd",
804 target_os = "fuchsia",
805 target_os = "linux",
806 target_os = "openbsd"
807 ))]
808 #[pyattr]
809 use c::AF_BLUETOOTH;
810
811 #[cfg(any(
812 target_os = "android",
813 target_os = "freebsd",
814 target_os = "fuchsia",
815 target_os = "linux",
816 target_os = "openbsd"
817 ))]
818 #[pyattr]
819 const BDADDR_ANY: &str = "00:00:00:00:00:00";
820 #[cfg(any(
821 target_os = "android",
822 target_os = "freebsd",
823 target_os = "fuchsia",
824 target_os = "linux",
825 target_os = "openbsd"
826 ))]
827 #[pyattr]
828 const BDADDR_LOCAL: &str = "00:00:00:FF:FF:FF";
829 #[cfg(windows)]
832 #[pyattr]
833 use windows_sys::Win32::Networking::WinSock::{
834 IPPROTO_CBT, IPPROTO_ICLFXBM, IPPROTO_IGP, IPPROTO_L2TP, IPPROTO_PGM, IPPROTO_RDP,
835 IPPROTO_SCTP, IPPROTO_ST,
836 };
837
838 #[pyattr]
839 fn error(vm: &VirtualMachine) -> PyTypeRef {
840 vm.ctx.exceptions.os_error.to_owned()
841 }
842
843 #[pyattr]
844 fn timeout(vm: &VirtualMachine) -> PyTypeRef {
845 vm.ctx.exceptions.timeout_error.to_owned()
846 }
847
848 #[pyattr(once)]
849 fn herror(vm: &VirtualMachine) -> PyTypeRef {
850 vm.ctx.new_exception_type(
851 "socket",
852 "herror",
853 Some(vec![vm.ctx.exceptions.os_error.to_owned()]),
854 )
855 }
856 #[pyattr(once)]
857 fn gaierror(vm: &VirtualMachine) -> PyTypeRef {
858 vm.ctx.new_exception_type(
859 "socket",
860 "gaierror",
861 Some(vec![vm.ctx.exceptions.os_error.to_owned()]),
862 )
863 }
864
865 #[pyfunction]
866 const fn htonl(x: u32) -> u32 {
867 u32::to_be(x)
868 }
869
870 #[pyfunction]
871 const fn htons(x: u16) -> u16 {
872 u16::to_be(x)
873 }
874
875 #[pyfunction]
876 const fn ntohl(x: u32) -> u32 {
877 u32::from_be(x)
878 }
879
880 #[pyfunction]
881 const fn ntohs(x: u16) -> u16 {
882 u16::from_be(x)
883 }
884
885 #[cfg(unix)]
886 type RawSocket = std::os::unix::io::RawFd;
887 #[cfg(windows)]
888 type RawSocket = std::os::windows::raw::SOCKET;
889
890 #[cfg(unix)]
891 macro_rules! errcode {
892 ($e:ident) => {
893 c::$e
894 };
895 }
896 #[cfg(windows)]
897 macro_rules! errcode {
898 ($e:ident) => {
899 paste::paste!(c::[<WSA $e>])
900 };
901}
902
903 #[cfg(windows)]
904 use windows_sys::Win32::NetworkManagement::IpHelper;
905
906 fn get_raw_sock(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<RawSocket> {
907 #[cfg(unix)]
908 type CastFrom = libc::c_long;
909 #[cfg(windows)]
910 type CastFrom = libc::c_longlong;
911
912 if obj.fast_isinstance(vm.ctx.types.float_type) {
914 return Err(vm.new_type_error("integer argument expected, got float"));
915 }
916 let int = obj
917 .try_index_opt(vm)
918 .unwrap_or_else(|| Err(vm.new_type_error("an integer is required")))?;
919 int.try_to_primitive::<CastFrom>(vm)
920 .map(|sock| sock as RawSocket)
921 }
922
923 #[cfg(target_os = "linux")]
924 #[derive(FromArgs)]
925 struct SendmsgAfalgArgs {
926 #[pyarg(any, default)]
927 msg: Vec<ArgBytesLike>,
928 #[pyarg(named)]
929 op: u32,
930 #[pyarg(named, default)]
931 iv: Option<ArgBytesLike>,
932 #[pyarg(named, default)]
933 assoclen: OptionalArg<isize>,
934 #[pyarg(named, default)]
935 flags: i32,
936 }
937
938 #[pyattr(name = "socket")]
939 #[pyattr(name = "SocketType")]
940 #[pyclass(name = "socket")]
941 #[derive(Debug, PyPayload)]
942 pub struct PySocket {
943 kind: AtomicCell<i32>,
944 family: AtomicCell<i32>,
945 proto: AtomicCell<i32>,
946 pub(crate) timeout: AtomicCell<f64>,
947 sock: PyRwLock<Option<Socket>>,
948 }
949
950 const _: () = assert!(core::mem::size_of::<Option<Socket>>() == core::mem::size_of::<Socket>());
951
952 impl Default for PySocket {
953 fn default() -> Self {
954 Self {
955 kind: AtomicCell::default(),
956 family: AtomicCell::default(),
957 proto: AtomicCell::default(),
958 timeout: AtomicCell::new(-1.0),
959 sock: PyRwLock::new(None),
960 }
961 }
962 }
963
964 #[cfg(windows)]
965 const CLOSED_ERR: i32 = c::WSAENOTSOCK;
966 #[cfg(unix)]
967 const CLOSED_ERR: i32 = c::EBADF;
968
969 impl Read for &PySocket {
970 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
971 (&mut &*self.sock()?).read(buf)
972 }
973 }
974
975 impl Write for &PySocket {
976 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
977 (&mut &*self.sock()?).write(buf)
978 }
979
980 fn flush(&mut self) -> std::io::Result<()> {
981 (&mut &*self.sock()?).flush()
982 }
983 }
984
985 impl PySocket {
986 pub fn sock_opt(&self) -> Option<PyMappedRwLockReadGuard<'_, Socket>> {
987 let sock = PyRwLockReadGuard::try_map(self.sock.read(), |sock| sock.as_ref());
988 sock.ok()
989 }
990
991 pub fn sock(&self) -> io::Result<PyMappedRwLockReadGuard<'_, Socket>> {
992 self.sock_opt()
993 .ok_or_else(|| io::Error::from_raw_os_error(CLOSED_ERR))
994 }
995
996 fn init_inner(
997 &self,
998 family: i32,
999 socket_kind: i32,
1000 proto: i32,
1001 sock: Socket,
1002 ) -> io::Result<()> {
1003 self.family.store(family);
1004 #[cfg(any(
1007 target_os = "android",
1008 target_os = "dragonfly",
1009 target_os = "freebsd",
1010 target_os = "fuchsia",
1011 target_os = "illumos",
1012 target_os = "linux",
1013 target_os = "netbsd",
1014 target_os = "openbsd",
1015 target_os = "redox"
1016 ))]
1017 let masked_kind = socket_kind & !(c::SOCK_NONBLOCK | c::SOCK_CLOEXEC);
1018 #[cfg(not(any(
1019 target_os = "android",
1020 target_os = "dragonfly",
1021 target_os = "freebsd",
1022 target_os = "fuchsia",
1023 target_os = "illumos",
1024 target_os = "linux",
1025 target_os = "netbsd",
1026 target_os = "openbsd",
1027 target_os = "redox"
1028 )))]
1029 let masked_kind = socket_kind;
1030 self.kind.store(masked_kind);
1031 self.proto.store(proto);
1032 let mut s = self.sock.write();
1033 let sock = s.insert(sock);
1034 #[cfg(any(
1036 target_os = "android",
1037 target_os = "dragonfly",
1038 target_os = "freebsd",
1039 target_os = "fuchsia",
1040 target_os = "illumos",
1041 target_os = "linux",
1042 target_os = "netbsd",
1043 target_os = "openbsd",
1044 target_os = "redox"
1045 ))]
1046 let timeout = if socket_kind & c::SOCK_NONBLOCK != 0 {
1047 0.0
1048 } else {
1049 DEFAULT_TIMEOUT.load()
1050 };
1051 #[cfg(not(any(
1052 target_os = "android",
1053 target_os = "dragonfly",
1054 target_os = "freebsd",
1055 target_os = "fuchsia",
1056 target_os = "illumos",
1057 target_os = "linux",
1058 target_os = "netbsd",
1059 target_os = "openbsd",
1060 target_os = "redox"
1061 )))]
1062 let timeout = DEFAULT_TIMEOUT.load();
1063 self.timeout.store(timeout);
1064 if timeout >= 0.0 {
1065 sock.set_nonblocking(true)?;
1066 }
1067 Ok(())
1068 }
1069
1070 pub fn get_timeout(&self) -> Result<Duration, bool> {
1072 let timeout = self.timeout.load();
1073 if timeout > 0.0 {
1074 Ok(Duration::from_secs_f64(timeout))
1075 } else {
1076 Err(timeout != 0.0)
1077 }
1078 }
1079
1080 fn sock_op<F, R>(
1081 &self,
1082 vm: &VirtualMachine,
1083 select: SelectKind,
1084 f: F,
1085 ) -> Result<R, IoOrPyException>
1086 where
1087 F: FnMut() -> io::Result<R>,
1088 {
1089 let timeout = self.get_timeout().ok();
1090 self.sock_op_timeout_err(vm, select, timeout, f)
1091 }
1092
1093 fn sock_op_timeout_err<F, R>(
1094 &self,
1095 vm: &VirtualMachine,
1096 select: SelectKind,
1097 timeout: Option<Duration>,
1098 mut f: F,
1099 ) -> Result<R, IoOrPyException>
1100 where
1101 F: FnMut() -> io::Result<R>,
1102 {
1103 let deadline = timeout.map(Deadline::new);
1104
1105 loop {
1106 if deadline.is_some() || matches!(select, SelectKind::Connect) {
1107 let interval = deadline.as_ref().map(|d| d.time_until()).transpose()?;
1108 let sock = self.sock()?;
1109 let res = vm.allow_threads(|| sock_select(&sock, select, interval));
1110 match res {
1111 Ok(true) => return Err(IoOrPyException::Timeout),
1112 Err(e) if e.kind() == io::ErrorKind::Interrupted => {
1113 vm.check_signals()?;
1114 continue;
1115 }
1116 Err(e) => return Err(e.into()),
1117 Ok(false) => {} }
1119 }
1120
1121 let err = loop {
1122 match vm.allow_threads(&mut f) {
1125 Ok(x) => return Ok(x),
1126 Err(e) if e.kind() == io::ErrorKind::Interrupted => vm.check_signals()?,
1127 Err(e) => break e,
1128 }
1129 };
1130 if timeout.is_some() && err.kind() == io::ErrorKind::WouldBlock {
1131 continue;
1132 }
1133 return Err(err.into());
1134 }
1135 }
1136
1137 fn extract_address(
1138 &self,
1139 addr: PyObjectRef,
1140 caller: &str,
1141 vm: &VirtualMachine,
1142 ) -> Result<socket2::SockAddr, IoOrPyException> {
1143 let family = self.family.load();
1144 match family {
1145 #[cfg(unix)]
1146 c::AF_UNIX => {
1147 use crate::vm::function::ArgStrOrBytesLike;
1148 use std::os::unix::ffi::OsStrExt;
1149 let buf = ArgStrOrBytesLike::try_from_object(vm, addr)?;
1150 let bytes = &*buf.borrow_bytes();
1151 let path = match &buf {
1152 ArgStrOrBytesLike::Buf(_) => ffi::OsStr::from_bytes(bytes).into(),
1153 ArgStrOrBytesLike::Str(s) => vm.fsencode(s)?,
1154 };
1155 socket2::SockAddr::unix(path)
1156 .map_err(|_| vm.new_os_error("AF_UNIX path too long".to_owned()).into())
1157 }
1158 c::AF_INET => {
1159 let tuple: PyTupleRef = addr.downcast().map_err(|obj| {
1160 vm.new_type_error(format!(
1161 "{}(): AF_INET address must be tuple, not {}",
1162 caller,
1163 obj.class().name()
1164 ))
1165 })?;
1166 if tuple.len() != 2 {
1167 return Err(vm
1168 .new_type_error("AF_INET address must be a pair (host, post)")
1169 .into());
1170 }
1171 let addr = Address::from_tuple(&tuple, vm)?;
1172 let mut addr4 = get_addr(vm, addr.host, c::AF_INET)?;
1173 match &mut addr4 {
1174 SocketAddr::V4(addr4) => {
1175 addr4.set_port(addr.port);
1176 }
1177 SocketAddr::V6(_) => unreachable!(),
1178 }
1179 Ok(addr4.into())
1180 }
1181 c::AF_INET6 => {
1182 let tuple: PyTupleRef = addr.downcast().map_err(|obj| {
1183 vm.new_type_error(format!(
1184 "{}(): AF_INET6 address must be tuple, not {}",
1185 caller,
1186 obj.class().name()
1187 ))
1188 })?;
1189 match tuple.len() {
1190 2..=4 => {}
1191 _ => return Err(vm.new_type_error(
1192 "AF_INET6 address must be a tuple (host, port[, flowinfo[, scopeid]])",
1193 ).into()),
1194 }
1195 let (addr, flowinfo, scopeid) = Address::from_tuple_ipv6(&tuple, vm)?;
1196 let mut addr6 = get_addr(vm, addr.host, c::AF_INET6)?;
1197 match &mut addr6 {
1198 SocketAddr::V6(addr6) => {
1199 addr6.set_port(addr.port);
1200 addr6.set_flowinfo(flowinfo);
1201 addr6.set_scope_id(scopeid);
1202 }
1203 SocketAddr::V4(_) => unreachable!(),
1204 }
1205 Ok(addr6.into())
1206 }
1207 #[cfg(target_os = "linux")]
1208 c::AF_CAN => {
1209 let tuple: PyTupleRef = addr.downcast().map_err(|obj| {
1210 vm.new_type_error(format!(
1211 "{}(): AF_CAN address must be tuple, not {}",
1212 caller,
1213 obj.class().name()
1214 ))
1215 })?;
1216 if tuple.is_empty() || tuple.len() > 2 {
1217 return Err(vm
1218 .new_type_error(
1219 "AF_CAN address must be a tuple (interface,) or (interface, addr)",
1220 )
1221 .into());
1222 }
1223 let interface: PyStrRef = tuple[0].clone().downcast().map_err(|obj| {
1224 vm.new_type_error(format!(
1225 "{}(): AF_CAN interface must be str, not {}",
1226 caller,
1227 obj.class().name()
1228 ))
1229 })?;
1230 let interface = interface.try_into_utf8(vm).map_err(IoOrPyException::from)?;
1231 let ifname = interface.as_str();
1232
1233 let ifindex = if ifname.is_empty() {
1235 0 } else {
1237 if ifname.len() >= 16 {
1239 return Err(vm
1240 .new_os_error("interface name too long".to_owned())
1241 .into());
1242 }
1243 let cstr = alloc::ffi::CString::new(ifname)
1244 .map_err(|_| vm.new_os_error("invalid interface name".to_owned()))?;
1245 let idx = unsafe { libc::if_nametoindex(cstr.as_ptr()) };
1246 if idx == 0 {
1247 return Err(io::Error::last_os_error().into());
1248 }
1249 idx as i32
1250 };
1251
1252 let mut storage: libc::sockaddr_storage = unsafe { core::mem::zeroed() };
1254 let can_addr =
1255 &mut storage as *mut libc::sockaddr_storage as *mut libc::sockaddr_can;
1256 unsafe {
1257 (*can_addr).can_family = libc::AF_CAN as libc::sa_family_t;
1258 (*can_addr).can_ifindex = ifindex;
1259 }
1260 let storage: socket2::SockAddrStorage =
1261 unsafe { core::mem::transmute(storage) };
1262 Ok(unsafe {
1263 socket2::SockAddr::new(
1264 storage,
1265 core::mem::size_of::<libc::sockaddr_can>() as libc::socklen_t,
1266 )
1267 })
1268 }
1269 #[cfg(target_os = "linux")]
1270 c::AF_ALG => {
1271 let tuple: PyTupleRef = addr.downcast().map_err(|obj| {
1272 vm.new_type_error(format!(
1273 "{}(): AF_ALG address must be tuple, not {}",
1274 caller,
1275 obj.class().name()
1276 ))
1277 })?;
1278 if tuple.len() != 2 {
1279 return Err(vm
1280 .new_type_error("AF_ALG address must be a tuple (type, name)")
1281 .into());
1282 }
1283 let alg_type: PyStrRef = tuple[0].clone().downcast().map_err(|obj| {
1284 vm.new_type_error(format!(
1285 "{}(): AF_ALG type must be str, not {}",
1286 caller,
1287 obj.class().name()
1288 ))
1289 })?;
1290 let alg_name: PyStrRef = tuple[1].clone().downcast().map_err(|obj| {
1291 vm.new_type_error(format!(
1292 "{}(): AF_ALG name must be str, not {}",
1293 caller,
1294 obj.class().name()
1295 ))
1296 })?;
1297
1298 let alg_type = alg_type.try_into_utf8(vm).map_err(IoOrPyException::from)?;
1299 let alg_name = alg_name.try_into_utf8(vm).map_err(IoOrPyException::from)?;
1300 let type_str = alg_type.as_str();
1301 let name_str = alg_name.as_str();
1302
1303 if type_str.len() >= 14 {
1305 return Err(vm.new_value_error("type too long").into());
1306 }
1307 if name_str.len() >= 64 {
1308 return Err(vm.new_value_error("name too long").into());
1309 }
1310
1311 let mut storage: libc::sockaddr_storage = unsafe { core::mem::zeroed() };
1313 let alg_addr =
1314 &mut storage as *mut libc::sockaddr_storage as *mut libc::sockaddr_alg;
1315 unsafe {
1316 (*alg_addr).salg_family = libc::AF_ALG as libc::sa_family_t;
1317 for (i, b) in type_str.bytes().enumerate() {
1319 (*alg_addr).salg_type[i] = b;
1320 }
1321 for (i, b) in name_str.bytes().enumerate() {
1323 (*alg_addr).salg_name[i] = b;
1324 }
1325 }
1326 let storage: socket2::SockAddrStorage =
1327 unsafe { core::mem::transmute(storage) };
1328 Ok(unsafe {
1329 socket2::SockAddr::new(
1330 storage,
1331 core::mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t,
1332 )
1333 })
1334 }
1335 _ => Err(vm.new_os_error(format!("{caller}(): bad family")).into()),
1336 }
1337 }
1338
1339 fn connect_inner(
1340 &self,
1341 address: PyObjectRef,
1342 caller: &str,
1343 vm: &VirtualMachine,
1344 ) -> Result<(), IoOrPyException> {
1345 let sock_addr = self.extract_address(address, caller, vm)?;
1346
1347 let sock = self.sock()?;
1348 let err = match vm.allow_threads(|| sock.connect(&sock_addr)) {
1349 Ok(()) => return Ok(()),
1350 Err(e) => e,
1351 };
1352
1353 let wait_connect = if err.kind() == io::ErrorKind::Interrupted {
1354 vm.check_signals()?;
1355 self.timeout.load() != 0.0
1356 } else {
1357 #[cfg(unix)]
1358 use c::EINPROGRESS;
1359 #[cfg(windows)]
1360 use c::WSAEWOULDBLOCK as EINPROGRESS;
1361
1362 self.timeout.load() > 0.0 && err.raw_os_error() == Some(EINPROGRESS)
1363 };
1364
1365 if wait_connect {
1366 self.sock_op(vm, SelectKind::Connect, || {
1370 let sock = self.sock()?;
1371 let err = sock.take_error()?;
1372 match err {
1373 Some(e) if e.posix_errno() == libc::EISCONN => Ok(()),
1374 Some(e) => Err(e),
1375 None => Ok(()),
1377 }
1378 })
1379 } else {
1380 Err(err.into())
1381 }
1382 }
1383 }
1384
1385 impl DefaultConstructor for PySocket {}
1386
1387 #[derive(FromArgs)]
1388 pub struct SocketInitArgs {
1389 #[pyarg(any, optional)]
1390 family: OptionalArg<i32>,
1391 #[pyarg(any, optional)]
1392 r#type: OptionalArg<i32>,
1393 #[pyarg(any, optional)]
1394 proto: OptionalArg<i32>,
1395 #[pyarg(any, optional)]
1396 fileno: OptionalOption<PyObjectRef>,
1397 }
1398
1399 impl Initializer for PySocket {
1400 type Args = SocketInitArgs;
1401
1402 fn init(zelf: PyRef<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
1403 Self::_init(zelf, args, vm).map_err(|e| e.into_pyexception(vm))
1404 }
1405 }
1406
1407 impl Representable for PySocket {
1408 #[inline]
1409 fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
1410 Ok(format!(
1411 "<socket object, fd={}, family={}, type={}, proto={}>",
1412 zelf.fileno(),
1413 zelf.family.load(),
1414 zelf.kind.load(),
1415 zelf.proto.load(),
1416 ))
1417 }
1418 }
1419
1420 impl Destructor for PySocket {
1421 fn del(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<()> {
1422 if zelf.sock.read().is_some() {
1424 let laddr = if let Ok(sock) = zelf.sock()
1425 && let Ok(addr) = sock.local_addr()
1426 && let Ok(repr) = get_addr_tuple(&addr, vm).repr(vm)
1427 {
1428 format!(", laddr={}", repr.as_wtf8())
1429 } else {
1430 String::new()
1431 };
1432
1433 let msg = format!(
1434 "unclosed <socket.socket fd={}, family={}, type={}, proto={}{}>",
1435 zelf.fileno(),
1436 zelf.family.load(),
1437 zelf.kind.load(),
1438 zelf.proto.load(),
1439 laddr
1440 );
1441 let _ = crate::vm::warn::warn(
1442 vm.ctx.new_str(msg).into(),
1443 Some(vm.ctx.exceptions.resource_warning.to_owned()),
1444 1,
1445 None,
1446 vm,
1447 );
1448 }
1449 let _ = zelf.close();
1450 Ok(())
1451 }
1452 }
1453
1454 #[pyclass(
1455 with(Constructor, Initializer, Representable, Destructor),
1456 flags(BASETYPE)
1457 )]
1458 impl PySocket {
1459 fn _init(
1460 zelf: PyRef<Self>,
1461 args: <Self as Initializer>::Args,
1462 vm: &VirtualMachine,
1463 ) -> Result<(), IoOrPyException> {
1464 let mut family = args.family.unwrap_or(-1);
1465 let mut socket_kind = args.r#type.unwrap_or(-1);
1466 let mut proto = args.proto.unwrap_or(-1);
1467
1468 let fileno = args.fileno;
1469 let sock;
1470
1471 #[cfg(windows)]
1473 if let Some(fileno_obj) = fileno.flatten() {
1474 use crate::vm::builtins::PyBytes;
1475 if let Ok(bytes) = fileno_obj.clone().downcast::<PyBytes>() {
1476 let bytes_data = bytes.as_bytes();
1477 let expected_size = core::mem::size_of::<c::WSAPROTOCOL_INFOW>();
1478
1479 if bytes_data.len() != expected_size {
1480 return Err(vm
1481 .new_value_error(format!(
1482 "socket descriptor string has wrong size, should be {} bytes",
1483 expected_size
1484 ))
1485 .into());
1486 }
1487
1488 let mut info: c::WSAPROTOCOL_INFOW = unsafe { core::mem::zeroed() };
1489 unsafe {
1490 core::ptr::copy_nonoverlapping(
1491 bytes_data.as_ptr(),
1492 &mut info as *mut c::WSAPROTOCOL_INFOW as *mut u8,
1493 expected_size,
1494 );
1495 }
1496
1497 let fd = unsafe {
1498 c::WSASocketW(
1499 c::FROM_PROTOCOL_INFO,
1500 c::FROM_PROTOCOL_INFO,
1501 c::FROM_PROTOCOL_INFO,
1502 &info,
1503 0,
1504 c::WSA_FLAG_OVERLAPPED,
1505 )
1506 };
1507
1508 if fd == c::INVALID_SOCKET {
1509 return Err(Self::wsa_error().into());
1510 }
1511
1512 crate::vm::stdlib::nt::raw_set_handle_inheritable(fd as _, false)?;
1513
1514 family = info.iAddressFamily;
1515 socket_kind = info.iSocketType;
1516 proto = info.iProtocol;
1517
1518 sock = unsafe { sock_from_raw_unchecked(fd as RawSocket) };
1519 return Ok(zelf.init_inner(family, socket_kind, proto, sock)?);
1520 }
1521
1522 let fileno = get_raw_sock(fileno_obj, vm)?;
1524 sock = sock_from_raw(fileno, vm)?;
1525 match sock.local_addr() {
1526 Ok(addr) if family == -1 => family = addr.family() as i32,
1527 Err(e)
1528 if family == -1
1529 || matches!(
1530 e.raw_os_error(),
1531 Some(errcode!(ENOTSOCK)) | Some(errcode!(EBADF))
1532 ) =>
1533 {
1534 core::mem::forget(sock);
1535 return Err(e.into());
1536 }
1537 _ => {}
1538 }
1539 if socket_kind == -1 {
1540 socket_kind = sock.r#type().map_err(|e| e.into_pyexception(vm))?.into();
1541 }
1542 proto = 0;
1543 return Ok(zelf.init_inner(family, socket_kind, proto, sock)?);
1544 }
1545
1546 #[cfg(not(windows))]
1547 let fileno = fileno
1548 .flatten()
1549 .map(|obj| get_raw_sock(obj, vm))
1550 .transpose()?;
1551 #[cfg(not(windows))]
1552 if let Some(fileno) = fileno {
1553 sock = sock_from_raw(fileno, vm)?;
1554 match sock.local_addr() {
1555 Ok(addr) if family == -1 => family = addr.family() as i32,
1556 Err(e)
1557 if family == -1
1558 || matches!(
1559 e.raw_os_error(),
1560 Some(errcode!(ENOTSOCK)) | Some(errcode!(EBADF))
1561 ) =>
1562 {
1563 core::mem::forget(sock);
1564 return Err(e.into());
1565 }
1566 _ => {}
1567 }
1568 if socket_kind == -1 {
1569 socket_kind = sock.r#type().map_err(|e| e.into_pyexception(vm))?.into();
1570 }
1571 cfg_if::cfg_if! {
1572 if #[cfg(any(
1573 target_os = "android",
1574 target_os = "freebsd",
1575 target_os = "fuchsia",
1576 target_os = "linux",
1577 ))] {
1578 if proto == -1 {
1579 proto = sock.protocol()?.map_or(0, Into::into);
1580 }
1581 } else {
1582 proto = 0;
1583 }
1584 }
1585 return Ok(zelf.init_inner(family, socket_kind, proto, sock)?);
1586 }
1587
1588 {
1590 if family == -1 {
1591 family = c::AF_INET as _
1592 }
1593 if socket_kind == -1 {
1594 socket_kind = c::SOCK_STREAM
1595 }
1596 if proto == -1 {
1597 proto = 0
1598 }
1599 sock = Socket::new(family.into(), socket_kind.into(), Some(proto.into()))?;
1600 };
1601 Ok(zelf.init_inner(family, socket_kind, proto, sock)?)
1602 }
1603
1604 #[pymethod]
1605 fn connect(
1606 &self,
1607 address: PyObjectRef,
1608 vm: &VirtualMachine,
1609 ) -> Result<(), IoOrPyException> {
1610 self.connect_inner(address, "connect", vm)
1611 }
1612
1613 #[pymethod]
1614 fn connect_ex(&self, address: PyObjectRef, vm: &VirtualMachine) -> PyResult<i32> {
1615 match self.connect_inner(address, "connect_ex", vm) {
1616 Ok(()) => Ok(0),
1617 Err(err) => err.errno(),
1618 }
1619 }
1620
1621 #[pymethod]
1622 fn bind(&self, address: PyObjectRef, vm: &VirtualMachine) -> Result<(), IoOrPyException> {
1623 let sock_addr = self.extract_address(address, "bind", vm)?;
1624 Ok(self.sock()?.bind(&sock_addr)?)
1625 }
1626
1627 #[pymethod]
1628 fn listen(&self, backlog: OptionalArg<i32>) -> io::Result<()> {
1629 let backlog = backlog.unwrap_or(128);
1630 let backlog = if backlog < 0 { 0 } else { backlog };
1631 self.sock()?.listen(backlog)
1632 }
1633
1634 #[pymethod]
1635 fn _accept(
1636 &self,
1637 vm: &VirtualMachine,
1638 ) -> Result<(RawSocket, PyObjectRef), IoOrPyException> {
1639 let (sock, addr) = self.sock_op(vm, SelectKind::Read, || self.sock()?.accept_raw())?;
1642 let fd = into_sock_fileno(sock);
1643 Ok((fd, get_addr_tuple(&addr, vm)))
1644 }
1645
1646 #[pymethod]
1647 fn recv(
1648 &self,
1649 bufsize: usize,
1650 flags: OptionalArg<i32>,
1651 vm: &VirtualMachine,
1652 ) -> Result<Vec<u8>, IoOrPyException> {
1653 let flags = flags.unwrap_or(0);
1654 let mut buffer = Vec::with_capacity(bufsize);
1655 let sock = self.sock()?;
1656 let n = self.sock_op(vm, SelectKind::Read, || {
1657 sock.recv_with_flags(buffer.spare_capacity_mut(), flags)
1658 })?;
1659 unsafe { buffer.set_len(n) };
1660 Ok(buffer)
1661 }
1662
1663 #[pymethod]
1664 fn recv_into(
1665 &self,
1666 buf: ArgMemoryBuffer,
1667 nbytes: OptionalArg<isize>,
1668 flags: OptionalArg<i32>,
1669 vm: &VirtualMachine,
1670 ) -> Result<usize, IoOrPyException> {
1671 let flags = flags.unwrap_or(0);
1672 let sock = self.sock()?;
1673 let mut buf = buf.borrow_buf_mut();
1674 let buf = &mut *buf;
1675
1676 let read_len = if let OptionalArg::Present(nbytes) = nbytes {
1678 let nbytes = nbytes
1679 .to_usize()
1680 .ok_or_else(|| vm.new_value_error("negative buffersize in recv_into"))?;
1681 nbytes.min(buf.len())
1682 } else {
1683 buf.len()
1684 };
1685
1686 let buf = &mut buf[..read_len];
1687 self.sock_op(vm, SelectKind::Read, || {
1688 sock.recv_with_flags(unsafe { slice_as_uninit(buf) }, flags)
1689 })
1690 }
1691
1692 #[pymethod]
1693 fn recvfrom(
1694 &self,
1695 bufsize: isize,
1696 flags: OptionalArg<i32>,
1697 vm: &VirtualMachine,
1698 ) -> Result<(Vec<u8>, PyObjectRef), IoOrPyException> {
1699 let flags = flags.unwrap_or(0);
1700 let bufsize = bufsize
1701 .to_usize()
1702 .ok_or_else(|| vm.new_value_error("negative buffersize in recvfrom"))?;
1703 let mut buffer = Vec::with_capacity(bufsize);
1704 let (n, addr) = self.sock_op(vm, SelectKind::Read, || {
1705 self.sock()?
1706 .recv_from_with_flags(buffer.spare_capacity_mut(), flags)
1707 })?;
1708 unsafe { buffer.set_len(n) };
1709 Ok((buffer, get_addr_tuple(&addr, vm)))
1710 }
1711
1712 #[pymethod]
1713 fn recvfrom_into(
1714 &self,
1715 buf: ArgMemoryBuffer,
1716 nbytes: OptionalArg<isize>,
1717 flags: OptionalArg<i32>,
1718 vm: &VirtualMachine,
1719 ) -> Result<(usize, PyObjectRef), IoOrPyException> {
1720 let mut buf = buf.borrow_buf_mut();
1721 let buf = &mut *buf;
1722 let buf = match nbytes {
1723 OptionalArg::Present(i) => {
1724 let i = i.to_usize().ok_or_else(|| {
1725 vm.new_value_error("negative buffersize in recvfrom_into")
1726 })?;
1727 buf.get_mut(..i).ok_or_else(|| {
1728 vm.new_value_error("nbytes is greater than the length of the buffer")
1729 })?
1730 }
1731 OptionalArg::Missing => buf,
1732 };
1733 let flags = flags.unwrap_or(0);
1734 let sock = self.sock()?;
1735 let (n, addr) = self.sock_op(vm, SelectKind::Read, || {
1736 sock.recv_from_with_flags(unsafe { slice_as_uninit(buf) }, flags)
1737 })?;
1738 Ok((n, get_addr_tuple(&addr, vm)))
1739 }
1740
1741 #[pymethod]
1742 fn send(
1743 &self,
1744 bytes: ArgBytesLike,
1745 flags: OptionalArg<i32>,
1746 vm: &VirtualMachine,
1747 ) -> Result<usize, IoOrPyException> {
1748 let flags = flags.unwrap_or(0);
1749 let buf = bytes.borrow_buf();
1750 let buf = &*buf;
1751 self.sock_op(vm, SelectKind::Write, || {
1752 self.sock()?.send_with_flags(buf, flags)
1753 })
1754 }
1755
1756 #[pymethod]
1757 fn sendall(
1758 &self,
1759 bytes: ArgBytesLike,
1760 flags: OptionalArg<i32>,
1761 vm: &VirtualMachine,
1762 ) -> Result<(), IoOrPyException> {
1763 let flags = flags.unwrap_or(0);
1764
1765 let timeout = self.get_timeout().ok();
1766
1767 let deadline = timeout.map(Deadline::new);
1768
1769 let buf = bytes.borrow_buf();
1770 let buf = &*buf;
1771 let mut buf_offset = 0;
1772 while buf_offset < buf.len() {
1774 let interval = deadline.as_ref().map(|d| d.time_until()).transpose()?;
1775 self.sock_op_timeout_err(vm, SelectKind::Write, interval, || {
1776 let subbuf = &buf[buf_offset..];
1777 buf_offset += self.sock()?.send_with_flags(subbuf, flags)?;
1778 Ok(())
1779 })?;
1780 vm.check_signals()?;
1781 }
1782 Ok(())
1783 }
1784
1785 #[pymethod]
1786 fn sendto(
1787 &self,
1788 bytes: ArgBytesLike,
1789 arg2: PyObjectRef,
1790 arg3: OptionalArg<PyObjectRef>,
1791 vm: &VirtualMachine,
1792 ) -> Result<usize, IoOrPyException> {
1793 let (flags, address) = match arg3 {
1795 OptionalArg::Present(arg3) => {
1796 let int = arg2
1798 .try_index_opt(vm)
1799 .unwrap_or_else(|| Err(vm.new_type_error("an integer is required")))?;
1800 let flags = int.try_to_primitive::<i32>(vm)?;
1801 (flags, arg3)
1802 }
1803 OptionalArg::Missing => (0, arg2),
1804 };
1805 let addr = self.extract_address(address, "sendto", vm)?;
1806 let buf = bytes.borrow_buf();
1807 let buf = &*buf;
1808 self.sock_op(vm, SelectKind::Write, || {
1809 self.sock()?.send_to_with_flags(buf, &addr, flags)
1810 })
1811 }
1812
1813 #[cfg(all(unix, not(target_os = "redox")))]
1814 #[pymethod]
1815 fn sendmsg(
1816 &self,
1817 buffers: Vec<ArgBytesLike>,
1818 ancdata: OptionalArg,
1819 flags: OptionalArg<i32>,
1820 addr: OptionalOption,
1821 vm: &VirtualMachine,
1822 ) -> PyResult<usize> {
1823 let flags = flags.unwrap_or(0);
1824 let mut msg = socket2::MsgHdr::new();
1825
1826 let sockaddr;
1827 if let Some(addr) = addr.flatten() {
1828 sockaddr = self
1829 .extract_address(addr, "sendmsg", vm)
1830 .map_err(|e| e.into_pyexception(vm))?;
1831 msg = msg.with_addr(&sockaddr);
1832 }
1833
1834 let buffers = buffers
1835 .iter()
1836 .map(|buf| buf.borrow_buf())
1837 .collect::<Vec<_>>();
1838 let buffers = buffers
1839 .iter()
1840 .map(|buf| io::IoSlice::new(buf))
1841 .collect::<Vec<_>>();
1842 msg = msg.with_buffers(&buffers);
1843
1844 let control_buf;
1845 if let OptionalArg::Present(ancdata) = ancdata {
1846 let cmsgs = vm.extract_elements_with(
1847 &ancdata,
1848 |obj| -> PyResult<(i32, i32, ArgBytesLike)> {
1849 let seq: Vec<PyObjectRef> = obj.try_into_value(vm)?;
1850 let [lvl, typ, data]: [PyObjectRef; 3] = seq
1851 .try_into()
1852 .map_err(|_| vm.new_type_error("expected a sequence of length 3"))?;
1853 Ok((
1854 lvl.try_into_value(vm)?,
1855 typ.try_into_value(vm)?,
1856 data.try_into_value(vm)?,
1857 ))
1858 },
1859 )?;
1860 control_buf = Self::pack_cmsgs_to_send(&cmsgs, vm)?;
1861 if !control_buf.is_empty() {
1862 msg = msg.with_control(&control_buf);
1863 }
1864 }
1865
1866 self.sock_op(vm, SelectKind::Write, || {
1867 let sock = self.sock()?;
1868 sock.sendmsg(&msg, flags)
1869 })
1870 .map_err(|e| e.into_pyexception(vm))
1871 }
1872
1873 #[cfg(target_os = "linux")]
1877 #[pymethod]
1878 fn sendmsg_afalg(&self, args: SendmsgAfalgArgs, vm: &VirtualMachine) -> PyResult<usize> {
1879 let msg = args.msg;
1880 let op = args.op;
1881 let iv = args.iv;
1882 let flags = args.flags;
1883
1884 let assoclen: Option<u32> = match args.assoclen {
1886 OptionalArg::Present(val) if val < 0 => {
1887 return Err(vm.new_type_error("assoclen must be non-negative"));
1888 }
1889 OptionalArg::Present(val) => Some(val as u32),
1890 OptionalArg::Missing => None,
1891 };
1892
1893 let mut control_buf = Vec::new();
1895
1896 {
1898 let op_bytes = op.to_ne_bytes();
1899 let space =
1900 unsafe { libc::CMSG_SPACE(core::mem::size_of::<u32>() as u32) } as usize;
1901 let old_len = control_buf.len();
1902 control_buf.resize(old_len + space, 0u8);
1903
1904 let cmsg = control_buf[old_len..].as_mut_ptr() as *mut libc::cmsghdr;
1905 unsafe {
1906 (*cmsg).cmsg_len = libc::CMSG_LEN(core::mem::size_of::<u32>() as u32) as _;
1907 (*cmsg).cmsg_level = libc::SOL_ALG;
1908 (*cmsg).cmsg_type = libc::ALG_SET_OP;
1909 let data = libc::CMSG_DATA(cmsg);
1910 core::ptr::copy_nonoverlapping(op_bytes.as_ptr(), data, op_bytes.len());
1911 }
1912 }
1913
1914 if let Some(iv_data) = iv {
1916 let iv_bytes = iv_data.borrow_buf();
1917 let iv_struct_size = 4 + iv_bytes.len();
1919 let space = unsafe { libc::CMSG_SPACE(iv_struct_size as u32) } as usize;
1920 let old_len = control_buf.len();
1921 control_buf.resize(old_len + space, 0u8);
1922
1923 let cmsg = control_buf[old_len..].as_mut_ptr() as *mut libc::cmsghdr;
1924 unsafe {
1925 (*cmsg).cmsg_len = libc::CMSG_LEN(iv_struct_size as u32) as _;
1926 (*cmsg).cmsg_level = libc::SOL_ALG;
1927 (*cmsg).cmsg_type = libc::ALG_SET_IV;
1928 let data = libc::CMSG_DATA(cmsg);
1929 let ivlen = (iv_bytes.len() as u32).to_ne_bytes();
1931 core::ptr::copy_nonoverlapping(ivlen.as_ptr(), data, 4);
1932 core::ptr::copy_nonoverlapping(iv_bytes.as_ptr(), data.add(4), iv_bytes.len());
1934 }
1935 }
1936
1937 if let Some(assoclen_val) = assoclen {
1939 let assoclen_bytes = assoclen_val.to_ne_bytes();
1940 let space =
1941 unsafe { libc::CMSG_SPACE(core::mem::size_of::<u32>() as u32) } as usize;
1942 let old_len = control_buf.len();
1943 control_buf.resize(old_len + space, 0u8);
1944
1945 let cmsg = control_buf[old_len..].as_mut_ptr() as *mut libc::cmsghdr;
1946 unsafe {
1947 (*cmsg).cmsg_len = libc::CMSG_LEN(core::mem::size_of::<u32>() as u32) as _;
1948 (*cmsg).cmsg_level = libc::SOL_ALG;
1949 (*cmsg).cmsg_type = libc::ALG_SET_AEAD_ASSOCLEN;
1950 let data = libc::CMSG_DATA(cmsg);
1951 core::ptr::copy_nonoverlapping(
1952 assoclen_bytes.as_ptr(),
1953 data,
1954 assoclen_bytes.len(),
1955 );
1956 }
1957 }
1958
1959 let buffers = msg.iter().map(|buf| buf.borrow_buf()).collect::<Vec<_>>();
1961 let iovecs: Vec<libc::iovec> = buffers
1962 .iter()
1963 .map(|buf| libc::iovec {
1964 iov_base: buf.as_ptr() as *mut _,
1965 iov_len: buf.len(),
1966 })
1967 .collect();
1968
1969 let mut msghdr: libc::msghdr = unsafe { core::mem::zeroed() };
1971 msghdr.msg_iov = iovecs.as_ptr() as *mut _;
1972 msghdr.msg_iovlen = iovecs.len() as _;
1973 if !control_buf.is_empty() {
1974 msghdr.msg_control = control_buf.as_mut_ptr() as *mut _;
1975 msghdr.msg_controllen = control_buf.len() as _;
1976 }
1977
1978 self.sock_op(vm, SelectKind::Write, || {
1979 let sock = self.sock()?;
1980 let fd = sock_fileno(&sock);
1981 let ret = unsafe { libc::sendmsg(fd as libc::c_int, &msghdr, flags) };
1982 if ret < 0 {
1983 Err(io::Error::last_os_error())
1984 } else {
1985 Ok(ret as usize)
1986 }
1987 })
1988 .map_err(|e| e.into_pyexception(vm))
1989 }
1990
1991 #[cfg(all(unix, not(target_os = "redox")))]
1995 #[pymethod]
1996 fn recvmsg(
1997 &self,
1998 bufsize: isize,
1999 ancbufsize: OptionalArg<isize>,
2000 flags: OptionalArg<i32>,
2001 vm: &VirtualMachine,
2002 ) -> PyResult<PyTupleRef> {
2003 use core::mem::MaybeUninit;
2004
2005 if bufsize < 0 {
2006 return Err(vm.new_value_error("negative buffer size in recvmsg"));
2007 }
2008 let bufsize = bufsize as usize;
2009
2010 let ancbufsize = ancbufsize.unwrap_or(0);
2011 if ancbufsize < 0 {
2012 return Err(vm.new_value_error("negative ancillary buffer size in recvmsg"));
2013 }
2014 let ancbufsize = ancbufsize as usize;
2015 let flags = flags.unwrap_or(0);
2016
2017 let mut data_buf: Vec<MaybeUninit<u8>> = vec![MaybeUninit::uninit(); bufsize];
2019 let mut anc_buf: Vec<MaybeUninit<u8>> = vec![MaybeUninit::uninit(); ancbufsize];
2020 let mut addr_storage: libc::sockaddr_storage = unsafe { core::mem::zeroed() };
2021
2022 let mut iov = [libc::iovec {
2024 iov_base: data_buf.as_mut_ptr().cast(),
2025 iov_len: bufsize,
2026 }];
2027
2028 let mut msg: libc::msghdr = unsafe { core::mem::zeroed() };
2030 msg.msg_name = (&mut addr_storage as *mut libc::sockaddr_storage).cast();
2031 msg.msg_namelen = core::mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
2032 msg.msg_iov = iov.as_mut_ptr();
2033 msg.msg_iovlen = 1;
2034 if ancbufsize > 0 {
2035 msg.msg_control = anc_buf.as_mut_ptr().cast();
2036 msg.msg_controllen = ancbufsize as _;
2037 }
2038
2039 let n = self
2040 .sock_op(vm, SelectKind::Read, || {
2041 let sock = self.sock()?;
2042 let fd = sock_fileno(&sock);
2043 let ret = unsafe { libc::recvmsg(fd as libc::c_int, &mut msg, flags) };
2044 if ret < 0 {
2045 Err(io::Error::last_os_error())
2046 } else {
2047 Ok(ret as usize)
2048 }
2049 })
2050 .map_err(|e| e.into_pyexception(vm))?;
2051
2052 let data = unsafe {
2054 data_buf.set_len(n);
2055 core::mem::transmute::<Vec<MaybeUninit<u8>>, Vec<u8>>(data_buf)
2056 };
2057
2058 let ancdata = Self::parse_ancillary_data(&msg, vm)?;
2060
2061 let address = if msg.msg_namelen > 0 {
2063 let storage: socket2::SockAddrStorage =
2064 unsafe { core::mem::transmute(addr_storage) };
2065 let addr = unsafe { socket2::SockAddr::new(storage, msg.msg_namelen) };
2066 get_addr_tuple(&addr, vm)
2067 } else {
2068 vm.ctx.none()
2069 };
2070
2071 Ok(vm.ctx.new_tuple(vec![
2072 vm.ctx.new_bytes(data).into(),
2073 ancdata,
2074 vm.ctx.new_int(msg.msg_flags).into(),
2075 address,
2076 ]))
2077 }
2078
2079 #[cfg(all(unix, not(target_os = "redox")))]
2081 fn parse_ancillary_data(msg: &libc::msghdr, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
2082 let mut result = Vec::new();
2083
2084 let ctrl_buf = msg.msg_control as *const u8;
2086 let ctrl_end = unsafe { ctrl_buf.add(msg.msg_controllen as _) };
2087
2088 let mut cmsg: *mut libc::cmsghdr = unsafe { libc::CMSG_FIRSTHDR(msg) };
2089 while !cmsg.is_null() {
2090 let cmsg_ref = unsafe { &*cmsg };
2091 let data_ptr = unsafe { libc::CMSG_DATA(cmsg) };
2092
2093 let data_len_from_cmsg =
2095 cmsg_ref.cmsg_len as usize - (data_ptr as usize - cmsg as usize);
2096 let available = ctrl_end as usize - data_ptr as usize;
2097 let data_len = data_len_from_cmsg.min(available);
2098
2099 let data = unsafe { core::slice::from_raw_parts(data_ptr, data_len) };
2100
2101 let tuple = vm.ctx.new_tuple(vec![
2102 vm.ctx.new_int(cmsg_ref.cmsg_level).into(),
2103 vm.ctx.new_int(cmsg_ref.cmsg_type).into(),
2104 vm.ctx.new_bytes(data.to_vec()).into(),
2105 ]);
2106
2107 result.push(tuple.into());
2108
2109 cmsg = unsafe { libc::CMSG_NXTHDR(msg, cmsg) };
2110 }
2111
2112 Ok(vm.ctx.new_list(result).into())
2113 }
2114
2115 #[cfg(all(unix, not(target_os = "redox")))]
2117 fn pack_cmsgs_to_send(
2118 cmsgs: &[(i32, i32, ArgBytesLike)],
2119 vm: &VirtualMachine,
2120 ) -> PyResult<Vec<u8>> {
2121 use core::{mem, ptr};
2122
2123 if cmsgs.is_empty() {
2124 return Ok(vec![]);
2125 }
2126
2127 let capacity = cmsgs
2128 .iter()
2129 .map(|(_, _, buf)| buf.len())
2130 .try_fold(0, |sum, len| {
2131 let space = checked_cmsg_space(len).ok_or_else(|| {
2132 vm.new_os_error("ancillary data item too large".to_owned())
2133 })?;
2134 usize::checked_add(sum, space)
2135 .ok_or_else(|| vm.new_os_error("too much ancillary data".to_owned()))
2136 })?;
2137
2138 let mut cmsg_buffer = vec![0u8; capacity];
2139
2140 let mut mhdr = unsafe { mem::zeroed::<libc::msghdr>() };
2142 mhdr.msg_control = cmsg_buffer.as_mut_ptr().cast();
2143 mhdr.msg_controllen = capacity as _;
2144
2145 let mut pmhdr: *mut libc::cmsghdr = unsafe { libc::CMSG_FIRSTHDR(&mhdr) };
2146 for (lvl, typ, buf) in cmsgs {
2147 if pmhdr.is_null() {
2148 return Err(vm.new_runtime_error(
2149 "unexpected NULL result from CMSG_FIRSTHDR/CMSG_NXTHDR",
2150 ));
2151 }
2152 let data = &*buf.borrow_buf();
2153 assert_eq!(data.len(), buf.len());
2154 unsafe {
2157 (*pmhdr).cmsg_level = *lvl;
2158 (*pmhdr).cmsg_type = *typ;
2159 (*pmhdr).cmsg_len = libc::CMSG_LEN(data.len() as _) as _;
2160 ptr::copy_nonoverlapping(data.as_ptr(), libc::CMSG_DATA(pmhdr), data.len());
2161 }
2162
2163 pmhdr = unsafe { libc::CMSG_NXTHDR(&mhdr, pmhdr) };
2165 }
2166
2167 Ok(cmsg_buffer)
2168 }
2169
2170 #[pymethod]
2171 fn close(&self) -> io::Result<()> {
2172 let sock = self.sock.write().take();
2173 if let Some(sock) = sock {
2174 close_inner(into_sock_fileno(sock))?;
2175 }
2176 Ok(())
2177 }
2178
2179 #[pymethod]
2180 #[inline]
2181 fn detach(&self) -> i64 {
2182 let sock = self.sock.write().take();
2183 sock.map_or(INVALID_SOCKET as i64, |s| into_sock_fileno(s) as i64)
2184 }
2185
2186 #[pymethod]
2187 fn fileno(&self) -> i64 {
2188 self.sock
2189 .read()
2190 .as_ref()
2191 .map_or(INVALID_SOCKET as i64, |s| sock_fileno(s) as i64)
2192 }
2193
2194 #[pymethod]
2195 fn getsockname(&self, vm: &VirtualMachine) -> std::io::Result<PyObjectRef> {
2196 let addr = self.sock()?.local_addr()?;
2197
2198 Ok(get_addr_tuple(&addr, vm))
2199 }
2200
2201 #[pymethod]
2202 fn getpeername(&self, vm: &VirtualMachine) -> std::io::Result<PyObjectRef> {
2203 let addr = self.sock()?.peer_addr()?;
2204
2205 Ok(get_addr_tuple(&addr, vm))
2206 }
2207
2208 #[pymethod]
2209 fn gettimeout(&self) -> Option<f64> {
2210 let timeout = self.timeout.load();
2211 if timeout >= 0.0 { Some(timeout) } else { None }
2212 }
2213
2214 #[pymethod]
2215 fn setblocking(&self, block: bool) -> io::Result<()> {
2216 self.timeout.store(if block { -1.0 } else { 0.0 });
2217 self.sock()?.set_nonblocking(!block)
2218 }
2219
2220 #[pymethod]
2221 fn getblocking(&self) -> bool {
2222 self.timeout.load() != 0.0
2223 }
2224
2225 #[pymethod]
2226 fn settimeout(&self, timeout: Option<ArgIntoFloat>, vm: &VirtualMachine) -> PyResult<()> {
2227 let timeout = match timeout {
2228 Some(t) => {
2229 let f = t.into_float();
2230 if f.is_nan() {
2231 return Err(vm.new_value_error("Invalid value NaN (not a number)"));
2232 }
2233 if f < 0.0 || !f.is_finite() {
2234 return Err(vm.new_value_error("Timeout value out of range"));
2235 }
2236 Some(f)
2237 }
2238 None => None,
2239 };
2240 self.timeout.store(timeout.unwrap_or(-1.0));
2241 self.sock()
2244 .map_err(|e| e.into_pyexception(vm))?
2245 .set_nonblocking(timeout.is_some())
2246 .map_err(|e| e.into_pyexception(vm))
2247 }
2248
2249 #[pymethod]
2250 fn getsockopt(
2251 &self,
2252 level: i32,
2253 name: i32,
2254 buflen: OptionalArg<i32>,
2255 vm: &VirtualMachine,
2256 ) -> Result<PyObjectRef, IoOrPyException> {
2257 let sock = self.sock()?;
2258 let fd = sock_fileno(&sock);
2259 let buflen = buflen.unwrap_or(0);
2260 if buflen == 0 {
2261 let mut flag: libc::c_int = 0;
2262 let mut flagsize = core::mem::size_of::<libc::c_int>() as _;
2263 let ret = unsafe {
2264 c::getsockopt(
2265 fd as _,
2266 level,
2267 name,
2268 &mut flag as *mut libc::c_int as *mut _,
2269 &mut flagsize,
2270 )
2271 };
2272 if ret < 0 {
2273 return Err(crate::common::os::errno_io_error().into());
2274 }
2275 Ok(vm.ctx.new_int(flag).into())
2276 } else {
2277 if buflen <= 0 || buflen > 1024 {
2278 return Err(vm
2279 .new_os_error("getsockopt buflen out of range".to_owned())
2280 .into());
2281 }
2282 let mut buf = vec![0u8; buflen as usize];
2283 let mut buflen = buflen as _;
2284 let ret = unsafe {
2285 c::getsockopt(
2286 fd as _,
2287 level,
2288 name,
2289 buf.as_mut_ptr() as *mut _,
2290 &mut buflen,
2291 )
2292 };
2293 if ret < 0 {
2294 return Err(crate::common::os::errno_io_error().into());
2295 }
2296 buf.truncate(buflen as usize);
2297 Ok(vm.ctx.new_bytes(buf).into())
2298 }
2299 }
2300
2301 #[pymethod]
2302 fn setsockopt(
2303 &self,
2304 level: i32,
2305 name: i32,
2306 value: Option<Either<ArgBytesLike, i32>>,
2307 optlen: OptionalArg<u32>,
2308 vm: &VirtualMachine,
2309 ) -> Result<(), IoOrPyException> {
2310 let sock = self.sock()?;
2311 let fd = sock_fileno(&sock);
2312 let ret = match (value, optlen) {
2313 (Some(Either::A(b)), OptionalArg::Missing) => b.with_ref(|b| unsafe {
2314 c::setsockopt(fd as _, level, name, b.as_ptr() as *const _, b.len() as _)
2315 }),
2316 (Some(Either::B(ref val)), OptionalArg::Missing) => unsafe {
2317 c::setsockopt(
2318 fd as _,
2319 level,
2320 name,
2321 val as *const i32 as *const _,
2322 core::mem::size_of::<i32>() as _,
2323 )
2324 },
2325 (None, OptionalArg::Present(optlen)) => unsafe {
2326 c::setsockopt(fd as _, level, name, core::ptr::null(), optlen as _)
2327 },
2328 _ => {
2329 return Err(vm
2330 .new_type_error("expected the value arg xor the optlen arg")
2331 .into());
2332 }
2333 };
2334 if ret < 0 {
2335 Err(crate::common::os::errno_io_error().into())
2336 } else {
2337 Ok(())
2338 }
2339 }
2340
2341 #[pymethod]
2342 fn shutdown(&self, how: i32, vm: &VirtualMachine) -> Result<(), IoOrPyException> {
2343 let how = match how {
2344 c::SHUT_RD => Shutdown::Read,
2345 c::SHUT_WR => Shutdown::Write,
2346 c::SHUT_RDWR => Shutdown::Both,
2347 _ => {
2348 return Err(vm
2349 .new_value_error("`how` must be SHUT_RD, SHUT_WR, or SHUT_RDWR")
2350 .into());
2351 }
2352 };
2353 Ok(self.sock()?.shutdown(how)?)
2354 }
2355
2356 #[cfg(windows)]
2357 fn wsa_error() -> io::Error {
2358 io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() })
2359 }
2360
2361 #[cfg(windows)]
2362 #[pymethod]
2363 fn ioctl(
2364 &self,
2365 cmd: PyObjectRef,
2366 option: PyObjectRef,
2367 vm: &VirtualMachine,
2368 ) -> Result<u32, IoOrPyException> {
2369 use crate::vm::builtins::PyInt;
2370 use crate::vm::convert::TryFromObject;
2371
2372 let sock = self.sock()?;
2373 let fd = sock_fileno(&sock);
2374 let mut recv: u32 = 0;
2375
2376 let cmd_int = cmd
2378 .downcast::<PyInt>()
2379 .map_err(|_| vm.new_type_error("an integer is required"))?;
2380 let cmd_val = cmd_int.as_bigint();
2381 let cmd: u32 = cmd_val
2382 .to_u32()
2383 .ok_or_else(|| vm.new_value_error(format!("invalid ioctl command {}", cmd_val)))?;
2384
2385 match cmd {
2386 c::SIO_RCVALL | c::SIO_LOOPBACK_FAST_PATH => {
2387 if vm.is_none(&option) {
2389 return Err(vm
2390 .new_type_error("an integer is required (got type NoneType)")
2391 .into());
2392 }
2393 let option_val: u32 = TryFromObject::try_from_object(vm, option)?;
2394 let ret = unsafe {
2395 c::WSAIoctl(
2396 fd as _,
2397 cmd,
2398 &option_val as *const u32 as *const _,
2399 core::mem::size_of::<u32>() as u32,
2400 core::ptr::null_mut(),
2401 0,
2402 &mut recv,
2403 core::ptr::null_mut(),
2404 None,
2405 )
2406 };
2407 if ret == c::SOCKET_ERROR {
2408 return Err(Self::wsa_error().into());
2409 }
2410 Ok(recv)
2411 }
2412 c::SIO_KEEPALIVE_VALS => {
2413 let tuple: PyTupleRef = option
2414 .downcast()
2415 .map_err(|_| vm.new_type_error("SIO_KEEPALIVE_VALS requires a tuple"))?;
2416 if tuple.len() != 3 {
2417 return Err(vm
2418 .new_type_error(
2419 "SIO_KEEPALIVE_VALS requires (onoff, keepalivetime, keepaliveinterval)",
2420 )
2421 .into());
2422 }
2423
2424 #[repr(C)]
2425 struct TcpKeepalive {
2426 onoff: u32,
2427 keepalivetime: u32,
2428 keepaliveinterval: u32,
2429 }
2430
2431 let ka = TcpKeepalive {
2432 onoff: TryFromObject::try_from_object(vm, tuple[0].clone())?,
2433 keepalivetime: TryFromObject::try_from_object(vm, tuple[1].clone())?,
2434 keepaliveinterval: TryFromObject::try_from_object(vm, tuple[2].clone())?,
2435 };
2436
2437 let ret = unsafe {
2438 c::WSAIoctl(
2439 fd as _,
2440 cmd,
2441 &ka as *const TcpKeepalive as *const _,
2442 core::mem::size_of::<TcpKeepalive>() as u32,
2443 core::ptr::null_mut(),
2444 0,
2445 &mut recv,
2446 core::ptr::null_mut(),
2447 None,
2448 )
2449 };
2450 if ret == c::SOCKET_ERROR {
2451 return Err(Self::wsa_error().into());
2452 }
2453 Ok(recv)
2454 }
2455 _ => Err(vm
2456 .new_value_error(format!("invalid ioctl command {}", cmd))
2457 .into()),
2458 }
2459 }
2460
2461 #[cfg(windows)]
2462 #[pymethod]
2463 fn share(&self, process_id: u32, _vm: &VirtualMachine) -> Result<Vec<u8>, IoOrPyException> {
2464 let sock = self.sock()?;
2465 let fd = sock_fileno(&sock);
2466
2467 let mut info: MaybeUninit<c::WSAPROTOCOL_INFOW> = MaybeUninit::uninit();
2468
2469 let ret = unsafe { c::WSADuplicateSocketW(fd as _, process_id, info.as_mut_ptr()) };
2470
2471 if ret == c::SOCKET_ERROR {
2472 return Err(Self::wsa_error().into());
2473 }
2474
2475 let info = unsafe { info.assume_init() };
2476 let bytes = unsafe {
2477 core::slice::from_raw_parts(
2478 &info as *const c::WSAPROTOCOL_INFOW as *const u8,
2479 core::mem::size_of::<c::WSAPROTOCOL_INFOW>(),
2480 )
2481 };
2482
2483 Ok(bytes.to_vec())
2484 }
2485
2486 #[pygetset(name = "type")]
2487 fn kind(&self) -> i32 {
2488 self.kind.load()
2489 }
2490
2491 #[pygetset]
2492 fn family(&self) -> i32 {
2493 self.family.load()
2494 }
2495
2496 #[pygetset]
2497 fn proto(&self) -> i32 {
2498 self.proto.load()
2499 }
2500 }
2501
2502 struct Address {
2503 host: PyUtf8StrRef,
2504 port: u16,
2505 }
2506
2507 impl ToSocketAddrs for Address {
2508 type Iter = alloc::vec::IntoIter<SocketAddr>;
2509 fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
2510 (self.host.as_str(), self.port).to_socket_addrs()
2511 }
2512 }
2513
2514 impl TryFromObject for Address {
2515 fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
2516 let tuple = PyTupleRef::try_from_object(vm, obj)?;
2517 if tuple.len() != 2 {
2518 Err(vm.new_type_error("Address tuple should have only 2 values"))
2519 } else {
2520 Self::from_tuple(&tuple, vm)
2521 }
2522 }
2523 }
2524
2525 impl Address {
2526 fn from_tuple(tuple: &[PyObjectRef], vm: &VirtualMachine) -> PyResult<Self> {
2527 let host = PyStrRef::try_from_object(vm, tuple[0].clone())?;
2528 let host = host.try_into_utf8(vm)?;
2529 let port = i32::try_from_borrowed_object(vm, &tuple[1])?;
2530 let port = port
2531 .to_u16()
2532 .ok_or_else(|| vm.new_overflow_error("port must be 0-65535."))?;
2533 Ok(Self { host, port })
2534 }
2535
2536 fn from_tuple_ipv6(
2537 tuple: &[PyObjectRef],
2538 vm: &VirtualMachine,
2539 ) -> PyResult<(Self, u32, u32)> {
2540 let addr = Self::from_tuple(tuple, vm)?;
2541 let flowinfo = tuple
2542 .get(2)
2543 .map(|obj| u32::try_from_borrowed_object(vm, obj))
2544 .transpose()?
2545 .unwrap_or(0);
2546 let scopeid = tuple
2547 .get(3)
2548 .map(|obj| u32::try_from_borrowed_object(vm, obj))
2549 .transpose()?
2550 .unwrap_or(0);
2551 if flowinfo > 0xfffff {
2552 return Err(vm.new_overflow_error("flowinfo must be 0-1048575."));
2553 }
2554 Ok((addr, flowinfo, scopeid))
2555 }
2556 }
2557
2558 fn get_ip_addr_tuple(addr: &SocketAddr, vm: &VirtualMachine) -> PyObjectRef {
2559 match addr {
2560 SocketAddr::V4(addr) => (addr.ip().to_string(), addr.port()).to_pyobject(vm),
2561 SocketAddr::V6(addr) => (
2562 addr.ip().to_string(),
2563 addr.port(),
2564 addr.flowinfo(),
2565 addr.scope_id(),
2566 )
2567 .to_pyobject(vm),
2568 }
2569 }
2570
2571 fn get_addr_tuple(addr: &socket2::SockAddr, vm: &VirtualMachine) -> PyObjectRef {
2572 if let Some(addr) = addr.as_socket() {
2573 return get_ip_addr_tuple(&addr, vm);
2574 }
2575 #[cfg(unix)]
2576 if addr.is_unix() {
2577 use std::os::unix::ffi::OsStrExt;
2578 if let Some(abstractpath) = addr.as_abstract_namespace() {
2579 return vm.ctx.new_bytes([b"\0", abstractpath].concat()).into();
2580 }
2581 let path = ffi::OsStr::as_bytes(addr.as_pathname().unwrap_or("".as_ref()).as_ref());
2583 let nul_pos = memchr::memchr(b'\0', path).unwrap_or(path.len());
2584 let path = ffi::OsStr::from_bytes(&path[..nul_pos]);
2585 return vm.fsdecode(path).into();
2586 }
2587 #[cfg(target_os = "linux")]
2588 {
2589 let family = addr.family();
2590 if family == libc::AF_CAN as libc::sa_family_t {
2591 let can_addr = unsafe { &*(addr.as_ptr() as *const libc::sockaddr_can) };
2593 let ifindex = can_addr.can_ifindex;
2594 let ifname = if ifindex == 0 {
2595 String::new()
2596 } else {
2597 let mut buf = [0u8; libc::IF_NAMESIZE];
2598 let ret = unsafe {
2599 libc::if_indextoname(
2600 ifindex as libc::c_uint,
2601 buf.as_mut_ptr() as *mut libc::c_char,
2602 )
2603 };
2604 if ret.is_null() {
2605 String::new()
2606 } else {
2607 let nul_pos = memchr::memchr(b'\0', &buf).unwrap_or(buf.len());
2608 String::from_utf8_lossy(&buf[..nul_pos]).into_owned()
2609 }
2610 };
2611 return vm.ctx.new_tuple(vec![vm.ctx.new_str(ifname).into()]).into();
2612 }
2613 if family == libc::AF_ALG as libc::sa_family_t {
2614 let alg_addr = unsafe { &*(addr.as_ptr() as *const libc::sockaddr_alg) };
2616 let type_bytes = &alg_addr.salg_type;
2617 let name_bytes = &alg_addr.salg_name;
2618 let type_nul = memchr::memchr(b'\0', type_bytes).unwrap_or(type_bytes.len());
2619 let name_nul = memchr::memchr(b'\0', name_bytes).unwrap_or(name_bytes.len());
2620 let type_str = String::from_utf8_lossy(&type_bytes[..type_nul]).into_owned();
2621 let name_str = String::from_utf8_lossy(&name_bytes[..name_nul]).into_owned();
2622 return vm
2623 .ctx
2624 .new_tuple(vec![
2625 vm.ctx.new_str(type_str).into(),
2626 vm.ctx.new_str(name_str).into(),
2627 ])
2628 .into();
2629 }
2630 }
2631 (String::new(), 0).to_pyobject(vm)
2633 }
2634
2635 #[pyfunction]
2636 fn gethostname(vm: &VirtualMachine) -> PyResult<PyStrRef> {
2637 gethostname::gethostname()
2638 .into_string()
2639 .map(|hostname| vm.ctx.new_str(hostname))
2640 .map_err(|err| vm.new_os_error(err.into_string().unwrap()))
2641 }
2642
2643 #[cfg(all(unix, not(target_os = "redox")))]
2644 #[pyfunction]
2645 fn sethostname(hostname: PyUtf8StrRef) -> nix::Result<()> {
2646 nix::unistd::sethostname(hostname.as_str())
2647 }
2648
2649 #[pyfunction]
2650 fn inet_aton(ip_string: PyUtf8StrRef, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
2651 ip_string
2652 .as_str()
2653 .parse::<Ipv4Addr>()
2654 .map(|ip_addr| Vec::<u8>::from(ip_addr.octets()))
2655 .map_err(|_| {
2656 vm.new_os_error("illegal IP address string passed to inet_aton".to_owned())
2657 })
2658 }
2659
2660 #[pyfunction]
2661 fn inet_ntoa(packed_ip: ArgBytesLike, vm: &VirtualMachine) -> PyResult<PyStrRef> {
2662 let packed_ip = packed_ip.borrow_buf();
2663 let packed_ip = <&[u8; 4]>::try_from(&*packed_ip)
2664 .map_err(|_| vm.new_os_error("packed IP wrong length for inet_ntoa".to_owned()))?;
2665 Ok(vm.ctx.new_str(Ipv4Addr::from(*packed_ip).to_string()))
2666 }
2667
2668 fn cstr_opt_as_ptr(x: &OptionalArg<ffi::CString>) -> *const libc::c_char {
2669 x.as_ref().map_or_else(core::ptr::null, |s| s.as_ptr())
2670 }
2671
2672 #[pyfunction]
2673 fn getservbyname(
2674 servicename: PyStrRef,
2675 protocolname: OptionalArg<PyStrRef>,
2676 vm: &VirtualMachine,
2677 ) -> PyResult<u16> {
2678 let cstr_name = servicename.to_cstring(vm)?;
2679 let cstr_proto = protocolname
2680 .as_ref()
2681 .map(|s| s.to_cstring(vm))
2682 .transpose()?;
2683 let cstr_proto = cstr_opt_as_ptr(&cstr_proto);
2684 let serv = unsafe { c::getservbyname(cstr_name.as_ptr() as _, cstr_proto as _) };
2685 if serv.is_null() {
2686 return Err(vm.new_os_error("service/proto not found".to_owned()));
2687 }
2688 let port = unsafe { (*serv).s_port };
2689 Ok(u16::from_be(port as u16))
2690 }
2691
2692 #[pyfunction]
2693 fn getservbyport(
2694 port: i32,
2695 protocolname: OptionalArg<PyStrRef>,
2696 vm: &VirtualMachine,
2697 ) -> PyResult<String> {
2698 let port = port
2699 .to_u16()
2700 .ok_or_else(|| vm.new_overflow_error("getservbyport: port must be 0-65535."))?;
2701 let cstr_proto = protocolname
2702 .as_ref()
2703 .map(|s| s.to_cstring(vm))
2704 .transpose()?;
2705 let cstr_proto = cstr_opt_as_ptr(&cstr_proto);
2706 let serv = unsafe { c::getservbyport(port.to_be() as _, cstr_proto as _) };
2707 if serv.is_null() {
2708 return Err(vm.new_os_error("port/proto not found".to_owned()));
2709 }
2710 let s = unsafe { ffi::CStr::from_ptr((*serv).s_name as _) };
2711 Ok(s.to_string_lossy().into_owned())
2712 }
2713
2714 unsafe fn slice_as_uninit<T>(v: &mut [T]) -> &mut [MaybeUninit<T>] {
2715 unsafe { &mut *(v as *mut [T] as *mut [MaybeUninit<T>]) }
2716 }
2717
2718 enum IoOrPyException {
2719 Timeout,
2720 Py(PyBaseExceptionRef),
2721 Io(io::Error),
2722 }
2723 impl From<PyBaseExceptionRef> for IoOrPyException {
2724 fn from(exc: PyBaseExceptionRef) -> Self {
2725 Self::Py(exc)
2726 }
2727 }
2728 impl From<PyRef<PyOSError>> for IoOrPyException {
2729 fn from(exc: PyRef<PyOSError>) -> Self {
2730 Self::Py(exc.upcast())
2731 }
2732 }
2733 impl From<io::Error> for IoOrPyException {
2734 fn from(err: io::Error) -> Self {
2735 Self::Io(err)
2736 }
2737 }
2738 impl IoOrPyException {
2739 fn errno(self) -> PyResult<i32> {
2740 match self {
2741 Self::Timeout => Ok(errcode!(EWOULDBLOCK)),
2742 Self::Io(err) => Ok(err.posix_errno()),
2743 Self::Py(exc) => Err(exc),
2744 }
2745 }
2746 }
2747 impl IntoPyException for IoOrPyException {
2748 #[inline]
2749 fn into_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef {
2750 match self {
2751 Self::Timeout => timeout_error(vm).upcast(),
2752 Self::Py(exc) => exc,
2753 Self::Io(err) => err.into_pyexception(vm),
2754 }
2755 }
2756 }
2757
2758 #[derive(Copy, Clone)]
2759 pub(crate) enum SelectKind {
2760 Read,
2761 Write,
2762 Connect,
2763 }
2764
2765 pub(crate) fn sock_select(
2767 sock: &Socket,
2768 kind: SelectKind,
2769 interval: Option<Duration>,
2770 ) -> io::Result<bool> {
2771 #[cfg(unix)]
2772 {
2773 use nix::poll::*;
2774 use std::os::fd::AsFd;
2775 let events = match kind {
2776 SelectKind::Read => PollFlags::POLLIN,
2777 SelectKind::Write => PollFlags::POLLOUT,
2778 SelectKind::Connect => PollFlags::POLLOUT | PollFlags::POLLERR,
2779 };
2780 let mut pollfd = [PollFd::new(sock.as_fd(), events)];
2781 let timeout = match interval {
2782 Some(d) => d.try_into().unwrap_or(PollTimeout::MAX),
2783 None => PollTimeout::NONE,
2784 };
2785 let ret = poll(&mut pollfd, timeout)?;
2786 Ok(ret == 0)
2787 }
2788 #[cfg(windows)]
2789 {
2790 use crate::select;
2791
2792 let fd = sock_fileno(sock);
2793
2794 let mut reads = select::FdSet::new();
2795 let mut writes = select::FdSet::new();
2796 let mut errs = select::FdSet::new();
2797
2798 let fd = fd as usize;
2799 match kind {
2800 SelectKind::Read => reads.insert(fd),
2801 SelectKind::Write => writes.insert(fd),
2802 SelectKind::Connect => {
2803 writes.insert(fd);
2804 errs.insert(fd);
2805 }
2806 }
2807
2808 let mut interval = interval.map(|dur| select::timeval {
2809 tv_sec: dur.as_secs() as _,
2810 tv_usec: dur.subsec_micros() as _,
2811 });
2812
2813 select::select(
2814 fd as i32 + 1,
2815 &mut reads,
2816 &mut writes,
2817 &mut errs,
2818 interval.as_mut(),
2819 )
2820 .map(|ret| ret == 0)
2821 }
2822 }
2823
2824 #[derive(FromArgs)]
2825 struct GAIOptions {
2826 #[pyarg(positional)]
2827 host: Option<ArgStrOrBytesLike>,
2828 #[pyarg(positional)]
2829 port: Option<Either<ArgStrOrBytesLike, i32>>,
2830
2831 #[pyarg(positional, default = c::AF_UNSPEC)]
2832 family: i32,
2833 #[pyarg(positional, default = 0)]
2834 ty: i32,
2835 #[pyarg(positional, default = 0)]
2836 proto: i32,
2837 #[pyarg(positional, default = 0)]
2838 flags: i32,
2839 }
2840
2841 #[pyfunction]
2842 fn getaddrinfo(
2843 opts: GAIOptions,
2844 vm: &VirtualMachine,
2845 ) -> Result<Vec<PyObjectRef>, IoOrPyException> {
2846 let hints = dns_lookup::AddrInfoHints {
2847 socktype: opts.ty,
2848 protocol: opts.proto,
2849 address: opts.family,
2850 flags: opts.flags,
2851 };
2852
2853 let host_encoded: Option<String> = match opts.host.as_ref() {
2855 Some(ArgStrOrBytesLike::Str(s)) => {
2856 let encoded =
2857 vm.state
2858 .codec_registry
2859 .encode_text(s.to_owned(), "idna", None, vm)?;
2860 let host_str = core::str::from_utf8(encoded.as_bytes())
2861 .map_err(|_| vm.new_runtime_error("idna output is not utf8"))?;
2862 Some(host_str.to_owned())
2863 }
2864 Some(ArgStrOrBytesLike::Buf(b)) => {
2865 let bytes = b.borrow_buf();
2866 let host_str = core::str::from_utf8(&bytes)
2867 .map_err(|_| vm.new_unicode_decode_error("host bytes is not utf8"))?;
2868 Some(host_str.to_owned())
2869 }
2870 None => None,
2871 };
2872 let host = host_encoded.as_deref();
2873
2874 let port_encoded: Option<String> = match opts.port.as_ref() {
2876 Some(Either::A(sb)) => {
2877 let port_str = match sb {
2878 ArgStrOrBytesLike::Str(s) => {
2879 s.to_str()
2881 .ok_or_else(|| vm.new_unicode_encode_error("surrogates not allowed"))?
2882 .to_owned()
2883 }
2884 ArgStrOrBytesLike::Buf(b) => {
2885 let bytes = b.borrow_buf();
2887 core::str::from_utf8(&bytes)
2888 .map_err(|_| vm.new_unicode_decode_error("port is not utf8"))?
2889 .to_owned()
2890 }
2891 };
2892 Some(port_str)
2893 }
2894 Some(Either::B(i)) => Some(i.to_string()),
2895 None => None,
2896 };
2897 let port = port_encoded.as_deref();
2898
2899 let addrs = dns_lookup::getaddrinfo(host, port, Some(hints))
2900 .map_err(|err| convert_socket_error(vm, err, SocketError::GaiError))?;
2901
2902 let list = addrs
2903 .map(|ai| {
2904 ai.map(|ai| {
2905 vm.new_tuple((
2906 ai.address,
2907 ai.socktype,
2908 ai.protocol,
2909 ai.canonname,
2910 get_ip_addr_tuple(&ai.sockaddr, vm),
2911 ))
2912 .into()
2913 })
2914 })
2915 .collect::<io::Result<Vec<_>>>()?;
2916 Ok(list)
2917 }
2918
2919 #[pyfunction]
2920 fn gethostbyaddr(
2921 addr: PyUtf8StrRef,
2922 vm: &VirtualMachine,
2923 ) -> Result<(String, PyListRef, PyListRef), IoOrPyException> {
2924 let addr = get_addr(vm, addr, c::AF_UNSPEC)?;
2925 let (hostname, _) = dns_lookup::getnameinfo(&addr, 0)
2926 .map_err(|e| convert_socket_error(vm, e, SocketError::HError))?;
2927 Ok((
2928 hostname,
2929 vm.ctx.new_list(vec![]),
2930 vm.ctx
2931 .new_list(vec![vm.ctx.new_str(addr.ip().to_string()).into()]),
2932 ))
2933 }
2934
2935 #[pyfunction]
2936 fn gethostbyname(name: PyUtf8StrRef, vm: &VirtualMachine) -> Result<String, IoOrPyException> {
2937 let addr = get_addr(vm, name, c::AF_INET)?;
2938 match addr {
2939 SocketAddr::V4(ip) => Ok(ip.ip().to_string()),
2940 _ => unreachable!(),
2941 }
2942 }
2943
2944 #[pyfunction]
2945 fn gethostbyname_ex(
2946 name: PyUtf8StrRef,
2947 vm: &VirtualMachine,
2948 ) -> Result<(String, PyListRef, PyListRef), IoOrPyException> {
2949 let addr = get_addr(vm, name, c::AF_INET)?;
2950 let (hostname, _) = dns_lookup::getnameinfo(&addr, 0)
2951 .map_err(|e| convert_socket_error(vm, e, SocketError::HError))?;
2952 Ok((
2953 hostname,
2954 vm.ctx.new_list(vec![]),
2955 vm.ctx
2956 .new_list(vec![vm.ctx.new_str(addr.ip().to_string()).into()]),
2957 ))
2958 }
2959
2960 #[pyfunction]
2961 fn inet_pton(af_inet: i32, ip_string: PyUtf8StrRef, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
2962 static ERROR_MSG: &str = "illegal IP address string passed to inet_pton";
2963 let ip_addr = match af_inet {
2964 c::AF_INET => ip_string
2965 .as_str()
2966 .parse::<Ipv4Addr>()
2967 .map_err(|_| vm.new_os_error(ERROR_MSG.to_owned()))?
2968 .octets()
2969 .to_vec(),
2970 c::AF_INET6 => ip_string
2971 .as_str()
2972 .parse::<Ipv6Addr>()
2973 .map_err(|_| vm.new_os_error(ERROR_MSG.to_owned()))?
2974 .octets()
2975 .to_vec(),
2976 _ => return Err(vm.new_os_error("Address family not supported by protocol".to_owned())),
2977 };
2978 Ok(ip_addr)
2979 }
2980
2981 #[pyfunction]
2982 fn inet_ntop(af_inet: i32, packed_ip: ArgBytesLike, vm: &VirtualMachine) -> PyResult<String> {
2983 let packed_ip = packed_ip.borrow_buf();
2984 match af_inet {
2985 c::AF_INET => {
2986 let packed_ip = <&[u8; 4]>::try_from(&*packed_ip).map_err(|_| {
2987 vm.new_value_error("invalid length of packed IP address string")
2988 })?;
2989 Ok(Ipv4Addr::from(*packed_ip).to_string())
2990 }
2991 c::AF_INET6 => {
2992 let packed_ip = <&[u8; 16]>::try_from(&*packed_ip).map_err(|_| {
2993 vm.new_value_error("invalid length of packed IP address string")
2994 })?;
2995 Ok(get_ipv6_addr_str(Ipv6Addr::from(*packed_ip)))
2996 }
2997 _ => Err(vm.new_value_error(format!("unknown address family {af_inet}"))),
2998 }
2999 }
3000
3001 #[pyfunction]
3002 fn getprotobyname(name: PyStrRef, vm: &VirtualMachine) -> PyResult {
3003 let cstr = name.to_cstring(vm)?;
3004 let proto = unsafe { c::getprotobyname(cstr.as_ptr() as _) };
3005 if proto.is_null() {
3006 return Err(vm.new_os_error("protocol not found".to_owned()));
3007 }
3008 let num = unsafe { (*proto).p_proto };
3009 Ok(vm.ctx.new_int(num).into())
3010 }
3011
3012 #[pyfunction]
3013 fn getnameinfo(
3014 address: PyTupleRef,
3015 flags: i32,
3016 vm: &VirtualMachine,
3017 ) -> Result<(String, String), IoOrPyException> {
3018 match address.len() {
3019 2..=4 => {}
3020 _ => {
3021 return Err(vm.new_type_error("illegal sockaddr argument").into());
3022 }
3023 }
3024 let (addr, flowinfo, scopeid) = Address::from_tuple_ipv6(&address, vm)?;
3025 let hints = dns_lookup::AddrInfoHints {
3026 address: c::AF_UNSPEC,
3027 socktype: c::SOCK_DGRAM,
3028 flags: c::AI_NUMERICHOST,
3029 protocol: 0,
3030 };
3031 let service = addr.port.to_string();
3032 let host_str = addr.host.as_str();
3033 let mut res = dns_lookup::getaddrinfo(Some(host_str), Some(&service), Some(hints))
3034 .map_err(|e| convert_socket_error(vm, e, SocketError::GaiError))?
3035 .filter_map(Result::ok);
3036 let mut ainfo = res.next().unwrap();
3037 if res.next().is_some() {
3038 return Err(vm
3039 .new_os_error("sockaddr resolved to multiple addresses".to_owned())
3040 .into());
3041 }
3042 match &mut ainfo.sockaddr {
3043 SocketAddr::V4(_) => {
3044 if address.len() != 2 {
3045 return Err(vm
3046 .new_os_error("IPv4 sockaddr must be 2 tuple".to_owned())
3047 .into());
3048 }
3049 }
3050 SocketAddr::V6(addr) => {
3051 addr.set_flowinfo(flowinfo);
3052 addr.set_scope_id(scopeid);
3053 }
3054 }
3055 dns_lookup::getnameinfo(&ainfo.sockaddr, flags)
3056 .map_err(|e| convert_socket_error(vm, e, SocketError::GaiError))
3057 }
3058
3059 #[cfg(unix)]
3060 #[pyfunction]
3061 fn socketpair(
3062 family: OptionalArg<i32>,
3063 socket_kind: OptionalArg<i32>,
3064 proto: OptionalArg<i32>,
3065 ) -> Result<(PySocket, PySocket), IoOrPyException> {
3066 let family = family.unwrap_or(libc::AF_UNIX);
3067 let socket_kind = socket_kind.unwrap_or(libc::SOCK_STREAM);
3068 let proto = proto.unwrap_or(0);
3069 let (a, b) = Socket::pair(family.into(), socket_kind.into(), Some(proto.into()))?;
3070 let py_a = PySocket::default();
3071 py_a.init_inner(family, socket_kind, proto, a)?;
3072 let py_b = PySocket::default();
3073 py_b.init_inner(family, socket_kind, proto, b)?;
3074 Ok((py_a, py_b))
3075 }
3076
3077 #[cfg(all(unix, not(target_os = "redox")))]
3078 type IfIndex = c::c_uint;
3079 #[cfg(windows)]
3080 type IfIndex = u32; #[cfg(not(target_os = "redox"))]
3083 #[pyfunction]
3084 fn if_nametoindex(name: FsPath, vm: &VirtualMachine) -> PyResult<IfIndex> {
3085 let name = name.to_cstring(vm)?;
3086 crate::common::os::set_errno(libc::ENODEV);
3088 let ret = unsafe { c::if_nametoindex(name.as_ptr() as _) };
3089 if ret == 0 {
3090 Err(vm.new_last_errno_error())
3091 } else {
3092 Ok(ret)
3093 }
3094 }
3095
3096 #[cfg(not(target_os = "redox"))]
3097 #[pyfunction]
3098 fn if_indextoname(index: IfIndex, vm: &VirtualMachine) -> PyResult<String> {
3099 let mut buf = [0; c::IF_NAMESIZE + 1];
3100 crate::common::os::set_errno(libc::ENXIO);
3102 let ret = unsafe { c::if_indextoname(index, buf.as_mut_ptr()) };
3103 if ret.is_null() {
3104 Err(vm.new_last_errno_error())
3105 } else {
3106 let buf = unsafe { ffi::CStr::from_ptr(buf.as_ptr() as _) };
3107 Ok(buf.to_string_lossy().into_owned())
3108 }
3109 }
3110
3111 #[cfg(any(
3112 windows,
3113 target_os = "dragonfly",
3114 target_os = "freebsd",
3115 target_os = "fuchsia",
3116 target_os = "ios",
3117 target_os = "linux",
3118 target_os = "macos",
3119 target_os = "netbsd",
3120 target_os = "openbsd",
3121 ))]
3122 #[pyfunction]
3123 fn if_nameindex(vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
3124 #[cfg(not(windows))]
3125 {
3126 let list = nix::net::if_::if_nameindex()
3127 .map_err(|err| err.into_pyexception(vm))?
3128 .to_slice()
3129 .iter()
3130 .map(|iface| {
3131 let tup: (u32, String) =
3132 (iface.index(), iface.name().to_string_lossy().into_owned());
3133 tup.to_pyobject(vm)
3134 })
3135 .collect();
3136
3137 Ok(list)
3138 }
3139 #[cfg(windows)]
3140 {
3141 use windows_sys::Win32::NetworkManagement::Ndis::NET_LUID_LH;
3142
3143 let table = MibTable::get_raw().map_err(|err| err.into_pyexception(vm))?;
3144 let list = table.as_slice().iter().map(|entry| {
3145 let name =
3146 get_name(&entry.InterfaceLuid).map_err(|err| err.into_pyexception(vm))?;
3147 let tup = (entry.InterfaceIndex, name.to_string_lossy());
3148 Ok(tup.to_pyobject(vm))
3149 });
3150 let list = list.collect::<PyResult<_>>()?;
3151 return Ok(list);
3152
3153 fn get_name(luid: &NET_LUID_LH) -> io::Result<widestring::WideCString> {
3154 let mut buf = [0; c::IF_NAMESIZE + 1];
3155 let ret = unsafe {
3156 IpHelper::ConvertInterfaceLuidToNameW(luid, buf.as_mut_ptr(), buf.len())
3157 };
3158 if ret == 0 {
3159 Ok(widestring::WideCString::from_ustr_truncate(
3160 widestring::WideStr::from_slice(&buf[..]),
3161 ))
3162 } else {
3163 Err(io::Error::from_raw_os_error(ret as i32))
3164 }
3165 }
3166 struct MibTable {
3167 ptr: core::ptr::NonNull<IpHelper::MIB_IF_TABLE2>,
3168 }
3169 impl MibTable {
3170 fn get_raw() -> io::Result<Self> {
3171 let mut ptr = core::ptr::null_mut();
3172 let ret = unsafe { IpHelper::GetIfTable2Ex(IpHelper::MibIfTableRaw, &mut ptr) };
3173 if ret == 0 {
3174 let ptr = unsafe { core::ptr::NonNull::new_unchecked(ptr) };
3175 Ok(Self { ptr })
3176 } else {
3177 Err(io::Error::from_raw_os_error(ret as i32))
3178 }
3179 }
3180 }
3181 impl MibTable {
3182 fn as_slice(&self) -> &[IpHelper::MIB_IF_ROW2] {
3183 unsafe {
3184 let p = self.ptr.as_ptr();
3185 let ptr = &raw const (*p).Table as *const IpHelper::MIB_IF_ROW2;
3186 core::slice::from_raw_parts(ptr, (*p).NumEntries as usize)
3187 }
3188 }
3189 }
3190 impl Drop for MibTable {
3191 fn drop(&mut self) {
3192 unsafe { IpHelper::FreeMibTable(self.ptr.as_ptr() as *mut _) };
3193 }
3194 }
3195 }
3196 }
3197
3198 fn get_addr(
3199 vm: &VirtualMachine,
3200 pyname: PyUtf8StrRef,
3201 af: i32,
3202 ) -> Result<SocketAddr, IoOrPyException> {
3203 let name = pyname.as_str();
3204 if name.is_empty() {
3205 let hints = dns_lookup::AddrInfoHints {
3206 address: af,
3207 socktype: c::SOCK_DGRAM,
3208 flags: c::AI_PASSIVE,
3209 protocol: 0,
3210 };
3211 let mut res = dns_lookup::getaddrinfo(None, Some("0"), Some(hints))
3212 .map_err(|e| convert_socket_error(vm, e, SocketError::GaiError))?;
3213 let ainfo = res.next().unwrap()?;
3214 if res.next().is_some() {
3215 return Err(vm
3216 .new_os_error("wildcard resolved to multiple address".to_owned())
3217 .into());
3218 }
3219 return Ok(ainfo.sockaddr);
3220 }
3221 if name == "255.255.255.255" || name == "<broadcast>" {
3222 match af {
3223 c::AF_INET | c::AF_UNSPEC => {}
3224 _ => {
3225 return Err(vm
3226 .new_os_error("address family mismatched".to_owned())
3227 .into());
3228 }
3229 }
3230 return Ok(SocketAddr::V4(net::SocketAddrV4::new(
3231 c::INADDR_BROADCAST.into(),
3232 0,
3233 )));
3234 }
3235 if let c::AF_INET | c::AF_UNSPEC = af
3236 && let Ok(addr) = name.parse::<Ipv4Addr>()
3237 {
3238 return Ok(SocketAddr::V4(net::SocketAddrV4::new(addr, 0)));
3239 }
3240 if matches!(af, c::AF_INET | c::AF_UNSPEC)
3241 && !name.contains('%')
3242 && let Ok(addr) = name.parse::<Ipv6Addr>()
3243 {
3244 return Ok(SocketAddr::V6(net::SocketAddrV6::new(addr, 0, 0, 0)));
3245 }
3246 let hints = dns_lookup::AddrInfoHints {
3247 address: af,
3248 ..Default::default()
3249 };
3250 let name = vm
3251 .state
3252 .codec_registry
3253 .encode_text(pyname.into_wtf8(), "idna", None, vm)?;
3254 let name = core::str::from_utf8(name.as_bytes())
3255 .map_err(|_| vm.new_runtime_error("idna output is not utf8"))?;
3256 let mut res = dns_lookup::getaddrinfo(Some(name), None, Some(hints))
3257 .map_err(|e| convert_socket_error(vm, e, SocketError::GaiError))?;
3258 Ok(res.next().unwrap().map(|ainfo| ainfo.sockaddr)?)
3259 }
3260
3261 fn sock_from_raw(fileno: RawSocket, vm: &VirtualMachine) -> PyResult<Socket> {
3262 let invalid = {
3263 cfg_if::cfg_if! {
3264 if #[cfg(windows)] {
3265 fileno == INVALID_SOCKET
3266 } else {
3267 fileno < 0
3268 }
3269 }
3270 };
3271 if invalid {
3272 return Err(vm.new_value_error("negative file descriptor"));
3273 }
3274 Ok(unsafe { sock_from_raw_unchecked(fileno) })
3275 }
3276 unsafe fn sock_from_raw_unchecked(fileno: RawSocket) -> Socket {
3278 #[cfg(unix)]
3279 {
3280 use std::os::unix::io::FromRawFd;
3281 unsafe { Socket::from_raw_fd(fileno) }
3282 }
3283 #[cfg(windows)]
3284 {
3285 use std::os::windows::io::FromRawSocket;
3286 unsafe { Socket::from_raw_socket(fileno) }
3287 }
3288 }
3289 pub(super) fn sock_fileno(sock: &Socket) -> RawSocket {
3290 #[cfg(unix)]
3291 {
3292 use std::os::unix::io::AsRawFd;
3293 sock.as_raw_fd()
3294 }
3295 #[cfg(windows)]
3296 {
3297 use std::os::windows::io::AsRawSocket;
3298 sock.as_raw_socket()
3299 }
3300 }
3301 fn into_sock_fileno(sock: Socket) -> RawSocket {
3302 #[cfg(unix)]
3303 {
3304 use std::os::unix::io::IntoRawFd;
3305 sock.into_raw_fd()
3306 }
3307 #[cfg(windows)]
3308 {
3309 use std::os::windows::io::IntoRawSocket;
3310 sock.into_raw_socket()
3311 }
3312 }
3313
3314 pub(super) const INVALID_SOCKET: RawSocket = {
3315 #[cfg(unix)]
3316 {
3317 -1
3318 }
3319 #[cfg(windows)]
3320 {
3321 windows_sys::Win32::Networking::WinSock::INVALID_SOCKET as RawSocket
3322 }
3323 };
3324
3325 fn convert_socket_error(
3326 vm: &VirtualMachine,
3327 err: dns_lookup::LookupError,
3328 err_kind: SocketError,
3329 ) -> IoOrPyException {
3330 if let dns_lookup::LookupErrorKind::System = err.kind() {
3331 return io::Error::from(err).into();
3332 }
3333 let strerr = {
3334 #[cfg(unix)]
3335 {
3336 let s = match err_kind {
3337 SocketError::GaiError => unsafe {
3338 ffi::CStr::from_ptr(libc::gai_strerror(err.error_num()))
3339 },
3340 SocketError::HError => unsafe {
3341 ffi::CStr::from_ptr(libc::hstrerror(err.error_num()))
3342 },
3343 };
3344 s.to_str().unwrap()
3345 }
3346 #[cfg(windows)]
3347 {
3348 "getaddrinfo failed"
3349 }
3350 };
3351 let exception_cls = match err_kind {
3352 SocketError::GaiError => gaierror(vm),
3353 SocketError::HError => herror(vm),
3354 };
3355 vm.new_os_subtype_error(exception_cls, Some(err.error_num()), strerr)
3356 .into()
3357 }
3358
3359 fn timeout_error(vm: &VirtualMachine) -> PyRef<PyOSError> {
3360 timeout_error_msg(vm, "timed out".to_owned())
3361 }
3362 pub(crate) fn timeout_error_msg(vm: &VirtualMachine, msg: String) -> PyRef<PyOSError> {
3363 vm.new_os_subtype_error(timeout(vm), None, msg)
3364 }
3365
3366 fn get_ipv6_addr_str(ipv6: Ipv6Addr) -> String {
3367 match ipv6.to_ipv4() {
3368 Some(v4) if !ipv6.is_unspecified() && matches!(v4.octets(), [0, 0, _, _]) => {
3370 format!("::{:x}", u32::from(v4))
3371 }
3372 _ => ipv6.to_string(),
3373 }
3374 }
3375
3376 pub(crate) struct Deadline {
3377 deadline: Instant,
3378 }
3379
3380 impl Deadline {
3381 fn new(timeout: Duration) -> Self {
3382 Self {
3383 deadline: Instant::now() + timeout,
3384 }
3385 }
3386 fn time_until(&self) -> Result<Duration, IoOrPyException> {
3387 self.deadline
3388 .checked_duration_since(Instant::now())
3389 .ok_or(IoOrPyException::Timeout)
3391 }
3392 }
3393
3394 static DEFAULT_TIMEOUT: AtomicCell<f64> = AtomicCell::new(-1.0);
3395
3396 #[pyfunction]
3397 fn getdefaulttimeout() -> Option<f64> {
3398 let timeout = DEFAULT_TIMEOUT.load();
3399 if timeout >= 0.0 { Some(timeout) } else { None }
3400 }
3401
3402 #[pyfunction]
3403 fn setdefaulttimeout(timeout: Option<ArgIntoFloat>, vm: &VirtualMachine) -> PyResult<()> {
3404 let val = match timeout {
3405 Some(t) => {
3406 let f = t.into_float();
3407 if f.is_nan() {
3408 return Err(vm.new_value_error("Invalid value NaN (not a number)"));
3409 }
3410 if f < 0.0 || !f.is_finite() {
3411 return Err(vm.new_value_error("Timeout value out of range"));
3412 }
3413 f
3414 }
3415 None => -1.0,
3416 };
3417 DEFAULT_TIMEOUT.store(val);
3418 Ok(())
3419 }
3420
3421 #[pyfunction]
3422 fn dup(x: PyObjectRef, vm: &VirtualMachine) -> Result<RawSocket, IoOrPyException> {
3423 let sock = get_raw_sock(x, vm)?;
3424 let sock = core::mem::ManuallyDrop::new(sock_from_raw(sock, vm)?);
3425 let newsock = sock.try_clone()?;
3426 let fd = into_sock_fileno(newsock);
3427 #[cfg(windows)]
3428 crate::vm::stdlib::nt::raw_set_handle_inheritable(fd as _, false)?;
3429 Ok(fd)
3430 }
3431
3432 #[pyfunction]
3433 fn close(x: PyObjectRef, vm: &VirtualMachine) -> Result<(), IoOrPyException> {
3434 Ok(close_inner(get_raw_sock(x, vm)?)?)
3435 }
3436
3437 fn close_inner(x: RawSocket) -> io::Result<()> {
3438 #[cfg(unix)]
3439 use libc::close;
3440 #[cfg(windows)]
3441 use windows_sys::Win32::Networking::WinSock::closesocket as close;
3442 let ret = unsafe { close(x as _) };
3443 if ret < 0 {
3444 let err = std::io::Error::last_os_error();
3445 if err.raw_os_error() != Some(errcode!(ECONNRESET)) {
3446 return Err(err);
3447 }
3448 }
3449 Ok(())
3450 }
3451
3452 enum SocketError {
3453 HError,
3454 GaiError,
3455 }
3456
3457 #[cfg(all(unix, not(target_os = "redox")))]
3458 fn checked_cmsg_len(len: usize) -> Option<usize> {
3459 let cmsg_len = |length| unsafe { libc::CMSG_LEN(length) };
3461 if len as u64 > (i32::MAX as u64 - cmsg_len(0) as u64) {
3462 return None;
3463 }
3464 let res = cmsg_len(len as _) as usize;
3465 if res > i32::MAX as usize || res < len {
3466 return None;
3467 }
3468 Some(res)
3469 }
3470
3471 #[cfg(all(unix, not(target_os = "redox")))]
3472 fn checked_cmsg_space(len: usize) -> Option<usize> {
3473 let cmsg_space = |length| unsafe { libc::CMSG_SPACE(length) };
3475 if len as u64 > (i32::MAX as u64 - cmsg_space(1) as u64) {
3476 return None;
3477 }
3478 let res = cmsg_space(len as _) as usize;
3479 if res > i32::MAX as usize || res < len {
3480 return None;
3481 }
3482 Some(res)
3483 }
3484
3485 #[cfg(all(unix, not(target_os = "redox")))]
3486 #[pyfunction(name = "CMSG_LEN")]
3487 fn cmsg_len(length: usize, vm: &VirtualMachine) -> PyResult<usize> {
3488 checked_cmsg_len(length)
3489 .ok_or_else(|| vm.new_overflow_error("CMSG_LEN() argument out of range"))
3490 }
3491
3492 #[cfg(all(unix, not(target_os = "redox")))]
3493 #[pyfunction(name = "CMSG_SPACE")]
3494 fn cmsg_space(length: usize, vm: &VirtualMachine) -> PyResult<usize> {
3495 checked_cmsg_space(length)
3496 .ok_or_else(|| vm.new_overflow_error("CMSG_SPACE() argument out of range"))
3497 }
3498}