#[cfg(unix)]
use crate::os::CheckLibcResult;
#[cfg(unix)]
use core::ffi::CStr;
#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(unix)]
use std::{io, os::fd::BorrowedFd};
#[cfg(not(target_arch = "wasm32"))]
pub fn hostname() -> std::ffi::OsString {
gethostname::gethostname()
}
#[cfg(not(target_arch = "wasm32"))]
pub use ::dns_lookup as dns;
#[cfg(not(target_arch = "wasm32"))]
pub use ::socket2 as raw;
#[cfg(not(any(
target_os = "ios",
target_os = "android",
target_os = "windows",
target_arch = "wasm32",
target_os = "redox"
)))]
fn select_mac_address(addresses: impl IntoIterator<Item = [u8; 6]>) -> Option<[u8; 6]> {
let mut first_local = None;
for address in addresses {
if address == [0; 6] {
continue;
}
if address[0] & 0x02 == 0 {
return Some(address);
}
first_local.get_or_insert(address);
}
first_local
}
#[cfg(not(any(
target_os = "ios",
target_os = "android",
target_os = "windows",
target_arch = "wasm32",
target_os = "redox"
)))]
pub fn mac_address() -> Option<[u8; 6]> {
let addresses = mac_address::MacAddressIterator::new().ok()?;
select_mac_address(addresses.map(|address| address.bytes()))
}
#[cfg(test)]
#[cfg(not(any(
target_os = "ios",
target_os = "android",
target_os = "windows",
target_arch = "wasm32",
target_os = "redox"
)))]
mod mac_address_tests {
use super::select_mac_address;
#[test]
fn prefers_universally_administered_address() {
let local = [0x02, 0, 0, 0, 0, 1];
let universal = [0x00, 0, 0, 0, 0, 2];
assert_eq!(select_mac_address([local, universal]), Some(universal));
}
#[test]
fn falls_back_to_first_locally_administered_address() {
let first = [0x02, 0, 0, 0, 0, 1];
let second = [0x06, 0, 0, 0, 0, 2];
assert_eq!(select_mac_address([first, second]), Some(first));
}
#[test]
fn ignores_zero_address() {
let universal = [0x00, 0, 0, 0, 0, 1];
assert_eq!(select_mac_address([[0; 6], universal]), Some(universal));
assert_eq!(select_mac_address([[0; 6]]), None);
}
}
#[cfg(unix)]
pub use libc::{AF_UNIX, SOCK_STREAM, sa_family_t, sockaddr_storage, socklen_t};
#[cfg(unix)]
pub use libc::{
AF_INET, AF_INET6, AF_UNSPEC, AI_ADDRCONFIG, AI_CANONNAME, AI_NUMERICHOST, AI_NUMERICSERV,
AI_PASSIVE, INADDR_ANY, INADDR_BROADCAST, INADDR_LOOPBACK, INADDR_NONE, IPPROTO_ICMP,
IPPROTO_ICMPV6, IPPROTO_IP, IPPROTO_IPV6, IPPROTO_TCP, IPPROTO_UDP, MSG_CTRUNC, MSG_DONTROUTE,
MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL, NI_DGRAM, NI_MAXHOST, NI_NAMEREQD, NI_NOFQDN,
NI_NUMERICHOST, NI_NUMERICSERV, SHUT_RD, SHUT_RDWR, SHUT_WR, SO_BROADCAST, SO_ERROR,
SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_REUSEADDR, SO_SNDBUF, SO_TYPE, SOCK_DGRAM,
SOL_SOCKET, SOMAXCONN, TCP_NODELAY,
};
#[cfg(all(unix, not(target_os = "redox")))]
pub use libc::{
AF_APPLETALK, AF_DECnet, AF_IPX, IPPROTO_AH, IPPROTO_DSTOPTS, IPPROTO_EGP, IPPROTO_ESP,
IPPROTO_FRAGMENT, IPPROTO_HOPOPTS, IPPROTO_IDP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_NONE,
IPPROTO_PIM, IPPROTO_PUP, IPPROTO_RAW, IPPROTO_ROUTING, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET,
};
#[cfg(unix)]
pub use libc::SO_REUSEPORT;
#[cfg(any(unix, target_os = "android"))]
pub use libc::{
EAI_AGAIN, EAI_BADFLAGS, EAI_FAIL, EAI_FAMILY, EAI_MEMORY, EAI_NONAME, EAI_SERVICE,
EAI_SOCKTYPE, EAI_SYSTEM, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_HDRINCL, IP_MULTICAST_IF,
IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TOS, IP_TTL, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF,
IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, MSG_EOR, SO_ACCEPTCONN, SO_DEBUG,
SO_DONTROUTE, SO_RCVLOWAT, SO_RCVTIMEO, SO_SNDLOWAT, SO_SNDTIMEO,
};
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use libc::{IP_OPTIONS, IPV6_HOPOPTS, IPV6_RECVRTHDR, IPV6_RTHDR};
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "linux",
target_vendor = "apple",
))]
pub use libc::IPV6_DONTFRAG;
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "linux",
target_vendor = "apple",
))]
pub use libc::{IPV6_CHECKSUM, IPV6_HOPLIMIT};
#[cfg(any(
target_os = "android",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_vendor = "apple",
))]
pub use libc::{AI_ALL, AI_V4MAPPED};
#[cfg(any(
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_vendor = "apple",
))]
pub use libc::EAI_NODATA;
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_vendor = "apple",
))]
pub use libc::IPV6_PKTINFO;
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_vendor = "apple",
))]
pub use libc::{IPV6_RECVTCLASS, IPV6_TCLASS};
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_vendor = "apple"
))]
pub use libc::{
AF_LINK, IP_RECVDSTADDR, IPPROTO_GGP, IPV6_JOIN_GROUP, IPV6_LEAVE_GROUP, SO_USELOOPBACK,
};
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_vendor = "apple",
))]
pub use libc::IPPROTO_ND;
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
pub use libc::{MSG_BCAST, MSG_MCAST};
#[cfg(any(target_os = "netbsd", target_os = "redox", target_vendor = "apple"))]
pub use libc::NI_MAXSERV;
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_vendor = "apple"
))]
pub use libc::{
AF_ROUTE, AF_SNA, EAI_OVERFLOW, IPPROTO_GRE, IPPROTO_RSVP, IPPROTO_TP, IPV6_RECVPKTINFO,
MSG_DONTWAIT, SCM_RIGHTS, TCP_MAXSEG,
};
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox"
))]
pub use libc::{SOCK_CLOEXEC, SOCK_NONBLOCK};
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple"
))]
pub use libc::{TCP_KEEPCNT, TCP_KEEPINTVL};
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "netbsd",
target_os = "redox"
))]
pub use libc::TCP_KEEPIDLE;
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd"
))]
pub use libc::{MSG_CMSG_CLOEXEC, MSG_NOSIGNAL};
#[cfg(target_vendor = "apple")]
pub use libc::{
AF_SYSTEM, IP_ADD_SOURCE_MEMBERSHIP, IP_BLOCK_SOURCE, IP_DROP_SOURCE_MEMBERSHIP, IP_PKTINFO,
IP_RECVTTL, IP_UNBLOCK_SOURCE, IPPROTO_MAX, IPPROTO_SCTP, MSG_NOSIGNAL, PF_SYSTEM,
SYSPROTO_CONTROL, TCP_CONNECTION_INFO, TCP_KEEPALIVE,
};
#[cfg(target_os = "linux")]
pub use libc::{
CAN_BCM, CAN_EFF_FLAG, CAN_EFF_MASK, CAN_ERR_FLAG, CAN_ERR_MASK, CAN_ISOTP, CAN_J1939, CAN_RAW,
CAN_RAW_ERR_FILTER, CAN_RAW_FD_FRAMES, CAN_RAW_FILTER, CAN_RAW_JOIN_FILTERS, CAN_RAW_LOOPBACK,
CAN_RAW_RECV_OWN_MSGS, CAN_RTR_FLAG, CAN_SFF_MASK, IPPROTO_MPTCP, J1939_IDLE_ADDR,
J1939_MAX_UNICAST_ADDR, J1939_NLA_BYTES_ACKED, J1939_NLA_PAD, J1939_NO_ADDR, J1939_NO_NAME,
J1939_NO_PGN, J1939_PGN_ADDRESS_CLAIMED, J1939_PGN_ADDRESS_COMMANDED, J1939_PGN_MAX,
J1939_PGN_PDU1_MAX, J1939_PGN_REQUEST, SCM_J1939_DEST_ADDR, SCM_J1939_DEST_NAME,
SCM_J1939_ERRQUEUE, SCM_J1939_PRIO, SO_J1939_ERRQUEUE, SO_J1939_FILTER, SO_J1939_PROMISC,
SO_J1939_SEND_PRIO, SOL_CAN_BASE, SOL_CAN_RAW,
};
#[cfg(all(target_os = "linux", target_env = "gnu"))]
pub use libc::SOL_RDS;
#[cfg(target_os = "android")]
pub use libc::{SOL_ATALK, SOL_AX25, SOL_IPX, SOL_NETROM, SOL_ROSE};
#[cfg(target_os = "freebsd")]
pub use libc::SO_SETFIB;
#[cfg(target_os = "netbsd")]
pub use libc::IPPROTO_VRRP;
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use libc::{
ALG_OP_DECRYPT, ALG_OP_ENCRYPT, ALG_SET_AEAD_ASSOCLEN, ALG_SET_AEAD_AUTHSIZE, ALG_SET_IV,
ALG_SET_KEY, ALG_SET_OP, IP_DEFAULT_MULTICAST_LOOP, IP_RECVOPTS, IP_RETOPTS, IPV6_DSTOPTS,
IPV6_NEXTHOP, IPV6_PATHMTU, IPV6_RECVDSTOPTS, IPV6_RECVHOPLIMIT, IPV6_RECVHOPOPTS,
IPV6_RECVPATHMTU, IPV6_RTHDRDSTOPTS, NETLINK_CRYPTO, NETLINK_DNRTMSG, NETLINK_FIREWALL,
NETLINK_IP6_FW, NETLINK_NFLOG, NETLINK_ROUTE, NETLINK_USERSOCK, NETLINK_XFRM, SO_PASSSEC,
SO_PEERSEC, SOL_ALG,
};
#[cfg(any(target_os = "android", target_vendor = "apple"))]
pub use libc::{AI_DEFAULT, AI_MASK, AI_V4MAPPED_CFG};
#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
pub use libc::MSG_NOTIFICATION;
#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
pub use libc::TCP_USER_TIMEOUT;
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
pub use libc::{
AF_ASH, AF_ATMPVC, AF_ATMSVC, AF_AX25, AF_BRIDGE, AF_ECONET, AF_IRDA, AF_LLC, AF_NETBEUI,
AF_NETLINK, AF_NETROM, AF_PACKET, AF_PPPOX, AF_RDS, AF_SECURITY, AF_TIPC, AF_VSOCK, AF_WANPIPE,
AF_X25, IP_TRANSPARENT, MSG_CONFIRM, MSG_ERRQUEUE, MSG_FASTOPEN, MSG_MORE, PF_CAN, PF_PACKET,
PF_RDS, SCM_CREDENTIALS, SO_BINDTODEVICE, SO_MARK, SOL_IP, SOL_TIPC, SOL_UDP, TCP_CORK,
TCP_DEFER_ACCEPT, TCP_LINGER2, TCP_QUICKACK, TCP_SYNCNT, TCP_WINDOW_CLAMP,
};
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_vendor = "apple"
))]
pub use libc::{IPPROTO_HELLO, IPPROTO_XTP, LOCAL_PEERCRED, MSG_EOF};
#[cfg(any(
target_os = "android",
target_os = "fuchsia",
target_os = "freebsd",
target_os = "linux"
))]
pub use libc::{IPPROTO_UDPLITE, TCP_CONGESTION};
#[cfg(any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "openbsd"
))]
pub use libc::AF_KEY;
#[cfg(any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox"
))]
pub use libc::SO_DOMAIN;
#[cfg(any(
target_os = "android",
target_os = "fuchsia",
all(
target_os = "linux",
any(
target_arch = "aarch64",
target_arch = "x86",
target_arch = "loongarch64",
target_arch = "mips",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "riscv64",
target_arch = "s390x",
target_arch = "x86_64"
)
),
target_os = "redox"
))]
pub use libc::SO_PRIORITY;
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
pub use libc::IPPROTO_MOBILE;
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_vendor = "apple"
))]
pub use libc::SCM_CREDS;
#[cfg(any(
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_vendor = "apple"
))]
pub use libc::TCP_FASTOPEN;
#[cfg(any(
target_os = "android",
target_os = "freebsd",
target_os = "fuchsia",
all(
target_os = "linux",
any(
target_arch = "aarch64",
target_arch = "x86",
target_arch = "loongarch64",
target_arch = "mips",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "riscv64",
target_arch = "s390x",
target_arch = "x86_64"
)
),
target_os = "redox"
))]
pub use libc::SO_PROTOCOL;
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox"
))]
pub use libc::{SO_PASSCRED, SO_PEERCRED};
#[cfg(any(
target_os = "android",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "netbsd"
))]
pub use libc::TCP_INFO;
#[cfg(any(
target_os = "android",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_vendor = "apple"
))]
pub use libc::IP_RECVTOS;
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_vendor = "apple"
))]
pub use libc::{IPPROTO_EON, IPPROTO_IPCOMP};
#[cfg(any(
target_os = "android",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "netbsd"
))]
pub use libc::IPPROTO_SCTP;
#[cfg(any(
target_os = "android",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "openbsd"
))]
pub use libc::AF_BLUETOOTH;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub use libc::{AF_ALG, AF_CAN};
#[cfg(target_os = "linux")]
pub use libc::{sockaddr_alg, sockaddr_can};
#[cfg(unix)]
pub const IPPORT_RESERVED: i32 = 1024;
#[cfg(unix)]
pub const IPPORT_USERRESERVED: i32 = 5000;
#[cfg(unix)]
pub const INADDR_UNSPEC_GROUP: u32 = 0xe000_0000;
#[cfg(unix)]
pub const INADDR_ALLHOSTS_GROUP: u32 = 0xe000_0001;
#[cfg(unix)]
pub const INADDR_MAX_LOCAL_GROUP: u32 = 0xe000_00ff;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub const NI_MAXSERV: i32 = 32;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub const IPV6_JOIN_GROUP: i32 = 20;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub const IPV6_LEAVE_GROUP: i32 = 21;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub const IPV6_RTHDR_TYPE_0: i32 = 0;
#[cfg(target_os = "linux")]
pub const CAN_BCM_TX_SETUP: i32 = 1;
#[cfg(target_os = "linux")]
pub const CAN_BCM_TX_DELETE: i32 = 2;
#[cfg(target_os = "linux")]
pub const CAN_BCM_TX_READ: i32 = 3;
#[cfg(target_os = "linux")]
pub const CAN_BCM_TX_SEND: i32 = 4;
#[cfg(target_os = "linux")]
pub const CAN_BCM_RX_SETUP: i32 = 5;
#[cfg(target_os = "linux")]
pub const CAN_BCM_RX_DELETE: i32 = 6;
#[cfg(target_os = "linux")]
pub const CAN_BCM_RX_READ: i32 = 7;
#[cfg(target_os = "linux")]
pub const CAN_BCM_TX_STATUS: i32 = 8;
#[cfg(target_os = "linux")]
pub const CAN_BCM_TX_EXPIRED: i32 = 9;
#[cfg(target_os = "linux")]
pub const CAN_BCM_RX_STATUS: i32 = 10;
#[cfg(target_os = "linux")]
pub const CAN_BCM_RX_TIMEOUT: i32 = 11;
#[cfg(target_os = "linux")]
pub const CAN_BCM_RX_CHANGED: i32 = 12;
#[cfg(target_os = "linux")]
pub const CAN_BCM_SETTIMER: i32 = 0x0001;
#[cfg(target_os = "linux")]
pub const CAN_BCM_STARTTIMER: i32 = 0x0002;
#[cfg(target_os = "linux")]
pub const CAN_BCM_TX_COUNTEVT: i32 = 0x0004;
#[cfg(target_os = "linux")]
pub const CAN_BCM_TX_ANNOUNCE: i32 = 0x0008;
#[cfg(target_os = "linux")]
pub const CAN_BCM_TX_CP_CAN_ID: i32 = 0x0010;
#[cfg(target_os = "linux")]
pub const CAN_BCM_RX_FILTER_ID: i32 = 0x0020;
#[cfg(target_os = "linux")]
pub const CAN_BCM_RX_CHECK_DLC: i32 = 0x0040;
#[cfg(target_os = "linux")]
pub const CAN_BCM_RX_NO_AUTOTIMER: i32 = 0x0080;
#[cfg(target_os = "linux")]
pub const CAN_BCM_RX_ANNOUNCE_RESUME: i32 = 0x0100;
#[cfg(target_os = "linux")]
pub const CAN_BCM_TX_RESET_MULTI_IDX: i32 = 0x0200;
#[cfg(target_os = "linux")]
pub const CAN_BCM_RX_RTR_FRAME: i32 = 0x0400;
#[cfg(target_os = "linux")]
pub const CAN_BCM_CAN_FD_FRAME: i32 = 0x0800;
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
pub const SO_VM_SOCKETS_BUFFER_SIZE: u32 = 0;
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
pub const SO_VM_SOCKETS_BUFFER_MIN_SIZE: u32 = 1;
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
pub const SO_VM_SOCKETS_BUFFER_MAX_SIZE: u32 = 2;
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
pub const VMADDR_CID_ANY: u32 = 0xffff_ffff;
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
pub const VMADDR_PORT_ANY: u32 = 0xffff_ffff;
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
pub const VMADDR_CID_HOST: u32 = 2;
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
pub const VM_SOCKETS_INVALID_VERSION: u32 = 0xffff_ffff;
#[cfg(any(
target_os = "android",
target_os = "fuchsia",
target_os = "freebsd",
target_os = "linux"
))]
pub const UDPLITE_SEND_CSCOV: i32 = 10;
#[cfg(any(
target_os = "android",
target_os = "fuchsia",
target_os = "freebsd",
target_os = "linux"
))]
pub const UDPLITE_RECV_CSCOV: i32 = 11;
#[cfg(not(any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
windows
)))]
pub const SOL_IP: i32 = 0;
#[cfg(not(any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
windows
)))]
pub const SOL_UDP: i32 = 17;
#[cfg(not(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_vendor = "apple",
windows
)))]
pub const SOMAXCONN: i32 = 5;
#[cfg(any(
target_os = "android",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "openbsd"
))]
pub const BDADDR_ANY: &str = "00:00:00:00:00:00";
#[cfg(any(
target_os = "android",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "openbsd"
))]
pub const BDADDR_LOCAL: &str = "00:00:00:FF:FF:FF";
#[cfg(target_vendor = "apple")]
pub const IPV6_RECVHOPLIMIT: i32 = 37;
#[cfg(target_vendor = "apple")]
pub const IPV6_RECVRTHDR: i32 = 38;
#[cfg(target_vendor = "apple")]
pub const IPV6_RECVHOPOPTS: i32 = 39;
#[cfg(target_vendor = "apple")]
pub const IPV6_RECVDSTOPTS: i32 = 40;
#[cfg(target_vendor = "apple")]
pub const IPV6_USE_MIN_MTU: i32 = 42;
#[cfg(target_vendor = "apple")]
pub const IPV6_RECVPATHMTU: i32 = 43;
#[cfg(target_vendor = "apple")]
pub const IPV6_PATHMTU: i32 = 44;
#[cfg(target_vendor = "apple")]
pub const IPV6_NEXTHOP: i32 = 48;
#[cfg(target_vendor = "apple")]
pub const IPV6_HOPOPTS: i32 = 49;
#[cfg(target_vendor = "apple")]
pub const IPV6_DSTOPTS: i32 = 50;
#[cfg(target_vendor = "apple")]
pub const IPV6_RTHDR: i32 = 51;
#[cfg(target_vendor = "apple")]
pub const IPV6_RTHDRDSTOPTS: i32 = 57;
#[cfg(target_vendor = "apple")]
pub const IPV6_RTHDR_TYPE_0: i32 = 0;
#[cfg(target_vendor = "apple")]
pub const EAI_ADDRFAMILY: i32 = 1;
#[cfg(target_vendor = "apple")]
pub const EAI_BADHINTS: i32 = 12;
#[cfg(target_vendor = "apple")]
pub const EAI_PROTOCOL: i32 = 13;
#[cfg(target_vendor = "apple")]
pub const EAI_MAX: i32 = 15;
#[cfg(all(unix, not(target_os = "redox")))]
pub fn sethostname(hostname: &[u8]) -> io::Result<()> {
use std::os::unix::ffi::OsStrExt;
nix::unistd::sethostname(std::ffi::OsStr::from_bytes(hostname)).map_err(io::Error::from)
}
#[cfg(unix)]
pub fn close_socket_ignore_connreset(socket: libc::c_int) -> io::Result<()> {
let ret = unsafe { libc::close(socket) };
if ret < 0 {
let err = io::Error::last_os_error();
if err.raw_os_error() != Some(libc::ECONNRESET) {
return Err(err);
}
}
Ok(())
}
#[cfg(unix)]
pub fn getsockopt_int(fd: libc::c_int, level: i32, name: i32) -> io::Result<i32> {
let mut flag: libc::c_int = 0;
let mut flagsize = core::mem::size_of::<libc::c_int>() as libc::socklen_t;
unsafe {
libc::getsockopt(
fd,
level,
name,
&mut flag as *mut libc::c_int as *mut _,
&mut flagsize,
)
}
.check_libc_neg()?;
Ok(flag)
}
#[cfg(unix)]
pub fn getsockopt_bytes(
fd: libc::c_int,
level: i32,
name: i32,
buflen: usize,
) -> io::Result<Vec<u8>> {
let mut buf = vec![0u8; buflen];
let mut optlen = buflen as libc::socklen_t;
unsafe { libc::getsockopt(fd, level, name, buf.as_mut_ptr() as *mut _, &mut optlen) }
.check_libc_neg()?;
buf.truncate(optlen as usize);
Ok(buf)
}
#[cfg(unix)]
pub fn setsockopt_bytes(fd: libc::c_int, level: i32, name: i32, value: &[u8]) -> io::Result<()> {
unsafe {
libc::setsockopt(
fd,
level,
name,
value.as_ptr() as *const _,
value.len() as libc::socklen_t,
)
}
.check_libc_neg()?;
Ok(())
}
#[cfg(unix)]
pub fn setsockopt_int(fd: libc::c_int, level: i32, name: i32, value: i32) -> io::Result<()> {
unsafe {
libc::setsockopt(
fd,
level,
name,
&value as *const i32 as *const _,
core::mem::size_of::<i32>() as libc::socklen_t,
)
}
.check_libc_neg()?;
Ok(())
}
#[cfg(unix)]
pub fn setsockopt_none(fd: libc::c_int, level: i32, name: i32, optlen: u32) -> io::Result<()> {
unsafe {
libc::setsockopt(
fd,
level,
name,
core::ptr::null(),
optlen as libc::socklen_t,
)
}
.check_libc_neg()?;
Ok(())
}
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
))]
pub fn if_nameindex() -> io::Result<Vec<(u32, String)>> {
let list = nix::net::if_::if_nameindex().map_err(io::Error::from)?;
Ok(list
.to_slice()
.iter()
.map(|iface| (iface.index(), iface.name().to_string_lossy().into_owned()))
.collect())
}
#[cfg(unix)]
pub fn if_nametoindex_checked(name: &CStr) -> io::Result<u32> {
let ret = unsafe { libc::if_nametoindex(name.as_ptr()) };
if ret == 0 {
Err(io::Error::last_os_error())
} else {
Ok(ret)
}
}
#[cfg(unix)]
pub fn if_indextoname_checked(index: u32) -> io::Result<String> {
let mut buf = [0u8; libc::IF_NAMESIZE];
let ret = unsafe {
libc::if_indextoname(index as libc::c_uint, buf.as_mut_ptr() as *mut libc::c_char)
};
if ret.is_null() {
Err(io::Error::last_os_error())
} else {
let buf = unsafe { CStr::from_ptr(buf.as_ptr() as *const libc::c_char) };
Ok(buf.to_string_lossy().into_owned())
}
}
#[cfg(unix)]
pub fn gai_error_string(err: i32) -> String {
unsafe { CStr::from_ptr(libc::gai_strerror(err)) }
.to_string_lossy()
.into_owned()
}
#[cfg(unix)]
pub fn h_error_string(err: i32) -> String {
unsafe { CStr::from_ptr(libc::hstrerror(err)) }
.to_string_lossy()
.into_owned()
}
#[cfg(all(unix, not(target_os = "redox")))]
#[derive(Debug, Clone)]
pub struct AncillaryMessage {
pub level: i32,
pub kind: i32,
pub data: Vec<u8>,
}
#[cfg(all(unix, not(target_os = "redox")))]
pub type SocketAddressBytes = [u8; core::mem::size_of::<libc::sockaddr_storage>()];
#[cfg(all(unix, not(target_os = "redox")))]
#[derive(Debug, Clone)]
pub struct RawSocketAddress {
pub storage: SocketAddressBytes,
pub len: usize,
}
#[cfg(all(unix, not(target_os = "redox")))]
#[derive(Debug, Clone)]
pub struct RecvMsgResult {
pub data: Vec<u8>,
pub ancdata: Vec<AncillaryMessage>,
pub msg_flags: i32,
pub address: Option<RawSocketAddress>,
}
#[cfg(all(unix, not(target_os = "redox")))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AncillaryPackError {
ItemTooLarge,
TooMuchData,
UnexpectedNullHeader,
}
#[cfg(all(unix, not(target_os = "redox")))]
pub fn checked_cmsg_len(len: usize) -> Option<usize> {
let cmsg_len = |length| unsafe { libc::CMSG_LEN(length) };
if len as u64 > (i32::MAX as u64 - cmsg_len(0) as u64) {
return None;
}
let res = cmsg_len(len as _) as usize;
if res > i32::MAX as usize || res < len {
return None;
}
Some(res)
}
#[cfg(all(unix, not(target_os = "redox")))]
pub fn checked_cmsg_space(len: usize) -> Option<usize> {
let cmsg_space = |length| unsafe { libc::CMSG_SPACE(length) };
if len as u64 > (i32::MAX as u64 - cmsg_space(1) as u64) {
return None;
}
let res = cmsg_space(len as _) as usize;
if res > i32::MAX as usize || res < len {
return None;
}
Some(res)
}
#[cfg(all(unix, not(target_os = "redox")))]
pub fn pack_ancillary_messages(cmsgs: &[(i32, i32, &[u8])]) -> Result<Vec<u8>, AncillaryPackError> {
use core::{mem, ptr};
if cmsgs.is_empty() {
return Ok(vec![]);
}
let capacity = cmsgs
.iter()
.map(|(_, _, buf)| buf.len())
.try_fold(0usize, |sum, len| {
let space = checked_cmsg_space(len).ok_or(AncillaryPackError::ItemTooLarge)?;
usize::checked_add(sum, space).ok_or(AncillaryPackError::TooMuchData)
})?;
let mut cmsg_buffer = vec![0u8; capacity];
let mut mhdr = unsafe { mem::zeroed::<libc::msghdr>() };
mhdr.msg_control = cmsg_buffer.as_mut_ptr().cast();
mhdr.msg_controllen = capacity as _;
let mut pmhdr: *mut libc::cmsghdr = unsafe { libc::CMSG_FIRSTHDR(&mhdr) };
for (lvl, typ, data) in cmsgs {
if pmhdr.is_null() {
return Err(AncillaryPackError::UnexpectedNullHeader);
}
let cmsg_len = checked_cmsg_len(data.len()).ok_or(AncillaryPackError::ItemTooLarge)?;
unsafe {
(*pmhdr).cmsg_level = *lvl;
(*pmhdr).cmsg_type = *typ;
(*pmhdr).cmsg_len = cmsg_len as _;
ptr::copy_nonoverlapping(data.as_ptr(), libc::CMSG_DATA(pmhdr), data.len());
pmhdr = libc::CMSG_NXTHDR(&mhdr, pmhdr);
}
}
Ok(cmsg_buffer)
}
#[cfg(all(unix, not(target_os = "redox")))]
pub fn parse_ancillary_messages(control: &[u8]) -> Vec<AncillaryMessage> {
use core::mem;
if control.is_empty() {
return Vec::new();
}
let mut msg = unsafe { mem::zeroed::<libc::msghdr>() };
msg.msg_control = control.as_ptr() as *mut _;
msg.msg_controllen = control.len() as _;
let ctrl_buf = msg.msg_control as *const u8;
let ctrl_end = unsafe { ctrl_buf.add(msg.msg_controllen as _) };
let mut result = Vec::new();
let mut cmsg: *mut libc::cmsghdr = unsafe { libc::CMSG_FIRSTHDR(&msg) };
while !cmsg.is_null() {
let cmsg_ref = unsafe { &*cmsg };
let data_ptr = unsafe { libc::CMSG_DATA(cmsg) };
let data_len_from_cmsg = cmsg_ref.cmsg_len as usize - (data_ptr as usize - cmsg as usize);
let available = ctrl_end as usize - data_ptr as usize;
let data_len = data_len_from_cmsg.min(available);
let data = unsafe { core::slice::from_raw_parts(data_ptr, data_len) };
result.push(AncillaryMessage {
level: cmsg_ref.cmsg_level,
kind: cmsg_ref.cmsg_type,
data: data.to_vec(),
});
cmsg = unsafe { libc::CMSG_NXTHDR(&msg, cmsg) };
}
result
}
#[cfg(all(unix, not(target_os = "redox")))]
pub fn recvmsg(
fd: BorrowedFd<'_>,
bufsize: usize,
ancbufsize: usize,
flags: i32,
) -> io::Result<RecvMsgResult> {
use core::mem::MaybeUninit;
let mut data_buf: Vec<MaybeUninit<u8>> = vec![MaybeUninit::uninit(); bufsize];
let mut anc_buf: Vec<MaybeUninit<u8>> = vec![MaybeUninit::uninit(); ancbufsize];
let mut addr_storage: libc::sockaddr_storage = unsafe { core::mem::zeroed() };
let mut iov = [libc::iovec {
iov_base: data_buf.as_mut_ptr().cast(),
iov_len: bufsize,
}];
let mut msg: libc::msghdr = unsafe { core::mem::zeroed() };
msg.msg_name = (&mut addr_storage as *mut libc::sockaddr_storage).cast();
msg.msg_namelen = core::mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
msg.msg_iov = iov.as_mut_ptr();
msg.msg_iovlen = 1;
if ancbufsize > 0 {
msg.msg_control = anc_buf.as_mut_ptr().cast();
msg.msg_controllen = ancbufsize as _;
}
let ret = unsafe { libc::recvmsg(fd.as_raw_fd(), &mut msg, flags) }.check_libc_neg()?;
let data = unsafe {
data_buf.set_len(ret as usize);
core::mem::transmute::<Vec<MaybeUninit<u8>>, Vec<u8>>(data_buf)
};
let control = unsafe {
core::slice::from_raw_parts(anc_buf.as_ptr().cast::<u8>(), msg.msg_controllen as usize)
};
let ancdata = parse_ancillary_messages(control);
let address = if msg.msg_namelen > 0 {
let storage = unsafe {
core::mem::transmute::<libc::sockaddr_storage, SocketAddressBytes>(addr_storage)
};
Some(RawSocketAddress {
storage,
len: msg.msg_namelen as usize,
})
} else {
None
};
Ok(RecvMsgResult {
data,
ancdata,
msg_flags: msg.msg_flags,
address,
})
}
#[cfg(target_os = "linux")]
pub fn sendmsg_afalg(
fd: BorrowedFd<'_>,
buffers: &[io::IoSlice<'_>],
op: u32,
iv: Option<&[u8]>,
assoclen: Option<u32>,
flags: i32,
) -> io::Result<usize> {
let mut control_buf = Vec::new();
{
let op_bytes = op.to_ne_bytes();
let space = unsafe { libc::CMSG_SPACE(core::mem::size_of::<u32>() as u32) } as usize;
let old_len = control_buf.len();
control_buf.resize(old_len + space, 0u8);
let cmsg = control_buf[old_len..].as_mut_ptr() as *mut libc::cmsghdr;
unsafe {
(*cmsg).cmsg_len = libc::CMSG_LEN(core::mem::size_of::<u32>() as u32) as _;
(*cmsg).cmsg_level = libc::SOL_ALG;
(*cmsg).cmsg_type = libc::ALG_SET_OP;
let data = libc::CMSG_DATA(cmsg);
core::ptr::copy_nonoverlapping(op_bytes.as_ptr(), data, op_bytes.len());
}
}
if let Some(iv_bytes) = iv {
let iv_struct_size = 4 + iv_bytes.len();
let space = unsafe { libc::CMSG_SPACE(iv_struct_size as u32) } as usize;
let old_len = control_buf.len();
control_buf.resize(old_len + space, 0u8);
let cmsg = control_buf[old_len..].as_mut_ptr() as *mut libc::cmsghdr;
unsafe {
(*cmsg).cmsg_len = libc::CMSG_LEN(iv_struct_size as u32) as _;
(*cmsg).cmsg_level = libc::SOL_ALG;
(*cmsg).cmsg_type = libc::ALG_SET_IV;
let data = libc::CMSG_DATA(cmsg);
let ivlen = (iv_bytes.len() as u32).to_ne_bytes();
core::ptr::copy_nonoverlapping(ivlen.as_ptr(), data, 4);
core::ptr::copy_nonoverlapping(iv_bytes.as_ptr(), data.add(4), iv_bytes.len());
}
}
if let Some(assoclen_val) = assoclen {
let assoclen_bytes = assoclen_val.to_ne_bytes();
let space = unsafe { libc::CMSG_SPACE(core::mem::size_of::<u32>() as u32) } as usize;
let old_len = control_buf.len();
control_buf.resize(old_len + space, 0u8);
let cmsg = control_buf[old_len..].as_mut_ptr() as *mut libc::cmsghdr;
unsafe {
(*cmsg).cmsg_len = libc::CMSG_LEN(core::mem::size_of::<u32>() as u32) as _;
(*cmsg).cmsg_level = libc::SOL_ALG;
(*cmsg).cmsg_type = libc::ALG_SET_AEAD_ASSOCLEN;
let data = libc::CMSG_DATA(cmsg);
core::ptr::copy_nonoverlapping(assoclen_bytes.as_ptr(), data, assoclen_bytes.len());
}
}
let iovecs: Vec<libc::iovec> = buffers
.iter()
.map(|buf| libc::iovec {
iov_base: buf.as_ptr() as *mut _,
iov_len: buf.len(),
})
.collect();
let mut msghdr: libc::msghdr = unsafe { core::mem::zeroed() };
msghdr.msg_iov = iovecs.as_ptr() as *mut _;
msghdr.msg_iovlen = iovecs.len() as _;
if !control_buf.is_empty() {
msghdr.msg_control = control_buf.as_mut_ptr() as *mut _;
msghdr.msg_controllen = control_buf.len() as _;
}
let ret = unsafe { libc::sendmsg(fd.as_raw_fd(), &msghdr, flags) }.check_libc_neg()?;
Ok(ret as usize)
}
#[cfg(windows)]
use core::{ffi::CStr, ptr::NonNull};
#[cfg(windows)]
use rustpython_wtf8::Wtf8Buf;
#[cfg(windows)]
use std::io;
#[cfg(windows)]
use windows_sys::Win32::{
NetworkManagement::{
IpHelper::{
ConvertInterfaceLuidToNameW, FreeMibTable, GetIfTable2Ex, MIB_IF_ROW2, MIB_IF_TABLE2,
MibIfTableRaw, if_indextoname, if_nametoindex,
},
Ndis::{IF_MAX_STRING_SIZE, NET_LUID_LH},
},
Networking::WinSock::{
FROM_PROTOCOL_INFO, SOCKET, WSA_FLAG_OVERLAPPED, WSADuplicateSocketW, WSAGetLastError,
WSAIoctl, WSAPROTOCOL_INFOW, WSASocketW,
},
};
#[cfg(windows)]
pub use windows_sys::Win32::Networking::WinSock::{
AF_APPLETALK, AF_DECnet, AF_IPX, AF_LINK, AI_ADDRCONFIG, AI_ALL, AI_CANONNAME, AI_NUMERICSERV,
AI_V4MAPPED, FIONBIO, INADDR_ANY, INADDR_BROADCAST, INADDR_LOOPBACK, INADDR_NONE,
INVALID_SOCKET, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_HDRINCL, IP_MULTICAST_IF,
IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_OPTIONS, IP_RECVDSTADDR, IP_TOS, IP_TTL,
IPPORT_RESERVED, IPPROTO_AH, IPPROTO_CBT, IPPROTO_DSTOPTS, IPPROTO_EGP, IPPROTO_ESP,
IPPROTO_FRAGMENT, IPPROTO_GGP, IPPROTO_HOPOPTS, IPPROTO_ICLFXBM, IPPROTO_ICMP, IPPROTO_ICMPV6,
IPPROTO_IDP, IPPROTO_IGMP, IPPROTO_IGP, IPPROTO_IP, IPPROTO_IP as IPPROTO_IPIP, IPPROTO_IPV4,
IPPROTO_IPV6, IPPROTO_L2TP, IPPROTO_MAX, IPPROTO_ND, IPPROTO_NONE, IPPROTO_PGM, IPPROTO_PIM,
IPPROTO_PUP, IPPROTO_RAW, IPPROTO_RDP, IPPROTO_ROUTING, IPPROTO_SCTP, IPPROTO_ST, IPPROTO_TCP,
IPPROTO_UDP, IPV6_CHECKSUM, IPV6_DONTFRAG, IPV6_HOPLIMIT, IPV6_HOPOPTS, IPV6_JOIN_GROUP,
IPV6_LEAVE_GROUP, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_PKTINFO,
IPV6_RECVRTHDR, IPV6_RECVTCLASS, IPV6_RTHDR, IPV6_TCLASS, IPV6_UNICAST_HOPS, IPV6_V6ONLY,
MSG_BCAST, MSG_CTRUNC, MSG_DONTROUTE, MSG_MCAST, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL,
NI_DGRAM, NI_MAXHOST, NI_MAXSERV, NI_NAMEREQD, NI_NOFQDN, NI_NUMERICHOST, NI_NUMERICSERV,
POLLIN, RCVALL_IPLEVEL, RCVALL_OFF, RCVALL_ON, RCVALL_SOCKETLEVELONLY, SD_BOTH,
SD_BOTH as SHUT_RDWR, SD_RECEIVE, SD_RECEIVE as SHUT_RD, SD_SEND, SD_SEND as SHUT_WR,
SIO_KEEPALIVE_VALS, SIO_LOOPBACK_FAST_PATH, SIO_RCVALL, SO_ACCEPTCONN, SO_BROADCAST, SO_DEBUG,
SO_DONTROUTE, SO_ERROR, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_RCVTIMEO,
SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, SO_USELOOPBACK, SOCK_DGRAM, SOCK_RAW, SOCK_RDM,
SOCK_SEQPACKET, SOCK_STREAM, SOCKET_ERROR, SOCKET_ERROR as SOCKET_ERROR_CODE, SOL_IP,
SOL_SOCKET, TCP_MAXSEG, TCP_NODELAY, WSAEBADF, WSAECONNABORTED, WSAECONNRESET, WSAEINTR,
WSAENOTSOCK, WSAEWOULDBLOCK, getprotobyname, getservbyname, getservbyport, getsockopt,
setsockopt,
};
#[cfg(windows)]
pub const SO_EXCLUSIVEADDRUSE: i32 = -5;
#[cfg(windows)]
pub const EAI_MEMORY: i32 = windows_sys::Win32::Networking::WinSock::WSA_NOT_ENOUGH_MEMORY;
#[cfg(windows)]
pub const EAI_FAMILY: i32 = windows_sys::Win32::Networking::WinSock::WSAEAFNOSUPPORT;
#[cfg(windows)]
pub const EAI_BADFLAGS: i32 = windows_sys::Win32::Networking::WinSock::WSAEINVAL;
#[cfg(windows)]
pub const EAI_SOCKTYPE: i32 = windows_sys::Win32::Networking::WinSock::WSAESOCKTNOSUPPORT;
#[cfg(windows)]
pub const EAI_NODATA: i32 = windows_sys::Win32::Networking::WinSock::WSAHOST_NOT_FOUND;
#[cfg(windows)]
pub const EAI_NONAME: i32 = windows_sys::Win32::Networking::WinSock::WSAHOST_NOT_FOUND;
#[cfg(windows)]
pub const EAI_FAIL: i32 = windows_sys::Win32::Networking::WinSock::WSANO_RECOVERY;
#[cfg(windows)]
pub const EAI_AGAIN: i32 = windows_sys::Win32::Networking::WinSock::WSATRY_AGAIN;
#[cfg(windows)]
pub const EAI_SERVICE: i32 = windows_sys::Win32::Networking::WinSock::WSATYPE_NOT_FOUND;
#[cfg(windows)]
pub const IF_NAMESIZE: usize = IF_MAX_STRING_SIZE as usize;
#[cfg(windows)]
pub const AF_UNSPEC: i32 = windows_sys::Win32::Networking::WinSock::AF_UNSPEC as i32;
#[cfg(windows)]
pub const AF_INET: i32 = windows_sys::Win32::Networking::WinSock::AF_INET as i32;
#[cfg(windows)]
pub const AF_INET6: i32 = windows_sys::Win32::Networking::WinSock::AF_INET6 as i32;
#[cfg(windows)]
pub const AI_PASSIVE: i32 = windows_sys::Win32::Networking::WinSock::AI_PASSIVE as i32;
#[cfg(windows)]
pub const AI_NUMERICHOST: i32 = windows_sys::Win32::Networking::WinSock::AI_NUMERICHOST as i32;
#[cfg(windows)]
pub const FROM_PROTOCOL_INFO_VALUE: i32 = FROM_PROTOCOL_INFO;
#[cfg(windows)]
pub const SOMAXCONN: i32 = 0x7fff_ffff;
#[cfg(windows)]
pub const SOL_TCP: i32 = 6;
#[cfg(windows)]
pub const SOL_UDP: i32 = 17;
#[cfg(windows)]
pub const SOL_RFCOMM: i32 = 3;
#[cfg(windows)]
pub const SO_SNDLOWAT: i32 = 0x1003;
#[cfg(windows)]
pub const SO_RCVLOWAT: i32 = 0x1004;
#[cfg(windows)]
pub const SO_ORIGINAL_DST: i32 = 12303;
#[cfg(windows)]
pub const SO_BTH_ENCRYPT: i32 = 2;
#[cfg(windows)]
pub const SO_BTH_MTU: i32 = 0x8000_0007u32 as i32;
#[cfg(windows)]
pub const SO_BTH_MTU_MAX: i32 = 0x8000_0008u32 as i32;
#[cfg(windows)]
pub const SO_BTH_MTU_MIN: i32 = 0x8000_000au32 as i32;
#[cfg(windows)]
pub const TCP_KEEPIDLE: i32 = 3;
#[cfg(windows)]
pub const TCP_FASTOPEN: i32 = 15;
#[cfg(windows)]
pub const TCP_KEEPCNT: i32 = 16;
#[cfg(windows)]
pub const TCP_KEEPINTVL: i32 = 17;
#[cfg(windows)]
pub const IPPORT_USERRESERVED: i32 = 5000;
#[cfg(windows)]
pub const INADDR_UNSPEC_GROUP: i32 = 0xe000_0000u32 as i32;
#[cfg(windows)]
pub const INADDR_ALLHOSTS_GROUP: i32 = 0xe000_0001u32 as i32;
#[cfg(windows)]
pub const INADDR_MAX_LOCAL_GROUP: i32 = 0xe000_00ffu32 as i32;
#[cfg(windows)]
pub const IP_ADD_SOURCE_MEMBERSHIP: i32 = 15;
#[cfg(windows)]
pub const IP_DROP_SOURCE_MEMBERSHIP: i32 = 16;
#[cfg(windows)]
pub const IP_BLOCK_SOURCE: i32 = 17;
#[cfg(windows)]
pub const IP_UNBLOCK_SOURCE: i32 = 18;
#[cfg(windows)]
pub const IP_PKTINFO: i32 = 19;
#[cfg(windows)]
pub const IP_RECVTTL: i32 = 21;
#[cfg(windows)]
pub const IP_RECVTOS: i32 = 40;
#[cfg(windows)]
pub const IP_RECVERR: i32 = 75;
#[cfg(windows)]
pub const IPV6_RECVERR: i32 = 75;
#[cfg(windows)]
pub const MSG_ERRQUEUE: i32 = 0x1000;
#[cfg(windows)]
pub const RCVALL_MAX: i32 = 3;
#[cfg(windows)]
pub const BDADDR_ANY: &str = "00:00:00:00:00:00";
#[cfg(windows)]
pub const BDADDR_LOCAL: &str = "00:00:00:FF:FF:FF";
#[cfg(windows)]
pub type RawSocket = SOCKET;
#[cfg(windows)]
pub const INVALID_RAW_SOCKET: RawSocket = INVALID_SOCKET as RawSocket;
#[cfg(windows)]
#[repr(C)]
pub struct TcpKeepalive {
pub onoff: u32,
pub keepalivetime: u32,
pub keepaliveinterval: u32,
}
#[cfg(windows)]
pub struct SharedSocket {
pub raw: RawSocket,
pub family: i32,
pub socket_type: i32,
pub protocol: i32,
}
#[cfg(windows)]
pub fn last_socket_error() -> io::Error {
io::Error::from_raw_os_error(unsafe { WSAGetLastError() })
}
#[cfg(windows)]
pub fn set_socket_inheritable(socket: RawSocket, inheritable: bool) -> io::Result<()> {
crate::nt::set_handle_inheritable(socket as _, inheritable)
}
#[cfg(windows)]
pub fn close_socket_ignore_connreset(socket: RawSocket) -> io::Result<()> {
let ret = unsafe { windows_sys::Win32::Networking::WinSock::closesocket(socket) };
if ret != 0 {
let err = last_socket_error();
if err.raw_os_error() != Some(WSAECONNRESET) {
return Err(err);
}
}
Ok(())
}
#[cfg(windows)]
pub fn getsockopt_int(socket: RawSocket, level: i32, name: i32) -> io::Result<i32> {
let mut flag = 0i32;
let mut optlen = core::mem::size_of::<i32>() as i32;
let ret = unsafe {
getsockopt(
socket,
level,
name,
&mut flag as *mut i32 as *mut _,
&mut optlen,
)
};
if ret == SOCKET_ERROR {
Err(crate::os::errno_io_error())
} else {
Ok(flag)
}
}
#[cfg(windows)]
pub fn getsockopt_bytes(
socket: RawSocket,
level: i32,
name: i32,
buflen: usize,
) -> io::Result<Vec<u8>> {
let mut buf = vec![0u8; buflen];
let mut optlen = buflen as i32;
let ret = unsafe { getsockopt(socket, level, name, buf.as_mut_ptr() as *mut _, &mut optlen) };
if ret == SOCKET_ERROR {
Err(crate::os::errno_io_error())
} else {
buf.truncate(optlen as usize);
Ok(buf)
}
}
#[cfg(windows)]
pub fn setsockopt_bytes(socket: RawSocket, level: i32, name: i32, value: &[u8]) -> io::Result<()> {
let ret = unsafe {
setsockopt(
socket,
level,
name,
value.as_ptr() as *const _,
value.len() as i32,
)
};
if ret == SOCKET_ERROR {
Err(crate::os::errno_io_error())
} else {
Ok(())
}
}
#[cfg(windows)]
pub fn setsockopt_int(socket: RawSocket, level: i32, name: i32, value: i32) -> io::Result<()> {
let ret = unsafe {
setsockopt(
socket,
level,
name,
&value as *const i32 as *const _,
core::mem::size_of::<i32>() as i32,
)
};
if ret == SOCKET_ERROR {
Err(crate::os::errno_io_error())
} else {
Ok(())
}
}
#[cfg(windows)]
pub fn setsockopt_none(socket: RawSocket, level: i32, name: i32, optlen: u32) -> io::Result<()> {
let ret = unsafe { setsockopt(socket, level, name, core::ptr::null(), optlen as i32) };
if ret == SOCKET_ERROR {
Err(crate::os::errno_io_error())
} else {
Ok(())
}
}
#[cfg(windows)]
pub fn protocol_info_size() -> usize {
core::mem::size_of::<WSAPROTOCOL_INFOW>()
}
#[cfg(windows)]
pub fn socket_from_share_data(bytes: &[u8]) -> io::Result<SharedSocket> {
let mut info: WSAPROTOCOL_INFOW = unsafe { core::mem::zeroed() };
unsafe {
core::ptr::copy_nonoverlapping(
bytes.as_ptr(),
&mut info as *mut WSAPROTOCOL_INFOW as *mut u8,
protocol_info_size(),
);
}
let raw = unsafe {
WSASocketW(
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
&info,
0,
WSA_FLAG_OVERLAPPED,
)
};
if raw == INVALID_SOCKET {
return Err(last_socket_error());
}
crate::nt::set_handle_inheritable(raw as _, false)?;
Ok(SharedSocket {
raw,
family: info.iAddressFamily,
socket_type: info.iSocketType,
protocol: info.iProtocol,
})
}
#[cfg(windows)]
pub fn share_socket(socket: RawSocket, process_id: u32) -> io::Result<Vec<u8>> {
let mut info = core::mem::MaybeUninit::<WSAPROTOCOL_INFOW>::uninit();
let ret = unsafe { WSADuplicateSocketW(socket, process_id, info.as_mut_ptr()) };
if ret == SOCKET_ERROR {
return Err(last_socket_error());
}
let info = unsafe { info.assume_init() };
let bytes = unsafe {
core::slice::from_raw_parts(
&info as *const WSAPROTOCOL_INFOW as *const u8,
core::mem::size_of::<WSAPROTOCOL_INFOW>(),
)
};
Ok(bytes.to_vec())
}
#[cfg(windows)]
pub fn ioctl_u32(socket: RawSocket, cmd: u32, option: u32) -> io::Result<u32> {
let mut recv = 0u32;
let ret = unsafe {
WSAIoctl(
socket,
cmd,
&option as *const u32 as *const _,
core::mem::size_of::<u32>() as u32,
core::ptr::null_mut(),
0,
&mut recv,
core::ptr::null_mut(),
None,
)
};
if ret == SOCKET_ERROR {
Err(last_socket_error())
} else {
Ok(recv)
}
}
#[cfg(windows)]
pub fn ioctl_keepalive(socket: RawSocket, keepalive: TcpKeepalive) -> io::Result<u32> {
let mut recv = 0u32;
let ret = unsafe {
WSAIoctl(
socket,
windows_sys::Win32::Networking::WinSock::SIO_KEEPALIVE_VALS,
&keepalive as *const TcpKeepalive as *const _,
core::mem::size_of::<TcpKeepalive>() as u32,
core::ptr::null_mut(),
0,
&mut recv,
core::ptr::null_mut(),
None,
)
};
if ret == SOCKET_ERROR {
Err(last_socket_error())
} else {
Ok(recv)
}
}
#[cfg(windows)]
pub fn if_nametoindex_checked(name: &CStr) -> io::Result<u32> {
crate::os::set_errno(libc::ENODEV);
let ret = unsafe { if_nametoindex(name.as_ptr() as _) };
if ret == 0 {
Err(crate::os::errno_io_error())
} else {
Ok(ret)
}
}
#[cfg(windows)]
pub fn if_indextoname_checked(index: u32) -> io::Result<String> {
let mut buf = [0; IF_MAX_STRING_SIZE as usize + 1];
crate::os::set_errno(libc::ENXIO);
let ret = unsafe { if_indextoname(index, buf.as_mut_ptr()) };
if ret.is_null() {
Err(crate::os::errno_io_error())
} else {
let buf = unsafe { CStr::from_ptr(buf.as_ptr() as _) };
Ok(buf.to_string_lossy().into_owned())
}
}
#[cfg(windows)]
fn if_name_from_wide(buf: &[u16]) -> Wtf8Buf {
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
Wtf8Buf::from_wide(&buf[..len])
}
#[cfg(windows)]
pub fn if_nameindex() -> io::Result<Vec<(u32, Wtf8Buf)>> {
fn get_name(luid: &NET_LUID_LH) -> io::Result<Wtf8Buf> {
let mut buf = [0u16; IF_MAX_STRING_SIZE as usize + 1];
let ret = unsafe { ConvertInterfaceLuidToNameW(luid, buf.as_mut_ptr(), buf.len()) };
if ret != 0 {
return Err(io::Error::from_raw_os_error(ret as i32));
}
Ok(if_name_from_wide(&buf))
}
struct MibTable {
ptr: NonNull<MIB_IF_TABLE2>,
}
impl MibTable {
fn get_raw() -> io::Result<Self> {
let mut ptr = core::ptr::null_mut();
let ret = unsafe { GetIfTable2Ex(MibIfTableRaw, &mut ptr) };
if ret == 0 {
let ptr = unsafe { NonNull::new_unchecked(ptr) };
Ok(Self { ptr })
} else {
Err(io::Error::from_raw_os_error(ret as i32))
}
}
fn as_slice(&self) -> &[MIB_IF_ROW2] {
unsafe {
let p = self.ptr.as_ptr();
let ptr = &raw const (*p).Table as *const MIB_IF_ROW2;
core::slice::from_raw_parts(ptr, (*p).NumEntries as usize)
}
}
}
impl Drop for MibTable {
fn drop(&mut self) {
unsafe { FreeMibTable(self.ptr.as_ptr() as *mut _) };
}
}
let table = MibTable::get_raw()?;
table
.as_slice()
.iter()
.map(|entry| Ok((entry.InterfaceIndex, get_name(&entry.InterfaceLuid)?)))
.collect()
}
#[cfg(test)]
#[cfg(windows)]
mod if_name_from_wide_tests {
use super::if_name_from_wide;
use rustpython_wtf8::Wtf8Buf;
#[test]
fn keeps_unpaired_surrogate() {
let units = [b'e' as u16, 0xD800, 0];
let name = if_name_from_wide(&units);
assert_eq!(name, Wtf8Buf::from_wide(&[b'e' as u16, 0xD800]));
assert_ne!(
name.as_bytes(),
String::from_utf16_lossy(&[b'e' as u16, 0xD800]).as_bytes()
);
}
}
#[cfg(windows)]
pub fn uuid_from_string_w(wide: &widestring::WideCStr) -> Result<windows_sys::core::GUID, u32> {
let mut guid = windows_sys::core::GUID {
data1: 0,
data2: 0,
data3: 0,
data4: [0; 8],
};
let status =
unsafe { windows_sys::Win32::System::Rpc::UuidFromStringW(wide.as_ptr(), &mut guid) };
if status == windows_sys::Win32::System::Rpc::RPC_S_OK {
Ok(guid)
} else {
Err(status as u32)
}
}
#[cfg(windows)]
pub fn uuid_to_string_w(guid: &windows_sys::core::GUID) -> Result<String, u32> {
use windows_sys::Win32::System::Rpc::{RPC_S_OK, RpcStringFreeW, UuidToStringW};
let mut raw = core::ptr::null_mut();
let status = unsafe { UuidToStringW(guid, &mut raw) };
if status != RPC_S_OK {
return Err(status as u32);
}
let mut len = 0usize;
unsafe {
while *raw.add(len) != 0 {
len += 1;
}
}
let text = String::from_utf16_lossy(unsafe { core::slice::from_raw_parts(raw, len) });
unsafe { RpcStringFreeW(&mut raw) };
Ok(text)
}
#[cfg(windows)]
pub const AF_SNA: i32 = 11;
#[cfg(windows)]
pub const AF_IRDA: i32 = 26;
#[cfg(windows)]
pub const AF_HYPERV: i32 = windows_sys::Win32::Networking::WinSock::AF_HYPERV as i32;
#[cfg(windows)]
pub const AF_BLUETOOTH: i32 = windows_sys::Win32::Devices::Bluetooth::AF_BTH as i32;
#[cfg(windows)]
pub const AF_BTH: i32 = AF_BLUETOOTH;
#[cfg(windows)]
pub const BTHPROTO_RFCOMM: i32 = windows_sys::Win32::Devices::Bluetooth::BTHPROTO_RFCOMM as i32;
#[cfg(windows)]
pub const HV_PROTOCOL_RAW: i32 = 1;
#[cfg(windows)]
pub const HVSOCKET_CONNECT_TIMEOUT: i32 = 0x01;
#[cfg(windows)]
pub const HVSOCKET_CONNECT_TIMEOUT_MAX: i32 = 300_000;
#[cfg(windows)]
pub const HVSOCKET_CONNECTED_SUSPEND: i32 = 0x04;
#[cfg(windows)]
pub const HVSOCKET_ADDRESS_FLAG_PASSTHRU: i32 = 0x01;
#[cfg(windows)]
pub const HV_GUID_ZERO: &str = "00000000-0000-0000-0000-000000000000";
#[cfg(windows)]
pub const HV_GUID_WILDCARD: &str = "00000000-0000-0000-0000-000000000000";
#[cfg(windows)]
pub const HV_GUID_BROADCAST: &str = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF";
#[cfg(windows)]
pub const HV_GUID_CHILDREN: &str = "90DB8B89-0D35-4F79-8CE9-49EA0AC8B7CD";
#[cfg(windows)]
pub const HV_GUID_LOOPBACK: &str = "E0E16197-DD56-4A10-9195-5EE7A155A838";
#[cfg(windows)]
pub const HV_GUID_PARENT: &str = "A42E7CDA-D03F-480C-9CC2-A4DE20ABB878";
#[cfg(windows)]
pub const SIO_TCP_SET_ACK_FREQUENCY: i32 =
windows_sys::Win32::Networking::WinSock::SIO_TCP_SET_ACK_FREQUENCY as i32;
#[cfg(windows)]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct SockaddrHv {
pub family: u16,
pub reserved: u16,
pub vm_id: windows_sys::core::GUID,
pub service_id: windows_sys::core::GUID,
}
#[cfg(windows)]
pub fn sockaddr_hv(
vm_id: windows_sys::core::GUID,
service_id: windows_sys::core::GUID,
) -> SockaddrHv {
SockaddrHv {
family: AF_HYPERV as u16,
reserved: 0,
vm_id,
service_id,
}
}
#[cfg(windows)]
pub fn sockaddr_bth_rfcomm(
bd_addr: u64,
port: u32,
) -> windows_sys::Win32::Devices::Bluetooth::SOCKADDR_BTH {
windows_sys::Win32::Devices::Bluetooth::SOCKADDR_BTH {
addressFamily: AF_BTH as u16,
btAddr: bd_addr,
serviceClassId: Default::default(),
port,
}
}
#[cfg(windows)]
pub fn unpack_sockaddr_bth(ptr: *const u8) -> (u64, u32) {
let bth = unsafe { &*(ptr.cast::<windows_sys::Win32::Devices::Bluetooth::SOCKADDR_BTH>()) };
(bth.btAddr, bth.port)
}
#[cfg(windows)]
pub fn parse_bdaddr(name: &str) -> Option<u64> {
let mut parts = name.split(':');
let mut value = 0u64;
for _ in 0..6 {
let part = parts.next()?;
if part.is_empty() || part.len() > 2 {
return None;
}
let octet = u8::from_str_radix(part, 16).ok()?;
value = (value << 8) | u64::from(octet);
}
if parts.next().is_some() {
return None;
}
Some(value)
}
#[cfg(windows)]
pub fn format_bdaddr(bdaddr: u64) -> String {
let octet = |i: u32| (bdaddr >> (8 * i)) & 0xFF;
alloc::format!(
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
octet(5),
octet(4),
octet(3),
octet(2),
octet(1),
octet(0)
)
}