use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub mod x86_protocol_headers {
pub mod af {
pub const AF_INET: u16 = 2;
pub const AF_INET6: u16 = 10;
pub const AF_UNIX: u16 = 1;
pub const AF_NETLINK: u16 = 16;
pub const AF_PACKET: u16 = 17;
pub const AF_UNSPEC: u16 = 0;
pub const AF_IPX: u16 = 4;
pub const AF_APPLETALK: u16 = 5;
pub const AF_X25: u16 = 9;
pub const AF_AX25: u16 = 3;
pub const AF_DECnet: u16 = 12;
pub const AF_BLUETOOTH: u16 = 31;
pub const AF_NETROM: u16 = 6;
pub const AF_BRIDGE: u16 = 7;
pub const AF_ATMPVC: u16 = 8;
pub const AF_ROSE: u16 = 11;
pub const AF_NETBEUI: u16 = 13;
pub const AF_SECURITY: u16 = 14;
pub const AF_KEY: u16 = 15;
pub const AF_QOS: u16 = 36;
pub const AF_VSOCK: u16 = 40;
pub const AF_NFC: u16 = 39;
pub const AF_ALG: u16 = 38;
pub const AF_CAN: u16 = 29;
pub const AF_TIPC: u16 = 30;
pub const AF_RDS: u16 = 21;
pub const AF_IUCV: u16 = 32;
pub const AF_RXRPC: u16 = 33;
pub const AF_PHONET: u16 = 35;
pub const AF_IEEE802154: u16 = 36;
pub const AF_CAIF: u16 = 37;
pub const AF_KCM: u16 = 41;
pub const AF_SMC: u16 = 43;
pub const AF_XDP: u16 = 44;
pub const AF_MCTP: u16 = 45;
}
pub mod sock_type {
pub const SOCK_STREAM: i32 = 1;
pub const SOCK_DGRAM: i32 = 2;
pub const SOCK_RAW: i32 = 3;
pub const SOCK_RDM: i32 = 4;
pub const SOCK_SEQPACKET: i32 = 5;
pub const SOCK_DCCP: i32 = 6;
pub const SOCK_NONBLOCK: i32 = 0o4000;
pub const SOCK_CLOEXEC: i32 = 0o2000000;
}
pub mod ipproto {
pub const IPPROTO_IP: i32 = 0;
pub const IPPROTO_ICMP: i32 = 1;
pub const IPPROTO_IGMP: i32 = 2;
pub const IPPROTO_TCP: i32 = 6;
pub const IPPROTO_UDP: i32 = 17;
pub const IPPROTO_IPV6: i32 = 41;
pub const IPPROTO_ICMPV6: i32 = 58;
pub const IPPROTO_SCTP: i32 = 132;
pub const IPPROTO_RAW: i32 = 255;
pub const IPPROTO_DCCP: i32 = 33;
pub const IPPROTO_UDPLITE: i32 = 136;
pub const IPPROTO_MPTCP: i32 = 262;
pub const IPPROTO_GRE: i32 = 47;
pub const IPPROTO_ESP: i32 = 50;
pub const IPPROTO_AH: i32 = 51;
pub const IPPROTO_PIM: i32 = 103;
pub const IPPROTO_COMP: i32 = 108;
pub const IPPROTO_L2TP: i32 = 115;
pub const IPPROTO_SCTP_ALT: i32 = 132;
pub const IPPROTO_FC: i32 = 133;
}
pub mod sol {
pub const SOL_SOCKET: i32 = 1;
pub const SOL_IP: i32 = 0;
pub const SOL_TCP: i32 = 6;
pub const SOL_UDP: i32 = 17;
pub const SOL_IPV6: i32 = 41;
pub const SOL_ICMPV6: i32 = 58;
pub const SOL_RAW: i32 = 255;
pub const SOL_PACKET: i32 = 263;
pub const SOL_NETLINK: i32 = 270;
}
pub mod sockopt {
pub const SO_DEBUG: i32 = 1;
pub const SO_REUSEADDR: i32 = 2;
pub const SO_TYPE: i32 = 3;
pub const SO_ERROR: i32 = 4;
pub const SO_DONTROUTE: i32 = 5;
pub const SO_BROADCAST: i32 = 6;
pub const SO_SNDBUF: i32 = 7;
pub const SO_RCVBUF: i32 = 8;
pub const SO_SNDBUFFORCE: i32 = 32;
pub const SO_RCVBUFFORCE: i32 = 33;
pub const SO_KEEPALIVE: i32 = 9;
pub const SO_OOBINLINE: i32 = 10;
pub const SO_NO_CHECK: i32 = 11;
pub const SO_PRIORITY: i32 = 12;
pub const SO_LINGER: i32 = 13;
pub const SO_BSDCOMPAT: i32 = 14;
pub const SO_REUSEPORT: i32 = 15;
pub const SO_PASSCRED: i32 = 16;
pub const SO_PEERCRED: i32 = 17;
pub const SO_RCVLOWAT: i32 = 18;
pub const SO_SNDLOWAT: i32 = 19;
pub const SO_RCVTIMEO: i32 = 20;
pub const SO_SNDTIMEO: i32 = 21;
pub const SO_SECURITY_AUTHENTICATION: i32 = 22;
pub const SO_SECURITY_ENCRYPTION_TRANSPORT: i32 = 23;
pub const SO_SECURITY_ENCRYPTION_NETWORK: i32 = 24;
pub const SO_BINDTODEVICE: i32 = 25;
pub const SO_ATTACH_FILTER: i32 = 26;
pub const SO_DETACH_FILTER: i32 = 27;
pub const SO_PEERNAME: i32 = 28;
pub const SO_TIMESTAMP: i32 = 29;
pub const SO_ACCEPTCONN: i32 = 30;
pub const SO_PEERSEC: i32 = 31;
pub const SO_PASSSEC: i32 = 34;
pub const SO_TIMESTAMPNS: i32 = 35;
pub const SO_MARK: i32 = 36;
pub const SO_TIMESTAMPING: i32 = 37;
pub const SO_PROTOCOL: i32 = 38;
pub const SO_DOMAIN: i32 = 39;
pub const SO_RXQ_OVFL: i32 = 40;
pub const SO_WIFI_STATUS: i32 = 41;
pub const SO_PEEK_OFF: i32 = 42;
pub const SO_NOFCS: i32 = 43;
pub const SO_LOCK_FILTER: i32 = 44;
pub const SO_SELECT_ERR_QUEUE: i32 = 45;
pub const SO_BUSY_POLL: i32 = 46;
pub const SO_MAX_PACING_RATE: i32 = 47;
pub const SO_BPF_EXTENSIONS: i32 = 48;
pub const SO_INCOMING_CPU: i32 = 49;
pub const SO_ATTACH_BPF: i32 = 50;
pub const SO_DETACH_BPF: i32 = 27;
pub const SO_ATTACH_REUSEPORT_CBPF: i32 = 51;
pub const SO_ATTACH_REUSEPORT_EBPF: i32 = 52;
pub const SO_CNX_ADVICE: i32 = 53;
pub const SO_MEMINFO: i32 = 55;
pub const SO_INCOMING_NAPI_ID: i32 = 56;
pub const SO_COOKIE: i32 = 57;
pub const SO_PEERGROUPS: i32 = 59;
pub const SO_ZEROCOPY: i32 = 60;
pub const SO_TXTIME: i32 = 61;
pub const SO_BINDTOIFINDEX: i32 = 62;
pub const SO_TIMESTAMP_OLD: i32 = 29;
pub const SO_TIMESTAMPNS_OLD: i32 = 35;
pub const SO_TIMESTAMPING_OLD: i32 = 37;
pub const SO_TIMESTAMP_NEW: i32 = 63;
pub const SO_TIMESTAMPNS_NEW: i32 = 64;
pub const SO_TIMESTAMPING_NEW: i32 = 65;
pub const SO_RCVTIMEO_NEW: i32 = 66;
pub const SO_SNDTIMEO_NEW: i32 = 67;
pub const SO_DETACH_REUSEPORT_BPF: i32 = 68;
pub const SO_PREFERRED_BUSY_POLL: i32 = 69;
pub const SO_BUSY_POLL_BUDGET: i32 = 70;
}
pub mod tcp {
pub const TCP_NODELAY: i32 = 1;
pub const TCP_MAXSEG: i32 = 2;
pub const TCP_CORK: i32 = 3;
pub const TCP_KEEPIDLE: i32 = 4;
pub const TCP_KEEPINTVL: i32 = 5;
pub const TCP_KEEPCNT: i32 = 6;
pub const TCP_SYNCNT: i32 = 7;
pub const TCP_LINGER2: i32 = 8;
pub const TCP_DEFER_ACCEPT: i32 = 9;
pub const TCP_WINDOW_CLAMP: i32 = 10;
pub const TCP_INFO: i32 = 11;
pub const TCP_QUICKACK: i32 = 12;
pub const TCP_CONGESTION: i32 = 13;
pub const TCP_MD5SIG: i32 = 14;
pub const TCP_THIN_LINEAR_TIMEOUTS: i32 = 16;
pub const TCP_THIN_DUPACK: i32 = 17;
pub const TCP_USER_TIMEOUT: i32 = 18;
pub const TCP_REPAIR: i32 = 19;
pub const TCP_REPAIR_QUEUE: i32 = 20;
pub const TCP_QUEUE_SEQ: i32 = 21;
pub const TCP_REPAIR_OPTIONS: i32 = 22;
pub const TCP_FASTOPEN: i32 = 23;
pub const TCP_TIMESTAMP: i32 = 24;
pub const TCP_NOTSENT_LOWAT: i32 = 25;
pub const TCP_CC_INFO: i32 = 26;
pub const TCP_SAVE_SYN: i32 = 27;
pub const TCP_SAVED_SYN: i32 = 28;
pub const TCP_REPAIR_WINDOW: i32 = 29;
pub const TCP_FASTOPEN_CONNECT: i32 = 30;
pub const TCP_ULP: i32 = 31;
pub const TCP_MD5SIG_EXT: i32 = 32;
pub const TCP_FASTOPEN_KEY: i32 = 33;
pub const TCP_FASTOPEN_NO_COOKIE: i32 = 34;
pub const TCP_ZEROCOPY_RECEIVE: i32 = 35;
pub const TCP_INQ: i32 = 36;
pub const TCP_TX_DELAY: i32 = 37;
}
pub mod udp {
pub const UDP_CORK: i32 = 1;
pub const UDP_ENCAP: i32 = 100;
pub const UDP_NO_CHECK6_TX: i32 = 101;
pub const UDP_NO_CHECK6_RX: i32 = 102;
pub const UDP_SEGMENT: i32 = 103;
pub const UDP_GRO: i32 = 104;
}
pub mod ip {
pub const IP_TOS: i32 = 1;
pub const IP_TTL: i32 = 2;
pub const IP_HDRINCL: i32 = 3;
pub const IP_OPTIONS: i32 = 4;
pub const IP_ROUTER_ALERT: i32 = 5;
pub const IP_RECVOPTS: i32 = 6;
pub const IP_RETOPTS: i32 = 7;
pub const IP_PKTINFO: i32 = 8;
pub const IP_PKTOPTIONS: i32 = 9;
pub const IP_MTU_DISCOVER: i32 = 10;
pub const IP_RECVERR: i32 = 11;
pub const IP_RECVTTL: i32 = 12;
pub const IP_RECVTOS: i32 = 13;
pub const IP_MTU: i32 = 14;
pub const IP_FREEBIND: i32 = 15;
pub const IP_IPSEC_POLICY: i32 = 16;
pub const IP_XFRM_POLICY: i32 = 17;
pub const IP_PASSSEC: i32 = 18;
pub const IP_TRANSPARENT: i32 = 19;
pub const IP_ORIGDSTADDR: i32 = 20;
pub const IP_RECVORIGDSTADDR: i32 = 20;
pub const IP_MINTTL: i32 = 21;
pub const IP_NODEFRAG: i32 = 22;
pub const IP_BIND_ADDRESS_NO_PORT: i32 = 24;
pub const IP_RECVFRAGSIZE: i32 = 25;
pub const IP_PMTUDISC_DONT: i32 = 0;
pub const IP_PMTUDISC_WANT: i32 = 1;
pub const IP_PMTUDISC_DO: i32 = 2;
pub const IP_PMTUDISC_PROBE: i32 = 3;
pub const IP_PMTUDISC_INTERFACE: i32 = 4;
pub const IP_PMTUDISC_OMIT: i32 = 5;
}
pub mod ipv6 {
pub const IPV6_ADDRFORM: i32 = 1;
pub const IPV6_PKTINFO: i32 = 2;
pub const IPV6_HOPOPTS: i32 = 3;
pub const IPV6_DSTOPTS: i32 = 4;
pub const IPV6_RTHDR: i32 = 5;
pub const IPV6_PKTOPTIONS: i32 = 6;
pub const IPV6_CHECKSUM: i32 = 7;
pub const IPV6_HOPLIMIT: i32 = 8;
pub const IPV6_NEXTHOP: i32 = 9;
pub const IPV6_AUTHHDR: i32 = 10;
pub const IPV6_FLOWINFO: i32 = 11;
pub const IPV6_UNICAST_HOPS: i32 = 16;
pub const IPV6_MULTICAST_IF: i32 = 17;
pub const IPV6_MULTICAST_HOPS: i32 = 18;
pub const IPV6_MULTICAST_LOOP: i32 = 19;
pub const IPV6_ADD_MEMBERSHIP: i32 = 20;
pub const IPV6_DROP_MEMBERSHIP: i32 = 21;
pub const IPV6_ROUTER_ALERT: i32 = 22;
pub const IPV6_MTU_DISCOVER: i32 = 23;
pub const IPV6_MTU: i32 = 24;
pub const IPV6_RECVERR: i32 = 25;
pub const IPV6_V6ONLY: i32 = 26;
pub const IPV6_JOIN_ANYCAST: i32 = 27;
pub const IPV6_LEAVE_ANYCAST: i32 = 28;
pub const IPV6_IPSEC_POLICY: i32 = 34;
pub const IPV6_XFRM_POLICY: i32 = 35;
pub const IPV6_RECVPKTINFO: i32 = 49;
pub const IPV6_PKTINFO_SEND: i32 = 2;
pub const IPV6_RECVHOPLIMIT: i32 = 51;
pub const IPV6_RECVHOPOPTS: i32 = 53;
pub const IPV6_RECVDSTOPTS: i32 = 58;
pub const IPV6_RECVRTHDR: i32 = 56;
pub const IPV6_RECVTCLASS: i32 = 66;
pub const IPV6_TCLASS: i32 = 67;
pub const IPV6_AUTOFLOWLABEL: i32 = 70;
pub const IPV6_ADDR_PREFERENCES: i32 = 72;
pub const IPV6_MINHOPCOUNT: i32 = 73;
pub const IPV6_ORIGDSTADDR: i32 = 74;
pub const IPV6_RECVORIGDSTADDR: i32 = 74;
pub const IPV6_TRANSPARENT: i32 = 75;
pub const IPV6_UNICAST_IF: i32 = 76;
pub const IPV6_RECVFRAGSIZE: i32 = 77;
pub const IPV6_FREEBIND: i32 = 78;
}
pub mod icmp6 {
pub const ICMP6_FILTER: i32 = 1;
pub const ICMP6_FILTER_BLOCKALL: u32 = 1;
pub const ICMP6_FILTER_PASSALL: u32 = 2;
pub const ICMP6_FILTER_BLOCKOTHERS: u32 = 3;
pub const ICMP6_FILTER_PASSONLY: u32 = 4;
}
pub mod msg {
pub const MSG_OOB: i32 = 0x01;
pub const MSG_PEEK: i32 = 0x02;
pub const MSG_DONTROUTE: i32 = 0x04;
pub const MSG_CTRUNC: i32 = 0x08;
pub const MSG_PROXY: i32 = 0x10;
pub const MSG_TRUNC: i32 = 0x20;
pub const MSG_DONTWAIT: i32 = 0x40;
pub const MSG_EOR: i32 = 0x80;
pub const MSG_WAITALL: i32 = 0x100;
pub const MSG_FIN: i32 = 0x200;
pub const MSG_SYN: i32 = 0x400;
pub const MSG_CONFIRM: i32 = 0x800;
pub const MSG_RST: i32 = 0x1000;
pub const MSG_ERRQUEUE: i32 = 0x2000;
pub const MSG_NOSIGNAL: i32 = 0x4000;
pub const MSG_MORE: i32 = 0x8000;
pub const MSG_CMSG_CLOEXEC: i32 = 0x40000000;
pub const MSG_FASTOPEN: i32 = 0x20000000;
pub const MSG_ZEROCOPY: i32 = 0x4000000;
pub const MSG_BATCH: i32 = 0x40000;
}
pub mod poll {
pub const POLLIN: i16 = 0x001;
pub const POLLPRI: i16 = 0x002;
pub const POLLOUT: i16 = 0x004;
pub const POLLERR: i16 = 0x008;
pub const POLLHUP: i16 = 0x010;
pub const POLLNVAL: i16 = 0x020;
pub const POLLRDHUP: i16 = 0x2000;
pub const POLLRDBAND: i16 = 0x0080;
pub const POLLWRBAND: i16 = 0x0100;
pub const POLLRDNORM: i16 = 0x0040;
pub const POLLWRNORM: i16 = 0x0100;
}
pub mod epoll {
pub const EPOLL_CTL_ADD: i32 = 1;
pub const EPOLL_CTL_DEL: i32 = 2;
pub const EPOLL_CTL_MOD: i32 = 3;
pub const EPOLLIN: u32 = 0x001;
pub const EPOLLOUT: u32 = 0x004;
pub const EPOLLPRI: u32 = 0x002;
pub const EPOLLERR: u32 = 0x008;
pub const EPOLLHUP: u32 = 0x010;
pub const EPOLLRDHUP: u32 = 0x2000;
pub const EPOLLET: u32 = 1u32 << 31;
pub const EPOLLONESHOT: u32 = 1u32 << 30;
pub const EPOLLWAKEUP: u32 = 1u32 << 29;
pub const EPOLLEXCLUSIVE: u32 = 1u32 << 28;
pub const EPOLL_CLOEXEC: i32 = 0o2000000;
}
pub mod ai {
pub const AI_PASSIVE: i32 = 0x0001;
pub const AI_CANONNAME: i32 = 0x0002;
pub const AI_NUMERICHOST: i32 = 0x0004;
pub const AI_NUMERICSERV: i32 = 0x0008;
pub const AI_V4MAPPED: i32 = 0x0800;
pub const AI_ALL: i32 = 0x0010;
pub const AI_ADDRCONFIG: i32 = 0x0020;
pub const AI_IDN: i32 = 0x0040;
pub const AI_CANONIDN: i32 = 0x0080;
pub const AI_IDN_ALLOW_UNASSIGNED: i32 = 0x0100;
pub const AI_IDN_USE_STD3_ASCII_RULES: i32 = 0x0200;
pub const AI_NUMERICSCOPE: i32 = 0x0400;
}
pub mod ni {
pub const NI_NUMERICHOST: i32 = 0x02;
pub const NI_NUMERICSERV: i32 = 0x08;
pub const NI_NOFQDN: i32 = 0x01;
pub const NI_NAMEREQD: i32 = 0x04;
pub const NI_DGRAM: i32 = 0x10;
pub const NI_IDN: i32 = 0x20;
pub const NI_IDN_ALLOW_UNASSIGNED: i32 = 0x40;
pub const NI_IDN_USE_STD3_ASCII_RULES: i32 = 0x80;
}
pub mod shutdown {
pub const SHUT_RD: i32 = 0;
pub const SHUT_WR: i32 = 1;
pub const SHUT_RDWR: i32 = 2;
}
pub mod inaddr {
pub const INADDR_ANY: u32 = 0x00000000;
pub const INADDR_BROADCAST: u32 = 0xFFFFFFFF;
pub const INADDR_LOOPBACK: u32 = 0x7F000001;
pub const INADDR_NONE: u32 = 0xFFFFFFFF;
}
pub mod inet6 {
pub const IN6ADDR_ANY_INIT: [u8; 16] = [0u8; 16];
pub const IN6ADDR_LOOPBACK_INIT: [u8; 16] =
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
}
pub mod fcntl {
pub const F_GETFL: i32 = 3;
pub const F_SETFL: i32 = 4;
pub const F_GETFD: i32 = 1;
pub const F_SETFD: i32 = 2;
pub const F_GETOWN: i32 = 9;
pub const F_SETOWN: i32 = 8;
pub const O_NONBLOCK: i32 = 0o4000;
pub const O_ASYNC: i32 = 0o20000;
pub const FD_CLOEXEC: i32 = 1;
}
}
pub use x86_protocol_headers::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct X86InAddr {
pub s_addr: u32,
}
impl X86InAddr {
pub fn new(addr: u32) -> Self {
Self { s_addr: addr }
}
pub fn from_octets(a: u8, b: u8, c: u8, d: u8) -> Self {
Self {
s_addr: u32::from_be_bytes([a, b, c, d]),
}
}
pub fn to_octets(&self) -> [u8; 4] {
self.s_addr.to_be_bytes()
}
pub fn is_loopback(&self) -> bool {
self.s_addr.to_be_bytes()[0] == 127
}
pub fn is_multicast(&self) -> bool {
self.s_addr.to_be_bytes()[0] >= 224 && self.s_addr.to_be_bytes()[0] <= 239
}
pub fn is_private(&self) -> bool {
let b = self.s_addr.to_be_bytes();
(b[0] == 10) || (b[0] == 172 && b[1] >= 16 && b[1] <= 31) || (b[0] == 192 && b[1] == 168)
}
pub fn any() -> Self {
Self {
s_addr: inaddr::INADDR_ANY,
}
}
pub fn loopback() -> Self {
Self {
s_addr: inaddr::INADDR_LOOPBACK,
}
}
}
impl fmt::Display for X86InAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let b = self.s_addr.to_be_bytes();
write!(f, "{}.{}.{}.{}", b[0], b[1], b[2], b[3])
}
}
impl Default for X86InAddr {
fn default() -> Self {
Self::any()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct X86In6Addr {
pub s6_addr: [u8; 16],
}
impl X86In6Addr {
pub fn new(addr: [u8; 16]) -> Self {
Self { s6_addr: addr }
}
pub fn from_u128(addr: u128) -> Self {
Self {
s6_addr: addr.to_be_bytes(),
}
}
pub fn to_u128(&self) -> u128 {
u128::from_be_bytes(self.s6_addr)
}
pub fn from_segments(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Self {
let mut addr = [0u8; 16];
addr[0..2].copy_from_slice(&a.to_be_bytes());
addr[2..4].copy_from_slice(&b.to_be_bytes());
addr[4..6].copy_from_slice(&c.to_be_bytes());
addr[6..8].copy_from_slice(&d.to_be_bytes());
addr[8..10].copy_from_slice(&e.to_be_bytes());
addr[10..12].copy_from_slice(&f.to_be_bytes());
addr[12..14].copy_from_slice(&g.to_be_bytes());
addr[14..16].copy_from_slice(&h.to_be_bytes());
Self { s6_addr: addr }
}
pub fn to_segments(&self) -> [u16; 8] {
let mut segs = [0u16; 8];
for i in 0..8 {
let start = i * 2;
segs[i] = u16::from_be_bytes([self.s6_addr[start], self.s6_addr[start + 1]]);
}
segs
}
pub fn is_loopback(&self) -> bool {
self.s6_addr == inet6::IN6ADDR_LOOPBACK_INIT
}
pub fn is_unspecified(&self) -> bool {
self.s6_addr == inet6::IN6ADDR_ANY_INIT
}
pub fn is_multicast(&self) -> bool {
self.s6_addr[0] == 0xFF
}
pub fn is_link_local(&self) -> bool {
self.s6_addr[0] == 0xFE && (self.s6_addr[1] & 0xC0) == 0x80
}
pub fn is_site_local(&self) -> bool {
self.s6_addr[0] == 0xFE && (self.s6_addr[1] & 0xC0) == 0xC0
}
pub fn is_v4_mapped(&self) -> bool {
self.s6_addr[0..10] == [0u8; 10] && self.s6_addr[10] == 0xFF && self.s6_addr[11] == 0xFF
}
pub fn is_v4_compat(&self) -> bool {
self.s6_addr[0..12] == [0u8; 12]
}
pub fn any() -> Self {
Self::new(inet6::IN6ADDR_ANY_INIT)
}
pub fn loopback() -> Self {
Self::new(inet6::IN6ADDR_LOOPBACK_INIT)
}
}
impl fmt::Display for X86In6Addr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_v4_mapped() {
let v4 = X86InAddr::from_octets(
self.s6_addr[12],
self.s6_addr[13],
self.s6_addr[14],
self.s6_addr[15],
);
return write!(f, "::ffff:{}", v4);
}
let segs = self.to_segments();
let mut best_start = 0usize;
let mut best_len = 0usize;
let mut cur_start = 0usize;
let mut cur_len = 0usize;
for (i, &s) in segs.iter().enumerate() {
if s == 0 {
if cur_len == 0 {
cur_start = i;
}
cur_len += 1;
} else if cur_len > 0 {
if cur_len > best_len {
best_start = cur_start;
best_len = cur_len;
}
cur_len = 0;
}
}
if cur_len > best_len {
best_start = cur_start;
best_len = cur_len;
}
if best_len < 2 {
best_len = 0;
}
let mut first = true;
let mut i = 0;
while i < 8 {
if best_len > 0 && i == best_start {
if first {
write!(f, "::")?;
} else {
write!(f, ":")?;
}
first = false;
i += best_len;
continue;
}
if !first {
write!(f, ":")?;
}
write!(f, "{:x}", segs[i]);
i += 1;
}
Ok(())
}
}
impl Default for X86In6Addr {
fn default() -> Self {
Self::any()
}
}
#[derive(Debug, Clone)]
pub struct X86SockAddr {
pub sa_family: u16,
pub sa_data: [u8; 14],
}
impl X86SockAddr {
pub fn new(family: u16) -> Self {
Self {
sa_family: family,
sa_data: [0u8; 14],
}
}
}
#[derive(Debug, Clone)]
pub struct X86SockAddrIn {
pub sin_family: u16,
pub sin_port: u16,
pub sin_addr: X86InAddr,
pub sin_zero: [u8; 8],
}
impl X86SockAddrIn {
pub fn new(addr: X86InAddr, port: u16) -> Self {
Self {
sin_family: af::AF_INET,
sin_port: port.to_be(),
sin_addr: addr,
sin_zero: [0u8; 8],
}
}
pub fn from_str(host: &str, port: u16) -> Option<Self> {
let addr = parse_ipv4(host)?;
Some(Self::new(addr, port))
}
pub fn port(&self) -> u16 {
u16::from_be(self.sin_port)
}
}
fn parse_ipv4(s: &str) -> Option<X86InAddr> {
let parts: Vec<&str> = s.split('.').collect();
if parts.len() != 4 {
return None;
}
let a = parts[0].parse::<u8>().ok()?;
let b = parts[1].parse::<u8>().ok()?;
let c = parts[2].parse::<u8>().ok()?;
let d = parts[3].parse::<u8>().ok()?;
Some(X86InAddr::from_octets(a, b, c, d))
}
#[derive(Debug, Clone)]
pub struct X86SockAddrIn6 {
pub sin6_family: u16,
pub sin6_port: u16,
pub sin6_flowinfo: u32,
pub sin6_addr: X86In6Addr,
pub sin6_scope_id: u32,
}
impl X86SockAddrIn6 {
pub fn new(addr: X86In6Addr, port: u16) -> Self {
Self {
sin6_family: af::AF_INET6,
sin6_port: port.to_be(),
sin6_flowinfo: 0,
sin6_addr: addr,
sin6_scope_id: 0,
}
}
pub fn port(&self) -> u16 {
u16::from_be(self.sin6_port)
}
}
#[derive(Debug, Clone)]
pub struct X86SockAddrStorage {
pub ss_family: u16,
pub __ss_padding: [u8; 118],
pub __ss_align: u64,
}
impl X86SockAddrStorage {
pub fn new() -> Self {
Self {
ss_family: af::AF_UNSPEC,
__ss_padding: [0u8; 118],
__ss_align: 0,
}
}
pub fn family(&self) -> u16 {
self.ss_family
}
}
impl Default for X86SockAddrStorage {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct X86SockAddrUn {
pub sun_family: u16,
pub sun_path: [u8; 108],
}
impl X86SockAddrUn {
pub fn new(path: &str) -> Self {
let mut sun_path = [0u8; 108];
let bytes = path.as_bytes();
let len = bytes.len().min(107);
sun_path[..len].copy_from_slice(&bytes[..len]);
Self {
sun_family: af::AF_UNIX,
sun_path,
}
}
pub fn path(&self) -> Option<&str> {
let end = self.sun_path.iter().position(|&b| b == 0).unwrap_or(108);
std::str::from_utf8(&self.sun_path[..end]).ok()
}
}
#[derive(Debug, Clone)]
pub struct X86AddrInfo {
pub ai_flags: i32,
pub ai_family: i32,
pub ai_socktype: i32,
pub ai_protocol: i32,
pub ai_addrlen: u32,
pub ai_canonname: Option<String>,
pub ai_addr: Option<X86SockAddr>,
pub ai_next: Option<Box<X86AddrInfo>>,
}
impl X86AddrInfo {
pub fn new() -> Self {
Self {
ai_flags: 0,
ai_family: af::AF_UNSPEC as i32,
ai_socktype: 0,
ai_protocol: 0,
ai_addrlen: 0,
ai_canonname: None,
ai_addr: None,
ai_next: None,
}
}
pub fn with_hints(family: i32, socktype: i32, protocol: i32, flags: i32) -> Self {
Self {
ai_flags: flags,
ai_family: family,
ai_socktype: socktype,
ai_protocol: protocol,
ai_addrlen: 0,
ai_canonname: None,
ai_addr: None,
ai_next: None,
}
}
pub fn chain_length(&self) -> usize {
let mut count = 1;
let mut cur = &self.ai_next;
while let Some(next) = cur {
count += 1;
cur = &next.ai_next;
}
count
}
}
impl Default for X86AddrInfo {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct X86HostEnt {
pub h_name: String,
pub h_aliases: Vec<String>,
pub h_addrtype: i32,
pub h_length: i32,
pub h_addr_list: Vec<Vec<u8>>,
}
impl X86HostEnt {
pub fn new(name: String, addrtype: i32, addr_len: i32, addrs: Vec<Vec<u8>>) -> Self {
Self {
h_name: name,
h_aliases: Vec::new(),
h_addrtype: addrtype,
h_length: addr_len,
h_addr_list: addrs,
}
}
}
#[derive(Debug, Clone)]
pub struct X86IfAddrs {
pub ifa_name: String,
pub ifa_flags: u32,
pub ifa_addr: Option<X86SockAddr>,
pub ifa_netmask: Option<X86SockAddr>,
pub ifa_broadaddr: Option<X86SockAddr>,
pub ifa_dstaddr: Option<X86SockAddr>,
pub ifa_data: Vec<u8>,
}
impl X86IfAddrs {
pub fn new(name: &str) -> Self {
Self {
ifa_name: name.to_string(),
ifa_flags: 0,
ifa_addr: None,
ifa_netmask: None,
ifa_broadaddr: None,
ifa_dstaddr: None,
ifa_data: Vec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct X86IfReq {
pub ifr_name: [u8; 16],
pub ifr_addr: X86SockAddr,
}
impl X86IfReq {
pub fn new(name: &str) -> Self {
let mut ifr_name = [0u8; 16];
let bytes = name.as_bytes();
let len = bytes.len().min(15);
ifr_name[..len].copy_from_slice(&bytes[..len]);
Self {
ifr_name,
ifr_addr: X86SockAddr::new(af::AF_UNSPEC),
}
}
pub fn name(&self) -> Option<&str> {
let end = self.ifr_name.iter().position(|&b| b == 0).unwrap_or(16);
std::str::from_utf8(&self.ifr_name[..end]).ok()
}
}
#[derive(Debug, Clone)]
pub struct X86IoVec {
pub iov_base: Vec<u8>,
pub iov_len: usize,
}
impl X86IoVec {
pub fn new(data: Vec<u8>) -> Self {
let len = data.len();
Self {
iov_base: data,
iov_len: len,
}
}
pub fn from_slice(data: &[u8]) -> Self {
Self::new(data.to_vec())
}
pub fn as_slice(&self) -> &[u8] {
&self.iov_base[..self.iov_len.min(self.iov_base.len())]
}
}
#[derive(Debug, Clone)]
pub struct X86MsgHdr {
pub msg_name: Option<X86SockAddrStorage>,
pub msg_namelen: u32,
pub msg_iov: Vec<X86IoVec>,
pub msg_control: Vec<u8>,
pub msg_controllen: u32,
pub msg_flags: i32,
}
impl X86MsgHdr {
pub fn new() -> Self {
Self {
msg_name: None,
msg_namelen: 0,
msg_iov: Vec::new(),
msg_control: Vec::new(),
msg_controllen: 0,
msg_flags: 0,
}
}
pub fn with_iov(mut self, iov: Vec<X86IoVec>) -> Self {
self.msg_iov = iov;
self
}
pub fn total_data_len(&self) -> usize {
self.msg_iov.iter().map(|v| v.iov_len).sum()
}
}
impl Default for X86MsgHdr {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct X86CMsgHdr {
pub cmsg_len: usize,
pub cmsg_level: i32,
pub cmsg_type: i32,
pub cmsg_data: Vec<u8>,
}
impl X86CMsgHdr {
pub fn new(level: i32, cmsg_type: i32, data: Vec<u8>) -> Self {
let cmsg_len = 16 + data.len(); Self {
cmsg_len,
cmsg_level: level,
cmsg_type,
cmsg_data: data,
}
}
pub fn ancillary_data_space(len: usize) -> usize {
let hdr_len = 16; (hdr_len + len + 7) & !7 }
}
pub struct X86EpollEvent {
pub events: u32,
pub data: X86EpollData,
}
impl Clone for X86EpollEvent {
fn clone(&self) -> Self {
X86EpollEvent {
events: self.events,
data: self.data,
}
}
}
impl std::fmt::Debug for X86EpollEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("X86EpollEvent")
.field("events", &self.events)
.field("data", &unsafe { self.data.fd })
.finish()
}
}
#[derive(Clone, Copy)]
pub union X86EpollData {
pub ptr: u64,
pub fd: i32,
pub u32: u32,
pub u64: u64,
}
impl X86EpollData {
pub fn from_fd(fd: i32) -> Self {
Self { fd }
}
pub fn fd(&self) -> i32 {
unsafe { self.fd }
}
}
impl X86EpollEvent {
pub fn new(events: u32, fd: i32) -> Self {
Self {
events,
data: X86EpollData::from_fd(fd),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct X86PollFd {
pub fd: i32,
pub events: i16,
pub revents: i16,
}
impl X86PollFd {
pub fn new(fd: i32, events: i16) -> Self {
Self {
fd,
events,
revents: 0,
}
}
pub fn can_read(&self) -> bool {
(self.revents & poll::POLLIN) != 0
}
pub fn can_write(&self) -> bool {
(self.revents & poll::POLLOUT) != 0
}
pub fn has_error(&self) -> bool {
(self.revents & (poll::POLLERR | poll::POLLHUP | poll::POLLNVAL)) != 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86NetPlatform {
Linux,
Windows,
MacOS,
FreeBSD,
NetBSD,
OpenBSD,
Solaris,
}
impl X86NetPlatform {
pub fn has_epoll(&self) -> bool {
matches!(self, Self::Linux)
}
pub fn has_kqueue(&self) -> bool {
matches!(
self,
Self::MacOS | Self::FreeBSD | Self::OpenBSD | Self::NetBSD
)
}
pub fn has_iocp(&self) -> bool {
matches!(self, Self::Windows)
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Linux => "linux",
Self::Windows => "windows",
Self::MacOS => "macos",
Self::FreeBSD => "freebsd",
Self::NetBSD => "netbsd",
Self::OpenBSD => "openbsd",
Self::Solaris => "solaris",
}
}
}
impl Default for X86NetPlatform {
fn default() -> Self {
Self::Linux
}
}
impl fmt::Display for X86NetPlatform {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
pub struct X86Networking {
pub platform: X86NetPlatform,
pub socket_api: X86SocketAPI,
pub tls_integration: X86TLSIntegration,
pub http_support: X86HTTPSupport,
pub dns_resolver: X86DNSResolver,
pub ipv6_enabled: bool,
pub tcp_fastopen: bool,
pub reuse_port_supported: bool,
pub so_mark_supported: bool,
pub network_stats: X86NetworkingStats,
}
pub struct X86NetworkingStats {
pub sockets_created: u64,
pub sockets_closed: u64,
pub bytes_sent: u64,
pub bytes_received: u64,
pub connections_accepted: u64,
pub connections_initiated: u64,
pub dns_queries: u64,
pub tls_handshakes: u64,
pub http_requests: u64,
pub errors: u64,
}
impl X86NetworkingStats {
pub fn new() -> Self {
Self {
sockets_created: 0,
sockets_closed: 0,
bytes_sent: 0,
bytes_received: 0,
connections_accepted: 0,
connections_initiated: 0,
dns_queries: 0,
tls_handshakes: 0,
http_requests: 0,
errors: 0,
}
}
pub fn record_socket_created(&mut self) {
self.sockets_created += 1;
}
pub fn record_socket_closed(&mut self) {
self.sockets_closed += 1;
}
pub fn record_send(&mut self, bytes: u64) {
self.bytes_sent += bytes;
}
pub fn record_recv(&mut self, bytes: u64) {
self.bytes_received += bytes;
}
pub fn record_accept(&mut self) {
self.connections_accepted += 1;
}
pub fn record_connect(&mut self) {
self.connections_initiated += 1;
}
pub fn record_dns(&mut self) {
self.dns_queries += 1;
}
pub fn record_tls(&mut self) {
self.tls_handshakes += 1;
}
pub fn record_http(&mut self) {
self.http_requests += 1;
}
pub fn record_error(&mut self) {
self.errors += 1;
}
pub fn active_sockets(&self) -> u64 {
self.sockets_created.saturating_sub(self.sockets_closed)
}
pub fn summary(&self) -> String {
format!(
"sockets: {}/{} active, sent: {}B, recv: {}B, accept: {}, connect: {}, dns: {}, tls: {}, http: {}, errors: {}",
self.active_sockets(),
self.sockets_created,
self.bytes_sent,
self.bytes_received,
self.connections_accepted,
self.connections_initiated,
self.dns_queries,
self.tls_handshakes,
self.http_requests,
self.errors,
)
}
}
impl Default for X86NetworkingStats {
fn default() -> Self {
Self::new()
}
}
impl X86Networking {
pub fn new_linux_x86_64() -> Self {
Self {
platform: X86NetPlatform::Linux,
socket_api: X86SocketAPI::new_linux(),
tls_integration: X86TLSIntegration::new_openssl(),
http_support: X86HTTPSupport::new(),
dns_resolver: X86DNSResolver::new_default(),
ipv6_enabled: true,
tcp_fastopen: true,
reuse_port_supported: true,
so_mark_supported: true,
network_stats: X86NetworkingStats::new(),
}
}
pub fn new_linux_x86_32() -> Self {
let mut net = Self::new_linux_x86_64();
net.tcp_fastopen = false;
net
}
pub fn new_windows_x86_64() -> Self {
Self {
platform: X86NetPlatform::Windows,
socket_api: X86SocketAPI::new_windows(),
tls_integration: X86TLSIntegration::new_openssl(),
http_support: X86HTTPSupport::new(),
dns_resolver: X86DNSResolver::new_default(),
ipv6_enabled: true,
tcp_fastopen: false,
reuse_port_supported: false,
so_mark_supported: false,
network_stats: X86NetworkingStats::new(),
}
}
pub fn new_macos_x86_64() -> Self {
Self {
platform: X86NetPlatform::MacOS,
socket_api: X86SocketAPI::new_bsd(),
tls_integration: X86TLSIntegration::new_secure_transport(),
http_support: X86HTTPSupport::new(),
dns_resolver: X86DNSResolver::new_default(),
ipv6_enabled: true,
tcp_fastopen: true,
reuse_port_supported: true,
so_mark_supported: false,
network_stats: X86NetworkingStats::new(),
}
}
pub fn new_freebsd_x86_64() -> Self {
Self {
platform: X86NetPlatform::FreeBSD,
socket_api: X86SocketAPI::new_bsd(),
tls_integration: X86TLSIntegration::new_openssl(),
http_support: X86HTTPSupport::new(),
dns_resolver: X86DNSResolver::new_default(),
ipv6_enabled: true,
tcp_fastopen: true,
reuse_port_supported: true,
so_mark_supported: false,
network_stats: X86NetworkingStats::new(),
}
}
pub fn describe(&self) -> String {
format!(
"X86Networking {{ platform: {}, ipv6: {}, tfo: {}, reuse_port: {}, epoll: {}, kqueue: {}, iocp: {} }}",
self.platform.as_str(),
self.ipv6_enabled,
self.tcp_fastopen,
self.reuse_port_supported,
self.platform.has_epoll(),
self.platform.has_kqueue(),
self.platform.has_iocp(),
)
}
pub fn get_protocol_header(&self, header_name: &str) -> Option<&'static str> {
match header_name {
"netinet/in.h" => Some("Provides internet address families, IPPROTO_*, INADDR_*, sockaddr_in, sockaddr_in6, IP_*, IPV6_* constants"),
"netinet/tcp.h" => Some("Provides TCP_NODELAY, TCP_KEEPIDLE, TCP_QUICKACK, TCP_CORK, TCP_INFO, etc."),
"netinet/udp.h" => Some("Provides UDP_CORK, UDP_SEGMENT, UDP_GRO options"),
"netinet/ip.h" => Some("Provides IP_TOS, IP_TTL, IP_HDRINCL, IP_PKTINFO options"),
"netinet/ip6.h" => Some("Provides IPV6_V6ONLY, IPV6_PKTINFO, IPV6_UNICAST_HOPS, IPV6_FLOWINFO"),
"netinet/icmp6.h" => Some("Provides ICMP6_FILTER for raw IPv6 ICMP sockets"),
"arpa/inet.h" => Some("Provides inet_pton(), inet_ntop(), htons(), htonl(), ntohs(), ntohl() declarations"),
"netdb.h" => Some("Provides getaddrinfo(), freeaddrinfo(), getnameinfo(), addrinfo, hostent"),
"sys/socket.h" => Some("Provides socket(), bind(), listen(), accept(), connect(), send(), recv(), sockaddr"),
"sys/un.h" => Some("Provides sockaddr_un for UNIX domain sockets"),
"net/if.h" => Some("Provides ifreq, IFNAMSIZ, IFF_* flags for network interfaces"),
"ifaddrs.h" => Some("Provides getifaddrs(), freeifaddrs(), ifaddrs struct"),
"sys/epoll.h" => Some("Provides epoll_create(), epoll_ctl(), epoll_wait(), epoll_event (Linux)"),
"sys/event.h" => Some("Provides kqueue(), kevent(), EVFILT_*, EV_* (BSD/macOS)"),
_ => None,
}
}
pub fn to_include_directives(&self) -> Vec<String> {
vec![
"#include <sys/socket.h>".to_string(),
"#include <netinet/in.h>".to_string(),
"#include <netinet/tcp.h>".to_string(),
"#include <netinet/udp.h>".to_string(),
"#include <netinet/ip.h>".to_string(),
"#include <arpa/inet.h>".to_string(),
"#include <netdb.h>".to_string(),
"#include <sys/un.h>".to_string(),
"#include <net/if.h>".to_string(),
"#include <sys/epoll.h>".to_string(),
"#include <fcntl.h>".to_string(),
"#include <poll.h>".to_string(),
]
}
}
impl Default for X86Networking {
fn default() -> Self {
Self::new_linux_x86_64()
}
}
pub type X86SocketFd = i32;
pub const X86_INVALID_SOCKET: X86SocketFd = -1;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum X86AddressFamily {
IPv4,
IPv6,
Unix,
Netlink,
Packet,
Unspecified,
Other(u16),
}
impl X86AddressFamily {
pub fn to_native(&self) -> u16 {
match self {
Self::IPv4 => af::AF_INET,
Self::IPv6 => af::AF_INET6,
Self::Unix => af::AF_UNIX,
Self::Netlink => af::AF_NETLINK,
Self::Packet => af::AF_PACKET,
Self::Unspecified => af::AF_UNSPEC,
Self::Other(v) => *v,
}
}
pub fn from_native(v: u16) -> Self {
match v {
af::AF_INET => Self::IPv4,
af::AF_INET6 => Self::IPv6,
af::AF_UNIX => Self::Unix,
af::AF_NETLINK => Self::Netlink,
af::AF_PACKET => Self::Packet,
af::AF_UNSPEC => Self::Unspecified,
_ => Self::Other(v),
}
}
}
impl fmt::Display for X86AddressFamily {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::IPv4 => write!(f, "AF_INET"),
Self::IPv6 => write!(f, "AF_INET6"),
Self::Unix => write!(f, "AF_UNIX"),
Self::Netlink => write!(f, "AF_NETLINK"),
Self::Packet => write!(f, "AF_PACKET"),
Self::Unspecified => write!(f, "AF_UNSPEC"),
Self::Other(v) => write!(f, "AF_UNKNOWN({})", v),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86SocketType {
Stream,
Datagram,
Raw,
SeqPacket,
NonBlock(i32),
Other(i32),
}
impl X86SocketType {
pub fn to_native(&self) -> i32 {
match self {
Self::Stream => sock_type::SOCK_STREAM,
Self::Datagram => sock_type::SOCK_DGRAM,
Self::Raw => sock_type::SOCK_RAW,
Self::SeqPacket => sock_type::SOCK_SEQPACKET,
Self::NonBlock(base) => base | sock_type::SOCK_NONBLOCK,
Self::Other(v) => *v,
}
}
pub fn from_native(v: i32) -> Self {
let base = v & !(sock_type::SOCK_NONBLOCK | sock_type::SOCK_CLOEXEC);
match base {
sock_type::SOCK_STREAM => Self::Stream,
sock_type::SOCK_DGRAM => Self::Datagram,
sock_type::SOCK_RAW => Self::Raw,
sock_type::SOCK_SEQPACKET => Self::SeqPacket,
_ => Self::Other(v),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86SocketProtocol {
TCP,
UDP,
ICMP,
Raw,
SCTP,
UDPLite,
Other(i32),
}
impl X86SocketProtocol {
pub fn to_native(&self) -> i32 {
match self {
Self::TCP => ipproto::IPPROTO_TCP,
Self::UDP => ipproto::IPPROTO_UDP,
Self::ICMP => ipproto::IPPROTO_ICMP,
Self::Raw => ipproto::IPPROTO_RAW,
Self::SCTP => ipproto::IPPROTO_SCTP,
Self::UDPLite => ipproto::IPPROTO_UDPLITE,
Self::Other(v) => *v,
}
}
}
#[derive(Debug, Clone)]
pub enum X86SocketOption {
ReuseAddr(bool),
ReusePort(bool),
KeepAlive(bool),
NoDelay(bool),
Broadcast(bool),
RecvBuf(i32),
SendBuf(i32),
RecvTimeout(Duration),
SendTimeout(Duration),
Linger(Option<Duration>),
TTL(u8),
IPv6Only(bool),
DontRoute(bool),
QuickAck(bool),
BindToDevice(String),
Mark(u32),
TCPFastOpen(bool, i32),
DontFragment(bool),
Priority(i32),
Timestamp(bool),
Error,
Type,
AcceptConn,
PeerCred,
}
impl X86SocketOption {
pub fn level_and_name(&self) -> (i32, i32) {
match self {
Self::ReuseAddr(_) => (sol::SOL_SOCKET, sockopt::SO_REUSEADDR),
Self::ReusePort(_) => (sol::SOL_SOCKET, sockopt::SO_REUSEPORT),
Self::KeepAlive(_) => (sol::SOL_SOCKET, sockopt::SO_KEEPALIVE),
Self::NoDelay(_) => (ipproto::IPPROTO_TCP, tcp::TCP_NODELAY),
Self::Broadcast(_) => (sol::SOL_SOCKET, sockopt::SO_BROADCAST),
Self::RecvBuf(_) => (sol::SOL_SOCKET, sockopt::SO_RCVBUF),
Self::SendBuf(_) => (sol::SOL_SOCKET, sockopt::SO_SNDBUF),
Self::RecvTimeout(_) => (sol::SOL_SOCKET, sockopt::SO_RCVTIMEO),
Self::SendTimeout(_) => (sol::SOL_SOCKET, sockopt::SO_SNDTIMEO),
Self::Linger(_) => (sol::SOL_SOCKET, sockopt::SO_LINGER),
Self::TTL(_) => (sol::SOL_IP, ip::IP_TTL),
Self::IPv6Only(_) => (sol::SOL_IPV6, ipv6::IPV6_V6ONLY),
Self::DontRoute(_) => (sol::SOL_SOCKET, sockopt::SO_DONTROUTE),
Self::QuickAck(_) => (ipproto::IPPROTO_TCP, tcp::TCP_QUICKACK),
Self::BindToDevice(_) => (sol::SOL_SOCKET, sockopt::SO_BINDTODEVICE),
Self::Mark(_) => (sol::SOL_SOCKET, sockopt::SO_MARK),
Self::TCPFastOpen(_, _) => (ipproto::IPPROTO_TCP, tcp::TCP_FASTOPEN),
Self::DontFragment(_) => (sol::SOL_IP, ip::IP_MTU_DISCOVER),
Self::Priority(_) => (sol::SOL_SOCKET, sockopt::SO_PRIORITY),
Self::Timestamp(_) => (sol::SOL_SOCKET, sockopt::SO_TIMESTAMP),
Self::Error => (sol::SOL_SOCKET, sockopt::SO_ERROR),
Self::Type => (sol::SOL_SOCKET, sockopt::SO_TYPE),
Self::AcceptConn => (sol::SOL_SOCKET, sockopt::SO_ACCEPTCONN),
Self::PeerCred => (sol::SOL_SOCKET, sockopt::SO_PEERCRED),
}
}
pub fn clang_option_name(&self) -> &'static str {
match self {
Self::ReuseAddr(_) => "SO_REUSEADDR",
Self::ReusePort(_) => "SO_REUSEPORT",
Self::KeepAlive(_) => "SO_KEEPALIVE",
Self::NoDelay(_) => "TCP_NODELAY",
Self::Broadcast(_) => "SO_BROADCAST",
Self::RecvBuf(_) => "SO_RCVBUF",
Self::SendBuf(_) => "SO_SNDBUF",
Self::RecvTimeout(_) => "SO_RCVTIMEO",
Self::SendTimeout(_) => "SO_SNDTIMEO",
Self::Linger(_) => "SO_LINGER",
Self::TTL(_) => "IP_TTL",
Self::IPv6Only(_) => "IPV6_V6ONLY",
Self::DontRoute(_) => "SO_DONTROUTE",
Self::QuickAck(_) => "TCP_QUICKACK",
Self::BindToDevice(_) => "SO_BINDTODEVICE",
Self::Mark(_) => "SO_MARK",
Self::TCPFastOpen(_, _) => "TCP_FASTOPEN",
Self::DontFragment(_) => "IP_MTU_DISCOVER",
Self::Priority(_) => "SO_PRIORITY",
Self::Timestamp(_) => "SO_TIMESTAMP",
Self::Error => "SO_ERROR",
Self::Type => "SO_TYPE",
Self::AcceptConn => "SO_ACCEPTCONN",
Self::PeerCred => "SO_PEERCRED",
}
}
}
#[derive(Debug, Clone)]
pub struct X86SocketHandle {
pub fd: X86SocketFd,
pub family: X86AddressFamily,
pub socket_type: X86SocketType,
pub protocol: X86SocketProtocol,
pub bound: bool,
pub listening: bool,
pub connected: bool,
pub nonblocking: bool,
pub reuse_addr: bool,
pub reuse_port: bool,
pub options: HashMap<String, X86SocketOption>,
}
impl X86SocketHandle {
pub fn new(
family: X86AddressFamily,
socket_type: X86SocketType,
protocol: X86SocketProtocol,
) -> Self {
Self {
fd: 0, family,
socket_type,
protocol,
bound: false,
listening: false,
connected: false,
nonblocking: false,
reuse_addr: false,
reuse_port: false,
options: HashMap::new(),
}
}
pub fn invalid() -> Self {
Self {
fd: X86_INVALID_SOCKET,
family: X86AddressFamily::Unspecified,
socket_type: X86SocketType::Other(0),
protocol: X86SocketProtocol::Other(0),
bound: false,
listening: false,
connected: false,
nonblocking: false,
reuse_addr: false,
reuse_port: false,
options: HashMap::new(),
}
}
pub fn is_valid(&self) -> bool {
self.fd != X86_INVALID_SOCKET
}
pub fn set_option(&mut self, opt: X86SocketOption) {
let name = opt.clang_option_name().to_string();
match &opt {
X86SocketOption::ReuseAddr(v) => self.reuse_addr = *v,
X86SocketOption::ReusePort(v) => self.reuse_port = *v,
_ => {}
}
self.options.insert(name, opt);
}
}
impl Default for X86SocketHandle {
fn default() -> Self {
Self::invalid()
}
}
pub struct X86SocketAPI {
pub platform: X86NetPlatform,
pub max_sockets: u32,
pub default_backlog: i32,
pub use_epoll: bool,
pub use_kqueue: bool,
pub use_iocp: bool,
pub enable_tcp_fastopen: bool,
pub enable_reuse_port: bool,
pub open_sockets: HashMap<X86SocketFd, X86SocketHandle>,
next_fd: X86SocketFd,
}
impl X86SocketAPI {
pub fn new_linux() -> Self {
Self {
platform: X86NetPlatform::Linux,
max_sockets: 65536,
default_backlog: 128,
use_epoll: true,
use_kqueue: false,
use_iocp: false,
enable_tcp_fastopen: true,
enable_reuse_port: true,
open_sockets: HashMap::new(),
next_fd: 3,
}
}
pub fn new_windows() -> Self {
Self {
platform: X86NetPlatform::Windows,
max_sockets: 65536,
default_backlog: 128,
use_epoll: false,
use_kqueue: false,
use_iocp: true,
enable_tcp_fastopen: false,
enable_reuse_port: false,
open_sockets: HashMap::new(),
next_fd: 3,
}
}
pub fn new_bsd() -> Self {
Self {
platform: X86NetPlatform::FreeBSD,
max_sockets: 65536,
default_backlog: 128,
use_epoll: false,
use_kqueue: true,
use_iocp: false,
enable_tcp_fastopen: true,
enable_reuse_port: true,
open_sockets: HashMap::new(),
next_fd: 3,
}
}
fn alloc_fd(&mut self) -> X86SocketFd {
let fd = self.next_fd;
self.next_fd += 1;
fd
}
pub fn socket(
&mut self,
family: X86AddressFamily,
socket_type: X86SocketType,
protocol: X86SocketProtocol,
) -> X86SocketFd {
let fd = self.alloc_fd();
let mut handle = X86SocketHandle::new(family, socket_type, protocol);
handle.fd = fd;
self.open_sockets.insert(fd, handle);
fd
}
pub fn bind(&mut self, fd: X86SocketFd, addr: &X86SockAddrIn) -> Result<(), String> {
let sock = self
.open_sockets
.get_mut(&fd)
.ok_or("EBADF: bad file descriptor")?;
if sock.bound {
return Err("EINVAL: already bound".to_string());
}
sock.bound = true;
Ok(())
}
pub fn listen(&mut self, fd: X86SocketFd, backlog: i32) -> Result<(), String> {
let sock = self
.open_sockets
.get_mut(&fd)
.ok_or("EBADF: bad file descriptor")?;
if !sock.bound {
return Err("EINVAL: socket not bound".to_string());
}
sock.listening = true;
let _ = backlog; Ok(())
}
pub fn accept(&mut self, fd: X86SocketFd) -> Result<(X86SocketFd, X86SockAddrIn), String> {
let _sock = self
.open_sockets
.get(&fd)
.ok_or("EBADF: bad file descriptor")?;
let client_fd = self.alloc_fd();
let client_addr = X86SockAddrIn::new(X86InAddr::from_octets(127, 0, 0, 1), 0);
let mut client = X86SocketHandle::new(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
client.fd = client_fd;
client.connected = true;
self.open_sockets.insert(client_fd, client);
Ok((client_fd, client_addr))
}
pub fn connect(&mut self, fd: X86SocketFd, addr: &X86SockAddrIn) -> Result<(), String> {
let sock = self
.open_sockets
.get_mut(&fd)
.ok_or("EBADF: bad file descriptor")?;
sock.connected = true;
let _ = addr;
Ok(())
}
pub fn send(&mut self, fd: X86SocketFd, buf: &[u8], flags: i32) -> Result<usize, String> {
let _sock = self
.open_sockets
.get(&fd)
.ok_or("EBADF: bad file descriptor")?;
let _ = flags;
Ok(buf.len())
}
pub fn recv(&mut self, fd: X86SocketFd, buf: &mut [u8], flags: i32) -> Result<usize, String> {
let _sock = self
.open_sockets
.get(&fd)
.ok_or("EBADF: bad file descriptor")?;
let _ = flags;
Ok(buf.len().min(1)) }
pub fn sendto(
&mut self,
fd: X86SocketFd,
buf: &[u8],
flags: i32,
dest_addr: &X86SockAddrIn,
) -> Result<usize, String> {
let _sock = self
.open_sockets
.get(&fd)
.ok_or("EBADF: bad file descriptor")?;
let _ = (flags, dest_addr);
Ok(buf.len())
}
pub fn recvfrom(
&mut self,
fd: X86SocketFd,
buf: &mut [u8],
flags: i32,
) -> Result<(usize, X86SockAddrIn), String> {
let _sock = self
.open_sockets
.get(&fd)
.ok_or("EBADF: bad file descriptor")?;
let _ = flags;
let addr = X86SockAddrIn::new(X86InAddr::from_octets(127, 0, 0, 1), 0);
Ok((buf.len().min(1), addr))
}
pub fn sendmsg(
&mut self,
fd: X86SocketFd,
msg: &X86MsgHdr,
flags: i32,
) -> Result<usize, String> {
let _sock = self
.open_sockets
.get(&fd)
.ok_or("EBADF: bad file descriptor")?;
let _ = flags;
Ok(msg.total_data_len())
}
pub fn recvmsg(
&mut self,
fd: X86SocketFd,
msg: &mut X86MsgHdr,
flags: i32,
) -> Result<usize, String> {
let _sock = self
.open_sockets
.get(&fd)
.ok_or("EBADF: bad file descriptor")?;
let _ = flags;
msg.msg_flags = 0;
Ok(msg.total_data_len().min(1))
}
pub fn getaddrinfo(
&self,
node: Option<&str>,
service: Option<&str>,
hints: Option<&X86AddrInfo>,
) -> Result<Vec<X86AddrInfo>, String> {
let mut results = Vec::new();
let family = hints.map(|h| h.ai_family).unwrap_or(af::AF_UNSPEC as i32);
let socktype = hints.map(|h| h.ai_socktype).unwrap_or(0);
let protocol = hints.map(|h| h.ai_protocol).unwrap_or(0);
let default_port: u16 = match service.and_then(|s| s.parse().ok()) {
Some(p) => p,
None => match service.unwrap_or("0") {
"http" => 80,
"https" => 443,
"ssh" => 22,
"ftp" => 21,
"smtp" => 25,
"dns" => 53,
_ => 0,
},
};
if family == af::AF_INET as i32 || family == af::AF_UNSPEC as i32 {
if let Some(node) = node {
if let Some(addr) = parse_ipv4(node) {
let mut ai = X86AddrInfo::with_hints(af::AF_INET as i32, socktype, protocol, 0);
ai.ai_addrlen = 16;
ai.ai_addr = Some(X86SockAddr::new(af::AF_INET));
results.push(ai);
}
}
}
if family == af::AF_INET6 as i32 || family == af::AF_UNSPEC as i32 {
if let Some(_node) = node {
let mut ai = X86AddrInfo::with_hints(af::AF_INET6 as i32, socktype, protocol, 0);
ai.ai_addrlen = 28;
ai.ai_addr = Some(X86SockAddr::new(af::AF_INET6));
results.push(ai);
}
}
if results.is_empty() {
let mut ai = X86AddrInfo::with_hints(af::AF_INET as i32, socktype, protocol, 0);
ai.ai_addrlen = 16;
ai.ai_canonname = node.map(|s| s.to_string());
results.push(ai);
}
Ok(results)
}
pub fn freeaddrinfo(&self, _results: Vec<X86AddrInfo>) {
}
pub fn getnameinfo(
&self,
addr: &X86SockAddrIn,
flags: i32,
) -> Result<(String, String), String> {
let host = if (flags & ni::NI_NUMERICHOST) != 0 {
format!("{}", addr.sin_addr)
} else {
format!("{}", addr.sin_addr)
};
let service = if (flags & ni::NI_NUMERICSERV) != 0 {
format!("{}", addr.port())
} else {
match addr.port() {
80 => "http".to_string(),
443 => "https".to_string(),
22 => "ssh".to_string(),
53 => "domain".to_string(),
_ => format!("{}", addr.port()),
}
};
Ok((host, service))
}
pub fn inet_pton(family: X86AddressFamily, src: &str) -> Result<Vec<u8>, String> {
match family {
X86AddressFamily::IPv4 => {
let addr = parse_ipv4(src).ok_or("Invalid IPv4 address")?;
Ok(addr.s_addr.to_ne_bytes()[..].to_vec())
}
X86AddressFamily::IPv6 => {
Ok(inet6::IN6ADDR_LOOPBACK_INIT.to_vec())
}
_ => Err("Address family not supported".to_string()),
}
}
pub fn inet_ntop(family: X86AddressFamily, src: &[u8]) -> Result<String, String> {
match family {
X86AddressFamily::IPv4 if src.len() >= 4 => {
Ok(format!("{}.{}.{}.{}", src[0], src[1], src[2], src[3]))
}
X86AddressFamily::IPv6 if src.len() >= 16 => {
let addr = X86In6Addr::new(src[0..16].try_into().unwrap());
Ok(format!("{}", addr))
}
_ => Err("Invalid address".to_string()),
}
}
pub fn htons(val: u16) -> u16 {
val.to_be()
}
pub fn htonl(val: u32) -> u32 {
val.to_be()
}
pub fn ntohs(val: u16) -> u16 {
u16::from_be(val)
}
pub fn ntohl(val: u32) -> u32 {
u32::from_be(val)
}
pub fn setsockopt(
&mut self,
fd: X86SocketFd,
level: i32,
optname: i32,
optval: &[u8],
) -> Result<(), String> {
let sock = self
.open_sockets
.get_mut(&fd)
.ok_or("EBADF: bad file descriptor")?;
if level == sol::SOL_SOCKET && optname == sockopt::SO_REUSEADDR {
sock.reuse_addr = optval.first().map_or(false, |&b| b != 0);
} else if level == sol::SOL_SOCKET && optname == sockopt::SO_REUSEPORT {
sock.reuse_port = optval.first().map_or(false, |&b| b != 0);
} else if level == ipproto::IPPROTO_TCP && optname == tcp::TCP_NODELAY {
let val = optval.first().map_or(false, |&b| b != 0);
sock.set_option(X86SocketOption::NoDelay(val));
}
Ok(())
}
pub fn getsockopt(&self, fd: X86SocketFd, level: i32, optname: i32) -> Result<Vec<u8>, String> {
let sock = self
.open_sockets
.get(&fd)
.ok_or("EBADF: bad file descriptor")?;
let result = if level == sol::SOL_SOCKET && optname == sockopt::SO_ERROR {
vec![0u8; 4]
} else if level == sol::SOL_SOCKET && optname == sockopt::SO_TYPE {
sock.socket_type.to_native().to_ne_bytes().to_vec()
} else if level == sol::SOL_SOCKET && optname == sockopt::SO_REUSEADDR {
vec![sock.reuse_addr as u8]
} else {
vec![0u8; 4]
};
Ok(result)
}
pub fn fcntl_set_nonblock(&mut self, fd: X86SocketFd) -> Result<(), String> {
let sock = self
.open_sockets
.get_mut(&fd)
.ok_or("EBADF: bad file descriptor")?;
sock.nonblocking = true;
Ok(())
}
pub fn fcntl_getfl(&self, fd: X86SocketFd) -> Result<i32, String> {
let sock = self
.open_sockets
.get(&fd)
.ok_or("EBADF: bad file descriptor")?;
let mut flags = 0i32;
if sock.nonblocking {
flags |= fcntl::O_NONBLOCK;
}
Ok(flags)
}
pub fn poll(&self, fds: &mut [X86PollFd], timeout_ms: i32) -> Result<i32, String> {
let _ = timeout_ms;
let mut ready = 0;
for pfd in fds.iter_mut() {
if self.open_sockets.contains_key(&pfd.fd) {
pfd.revents = poll::POLLOUT; ready += 1;
}
}
Ok(ready)
}
pub fn select(
&self,
nfds: i32,
_readfds: &mut HashSet<X86SocketFd>,
_writefds: &mut HashSet<X86SocketFd>,
_exceptfds: &mut HashSet<X86SocketFd>,
_timeout: Option<Duration>,
) -> Result<i32, String> {
let mut ready = 0;
for fd in 0..nfds {
if self.open_sockets.contains_key(&fd) {
ready += 1;
}
}
Ok(ready)
}
pub fn epoll_create(&self, size: i32) -> Result<X86SocketFd, String> {
if !self.use_epoll {
return Err("ENOSYS: epoll not available".to_string());
}
Ok(size.max(1) as X86SocketFd)
}
pub fn epoll_create1(&self, flags: i32) -> Result<X86SocketFd, String> {
if !self.use_epoll {
return Err("ENOSYS: epoll not available".to_string());
}
let _ = flags;
Ok(1)
}
pub fn epoll_ctl(
&self,
epfd: X86SocketFd,
op: i32,
fd: X86SocketFd,
event: Option<&X86EpollEvent>,
) -> Result<(), String> {
if !self.use_epoll {
return Err("ENOSYS: epoll not available".to_string());
}
match op {
epoll::EPOLL_CTL_ADD | epoll::EPOLL_CTL_MOD | epoll::EPOLL_CTL_DEL => {}
_ => return Err("EINVAL: invalid operation".to_string()),
}
let _ = (epfd, fd, event);
Ok(())
}
pub fn epoll_wait(
&self,
epfd: X86SocketFd,
events: &mut [X86EpollEvent],
timeout_ms: i32,
_maxevents: i32,
) -> Result<i32, String> {
if !self.use_epoll {
return Err("ENOSYS: epoll not available".to_string());
}
let _ = (epfd, timeout_ms);
let count = events.len().min(1) as i32;
for (i, ev) in events.iter_mut().enumerate().take(count as usize) {
ev.events = epoll::EPOLLIN | epoll::EPOLLOUT;
}
Ok(count)
}
pub fn kqueue(&self) -> Result<X86SocketFd, String> {
if !self.use_kqueue {
return Err("ENOSYS: kqueue not available".to_string());
}
Ok(1)
}
pub fn kevent(
&self,
kq: X86SocketFd,
changelist: &[X86Kevent],
eventlist: &mut [X86Kevent],
timeout: Option<Duration>,
) -> Result<i32, String> {
if !self.use_kqueue {
return Err("ENOSYS: kqueue not available".to_string());
}
let _ = (kq, changelist, timeout);
let count = eventlist.len().min(1) as i32;
for ev in eventlist.iter_mut().take(count as usize) {
ev.flags = kevent_flags::EV_EOF; }
Ok(count)
}
pub fn create_iocp(&self) -> Result<X86SocketFd, String> {
if !self.use_iocp {
return Err("ENOSYS: IOCP not available".to_string());
}
Ok(1)
}
pub fn iocp_associate(
&self,
iocp: X86SocketFd,
fd: X86SocketFd,
key: u64,
) -> Result<(), String> {
if !self.use_iocp {
return Err("ENOSYS: IOCP not available".to_string());
}
let _ = (iocp, fd, key);
Ok(())
}
pub fn iocp_get_status(&self, iocp: X86SocketFd) -> Result<(u64, u32, u32), String> {
if !self.use_iocp {
return Err("ENOSYS: IOCP not available".to_string());
}
let _ = iocp;
Ok((0, 0, 0))
}
pub fn close(&mut self, fd: X86SocketFd) -> Result<(), String> {
self.open_sockets
.remove(&fd)
.ok_or("EBADF: bad file descriptor")?;
Ok(())
}
pub fn shutdown(&mut self, fd: X86SocketFd, how: i32) -> Result<(), String> {
let _sock = self
.open_sockets
.get(&fd)
.ok_or("EBADF: bad file descriptor")?;
if how != shutdown::SHUT_RD && how != shutdown::SHUT_WR && how != shutdown::SHUT_RDWR {
return Err("EINVAL: invalid how".to_string());
}
Ok(())
}
pub fn socket_count(&self) -> usize {
self.open_sockets.len()
}
pub fn is_socket(&self, fd: X86SocketFd) -> bool {
self.open_sockets.contains_key(&fd)
}
pub fn socketpair(
&mut self,
domain: X86AddressFamily,
socket_type: X86SocketType,
protocol: X86SocketProtocol,
) -> Result<(X86SocketFd, X86SocketFd), String> {
let fd1 = self.socket(domain, socket_type, protocol);
let fd2 = self.socket(domain, socket_type, protocol);
Ok((fd1, fd2))
}
}
impl Default for X86SocketAPI {
fn default() -> Self {
Self::new_linux()
}
}
#[derive(Debug, Clone, Copy)]
pub struct X86Kevent {
pub ident: u64,
pub filter: i16,
pub flags: u16,
pub fflags: u32,
pub data: i64,
pub udata: u64,
}
impl X86Kevent {
pub fn new(ident: u64, filter: i16, flags: u16) -> Self {
Self {
ident,
filter,
flags,
fflags: 0,
data: 0,
udata: 0,
}
}
}
pub mod kevent_flags {
pub const EV_ADD: u16 = 0x0001;
pub const EV_DELETE: u16 = 0x0002;
pub const EV_ENABLE: u16 = 0x0004;
pub const EV_DISABLE: u16 = 0x0008;
pub const EV_ONESHOT: u16 = 0x0010;
pub const EV_CLEAR: u16 = 0x0020;
pub const EV_RECEIPT: u16 = 0x0040;
pub const EV_DISPATCH: u16 = 0x0080;
pub const EV_EOF: u16 = 0x8000;
pub const EV_ERROR: u16 = 0x4000;
pub const EVFILT_READ: i16 = -1;
pub const EVFILT_WRITE: i16 = -2;
pub const EVFILT_AIO: i16 = -3;
pub const EVFILT_VNODE: i16 = -4;
pub const EVFILT_PROC: i16 = -5;
pub const EVFILT_SIGNAL: i16 = -6;
pub const EVFILT_TIMER: i16 = -7;
pub const EVFILT_USER: i16 = -10;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86TLSLibrary {
OpenSSL,
BoringSSL,
LibreSSL,
SecureTransport,
SChannel,
}
impl X86TLSLibrary {
pub fn as_str(&self) -> &'static str {
match self {
Self::OpenSSL => "OpenSSL",
Self::BoringSSL => "BoringSSL",
Self::LibreSSL => "LibreSSL",
Self::SecureTransport => "SecureTransport",
Self::SChannel => "SChannel",
}
}
}
impl Default for X86TLSLibrary {
fn default() -> Self {
Self::OpenSSL
}
}
impl fmt::Display for X86TLSLibrary {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum X86TLSVersion {
SSLv3,
TLSv1_0,
TLSv1_1,
TLSv1_2,
TLSv1_3,
}
impl X86TLSVersion {
pub fn protocol_constant(&self) -> u16 {
match self {
Self::SSLv3 => 0x0300,
Self::TLSv1_0 => 0x0301,
Self::TLSv1_1 => 0x0302,
Self::TLSv1_2 => 0x0303,
Self::TLSv1_3 => 0x0304,
}
}
pub fn from_constant(v: u16) -> Option<Self> {
match v {
0x0300 => Some(Self::SSLv3),
0x0301 => Some(Self::TLSv1_0),
0x0302 => Some(Self::TLSv1_1),
0x0303 => Some(Self::TLSv1_2),
0x0304 => Some(Self::TLSv1_3),
_ => None,
}
}
pub fn min_supported(lib: X86TLSLibrary) -> Self {
match lib {
X86TLSLibrary::OpenSSL | X86TLSLibrary::BoringSSL | X86TLSLibrary::LibreSSL => {
Self::TLSv1_2
}
X86TLSLibrary::SecureTransport => Self::TLSv1_2,
X86TLSLibrary::SChannel => Self::TLSv1_0,
}
}
pub fn max_supported(lib: X86TLSLibrary) -> Self {
match lib {
X86TLSLibrary::BoringSSL => Self::TLSv1_2,
_ => Self::TLSv1_3,
}
}
}
impl fmt::Display for X86TLSVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::SSLv3 => write!(f, "SSLv3"),
Self::TLSv1_0 => write!(f, "TLSv1.0"),
Self::TLSv1_1 => write!(f, "TLSv1.1"),
Self::TLSv1_2 => write!(f, "TLSv1.2"),
Self::TLSv1_3 => write!(f, "TLSv1.3"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86TLSMethod {
TLSClient,
TLSServer,
TLS,
DTLSClient,
DTLSServer,
DTLS,
}
pub struct X86SSLContext {
pub method: X86TLSMethod,
pub library: X86TLSLibrary,
pub min_version: X86TLSVersion,
pub max_version: X86TLSVersion,
pub verify_mode: X86TLSVerifyMode,
pub certificate_file: Option<String>,
pub private_key_file: Option<String>,
pub ca_file: Option<String>,
pub ca_path: Option<String>,
pub cipher_list: String,
pub cipher_suites: String,
pub session_cache_enabled: bool,
pub session_tickets_enabled: bool,
pub alpn_protocols: Vec<String>,
pub sni_hostname: Option<String>,
}
impl X86SSLContext {
pub fn new(method: X86TLSMethod, library: X86TLSLibrary) -> Self {
Self {
method,
library,
min_version: X86TLSVersion::TLSv1_2,
max_version: X86TLSVersion::TLSv1_3,
verify_mode: X86TLSVerifyMode::Peer,
certificate_file: None,
private_key_file: None,
ca_file: None,
ca_path: None,
cipher_list: "DEFAULT".to_string(),
cipher_suites: String::new(),
session_cache_enabled: true,
session_tickets_enabled: true,
alpn_protocols: Vec::new(),
sni_hostname: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86TLSVerifyMode {
None,
Peer,
PeerFailIfNoPeerCert,
ClientOnce,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86TLSState {
Init,
Handshake,
Connected,
Shutdown,
Error,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86TLSError {
None,
SSL,
WantRead,
WantWrite,
WantConnect,
WantAccept,
WantX509Lookup,
Syscall,
ZeroReturn,
WantAsync,
WantAsyncJob,
WantClientHelloCB,
}
impl X86TLSError {
pub fn from_ssl_error(err: i32) -> Self {
match err {
0 => Self::None,
1 => Self::SSL,
2 => Self::WantRead,
3 => Self::WantWrite,
4 => Self::WantX509Lookup,
5 => Self::Syscall,
6 => Self::ZeroReturn,
7 => Self::WantConnect,
8 => Self::WantAccept,
9 => Self::WantAsync,
10 => Self::WantAsyncJob,
11 => Self::WantClientHelloCB,
_ => Self::SSL,
}
}
}
pub struct X86TLSIntegration {
pub library: X86TLSLibrary,
pub min_version: X86TLSVersion,
pub max_version: X86TLSVersion,
pub tls13_enabled: bool,
pub alpn_supported: bool,
pub sni_supported: bool,
pub session_reuse: bool,
pub certificate_compression: bool,
pub early_data_supported: bool,
contexts: HashMap<String, X86SSLContext>,
sessions: HashMap<u64, X86TLSSession>,
next_id: u64,
}
pub struct X86TLSSession {
pub id: u64,
pub state: X86TLSState,
pub fd: Option<X86SocketFd>,
pub version: X86TLSVersion,
pub cipher: String,
pub sni_hostname: Option<String>,
pub alpn_protocol: Option<String>,
pub peer_certificate: Option<Vec<u8>>,
pub bytes_sent: u64,
pub bytes_received: u64,
}
impl X86TLSSession {
pub fn new(id: u64) -> Self {
Self {
id,
state: X86TLSState::Init,
fd: None,
version: X86TLSVersion::TLSv1_3,
cipher: String::new(),
sni_hostname: None,
alpn_protocol: None,
peer_certificate: None,
bytes_sent: 0,
bytes_received: 0,
}
}
}
impl X86TLSIntegration {
pub fn new_openssl() -> Self {
Self {
library: X86TLSLibrary::OpenSSL,
min_version: X86TLSVersion::TLSv1_2,
max_version: X86TLSVersion::TLSv1_3,
tls13_enabled: true,
alpn_supported: true,
sni_supported: true,
session_reuse: true,
certificate_compression: true,
early_data_supported: true,
contexts: HashMap::new(),
sessions: HashMap::new(),
next_id: 1,
}
}
pub fn new_boringssl() -> Self {
let mut tls = Self::new_openssl();
tls.library = X86TLSLibrary::BoringSSL;
tls.tls13_enabled = false;
tls.max_version = X86TLSVersion::TLSv1_2;
tls.early_data_supported = false;
tls.certificate_compression = false;
tls
}
pub fn new_libressl() -> Self {
let mut tls = Self::new_openssl();
tls.library = X86TLSLibrary::LibreSSL;
tls
}
pub fn new_secure_transport() -> Self {
let mut tls = Self::new_openssl();
tls.library = X86TLSLibrary::SecureTransport;
tls.alpn_supported = false;
tls
}
pub fn ssl_ctx_new(&mut self, method: X86TLSMethod, ctx_label: &str) -> String {
let ctx = X86SSLContext::new(method, self.library);
let key = format!("{}_{}", ctx_label, self.next_id);
self.next_id += 1;
self.contexts.insert(key.clone(), ctx);
key
}
pub fn ssl_new(&mut self, ctx_key: &str) -> Result<u64, String> {
if !self.contexts.contains_key(ctx_key) {
return Err("SSL_CTX not found".to_string());
}
let id = self.next_id;
self.next_id += 1;
let session = X86TLSSession::new(id);
self.sessions.insert(id, session);
Ok(id)
}
pub fn ssl_set_fd(&mut self, ssl_id: u64, fd: X86SocketFd) -> Result<(), String> {
let session = self.sessions.get_mut(&ssl_id).ok_or("SSL not found")?;
session.fd = Some(fd);
Ok(())
}
pub fn ssl_set_tlsext_host_name(&mut self, ssl_id: u64, hostname: &str) -> Result<(), String> {
if !self.sni_supported {
return Err("SNI not supported".to_string());
}
let session = self.sessions.get_mut(&ssl_id).ok_or("SSL not found")?;
session.sni_hostname = Some(hostname.to_string());
Ok(())
}
pub fn ssl_connect(&mut self, ssl_id: u64) -> Result<(), X86TLSError> {
let session = self.sessions.get_mut(&ssl_id).ok_or(X86TLSError::SSL)?;
session.state = X86TLSState::Connected;
Ok(())
}
pub fn ssl_accept(&mut self, ssl_id: u64) -> Result<(), X86TLSError> {
let session = self.sessions.get_mut(&ssl_id).ok_or(X86TLSError::SSL)?;
session.state = X86TLSState::Connected;
Ok(())
}
pub fn ssl_read(&mut self, ssl_id: u64, buf: &mut [u8]) -> Result<usize, X86TLSError> {
let session = self.sessions.get_mut(&ssl_id).ok_or(X86TLSError::SSL)?;
if session.state != X86TLSState::Connected {
return Err(X86TLSError::SSL);
}
let n = buf.len().min(1024);
session.bytes_received += n as u64;
Ok(n)
}
pub fn ssl_write(&mut self, ssl_id: u64, buf: &[u8]) -> Result<usize, X86TLSError> {
let session = self.sessions.get_mut(&ssl_id).ok_or(X86TLSError::SSL)?;
if session.state != X86TLSState::Connected {
return Err(X86TLSError::SSL);
}
let n = buf.len();
session.bytes_sent += n as u64;
Ok(n)
}
pub fn ssl_shutdown(&mut self, ssl_id: u64) -> Result<(), X86TLSError> {
let session = self.sessions.get_mut(&ssl_id).ok_or(X86TLSError::SSL)?;
session.state = X86TLSState::Shutdown;
Ok(())
}
pub fn ssl_free(&mut self, ssl_id: u64) -> Result<(), String> {
self.sessions
.remove(&ssl_id)
.ok_or("SSL not found".to_string())?;
Ok(())
}
pub fn tls_protocol_constants(&self) -> Vec<(String, u16)> {
vec![
("TLS1_VERSION".to_string(), 0x0301),
("TLS1_1_VERSION".to_string(), 0x0302),
("TLS1_2_VERSION".to_string(), 0x0303),
("TLS1_3_VERSION".to_string(), 0x0304),
("DTLS1_VERSION".to_string(), 0xFEFF),
("DTLS1_2_VERSION".to_string(), 0xFEFD),
]
}
pub fn ssl_compile_flags(&self) -> Vec<String> {
let mut flags = Vec::new();
match self.library {
X86TLSLibrary::OpenSSL => {
flags.push("-lssl".to_string());
flags.push("-lcrypto".to_string());
if self.tls13_enabled {
flags.push("-DTLS1_3_SUPPORTED".to_string());
}
}
X86TLSLibrary::BoringSSL => {
flags.push("-lboringssl".to_string());
flags.push("-lboringssl_crypto".to_string());
}
X86TLSLibrary::LibreSSL => {
flags.push("-lssl".to_string());
flags.push("-lcrypto".to_string());
}
X86TLSLibrary::SecureTransport => {
flags.push("-framework".to_string());
flags.push("Security".to_string());
}
X86TLSLibrary::SChannel => {
flags.push("-lsecur32".to_string());
flags.push("-lcrypt32".to_string());
}
}
flags
}
pub fn alpn_protocol_list(&self, protocols: &[&str]) -> Vec<u8> {
let mut data = Vec::new();
for proto in protocols {
data.push(proto.len() as u8);
data.extend_from_slice(proto.as_bytes());
}
data
}
pub fn describe(&self) -> String {
format!(
"X86TLSIntegration {{ library: {}, TLSv1.2: {}, TLSv1.3: {}, ALPN: {}, SNI: {}, early_data: {} }}",
self.library.as_str(),
self.max_version >= X86TLSVersion::TLSv1_2,
self.tls13_enabled,
self.alpn_supported,
self.sni_supported,
self.early_data_supported,
)
}
}
impl Default for X86TLSIntegration {
fn default() -> Self {
Self::new_openssl()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86HTTPVersion {
HTTP10,
HTTP11,
HTTP2,
HTTP3,
}
impl X86HTTPVersion {
pub fn as_str(&self) -> &'static str {
match self {
Self::HTTP10 => "HTTP/1.0",
Self::HTTP11 => "HTTP/1.1",
Self::HTTP2 => "HTTP/2.0",
Self::HTTP3 => "HTTP/3.0",
}
}
pub fn from_str(s: &str) -> Option<Self> {
match s {
"HTTP/1.0" => Some(Self::HTTP10),
"HTTP/1.1" => Some(Self::HTTP11),
"HTTP/2.0" | "h2" => Some(Self::HTTP2),
"HTTP/3.0" | "h3" => Some(Self::HTTP3),
_ => None,
}
}
}
impl fmt::Display for X86HTTPVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum X86HTTPMethod {
GET,
POST,
PUT,
DELETE,
HEAD,
OPTIONS,
PATCH,
TRACE,
CONNECT,
}
impl X86HTTPMethod {
pub fn as_str(&self) -> &'static str {
match self {
Self::GET => "GET",
Self::POST => "POST",
Self::PUT => "PUT",
Self::DELETE => "DELETE",
Self::HEAD => "HEAD",
Self::OPTIONS => "OPTIONS",
Self::PATCH => "PATCH",
Self::TRACE => "TRACE",
Self::CONNECT => "CONNECT",
}
}
pub fn from_str(s: &str) -> Option<Self> {
match s {
"GET" => Some(Self::GET),
"POST" => Some(Self::POST),
"PUT" => Some(Self::PUT),
"DELETE" => Some(Self::DELETE),
"HEAD" => Some(Self::HEAD),
"OPTIONS" => Some(Self::OPTIONS),
"PATCH" => Some(Self::PATCH),
"TRACE" => Some(Self::TRACE),
"CONNECT" => Some(Self::CONNECT),
_ => None,
}
}
pub fn is_safe(&self) -> bool {
matches!(self, Self::GET | Self::HEAD | Self::OPTIONS | Self::TRACE)
}
pub fn is_idempotent(&self) -> bool {
matches!(
self,
Self::GET | Self::HEAD | Self::PUT | Self::DELETE | Self::OPTIONS | Self::TRACE
)
}
}
impl fmt::Display for X86HTTPMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
pub mod http_status {
pub const OK: u16 = 200;
pub const CREATED: u16 = 201;
pub const ACCEPTED: u16 = 202;
pub const NO_CONTENT: u16 = 204;
pub const MOVED_PERMANENTLY: u16 = 301;
pub const FOUND: u16 = 302;
pub const SEE_OTHER: u16 = 303;
pub const NOT_MODIFIED: u16 = 304;
pub const TEMPORARY_REDIRECT: u16 = 307;
pub const PERMANENT_REDIRECT: u16 = 308;
pub const BAD_REQUEST: u16 = 400;
pub const UNAUTHORIZED: u16 = 401;
pub const FORBIDDEN: u16 = 403;
pub const NOT_FOUND: u16 = 404;
pub const METHOD_NOT_ALLOWED: u16 = 405;
pub const REQUEST_TIMEOUT: u16 = 408;
pub const CONFLICT: u16 = 409;
pub const GONE: u16 = 410;
pub const TOO_MANY_REQUESTS: u16 = 429;
pub const INTERNAL_SERVER_ERROR: u16 = 500;
pub const NOT_IMPLEMENTED: u16 = 501;
pub const BAD_GATEWAY: u16 = 502;
pub const SERVICE_UNAVAILABLE: u16 = 503;
pub const GATEWAY_TIMEOUT: u16 = 504;
}
#[derive(Debug, Clone)]
pub struct X86HTTPRequest {
pub method: X86HTTPMethod,
pub url: X86URL,
pub version: X86HTTPVersion,
pub headers: HashMap<String, String>,
pub body: Vec<u8>,
}
impl X86HTTPRequest {
pub fn new(method: X86HTTPMethod, url: X86URL) -> Self {
let mut headers = HashMap::new();
headers.insert("Host".to_string(), url.host.clone().unwrap_or_default());
headers.insert("User-Agent".to_string(), "Clang-X86/1.0".to_string());
headers.insert("Accept".to_string(), "*/*".to_string());
Self {
method,
url,
version: X86HTTPVersion::HTTP11,
headers,
body: Vec::new(),
}
}
pub fn set_header(&mut self, key: &str, value: &str) {
self.headers.insert(key.to_string(), value.to_string());
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut req = format!(
"{} {} {}\r\n",
self.method.as_str(),
self.url.path_and_query(),
self.version.as_str(),
);
for (k, v) in &self.headers {
req.push_str(&format!("{}: {}\r\n", k, v));
}
if !self.body.is_empty() {
req.push_str(&format!("Content-Length: {}\r\n", self.body.len()));
}
req.push_str("\r\n");
let mut bytes = req.into_bytes();
bytes.extend_from_slice(&self.body);
bytes
}
}
#[derive(Debug, Clone)]
pub struct X86HTTPResponse {
pub version: X86HTTPVersion,
pub status: u16,
pub reason: String,
pub headers: HashMap<String, String>,
pub body: Vec<u8>,
}
impl X86HTTPResponse {
pub fn new(status: u16) -> Self {
Self {
version: X86HTTPVersion::HTTP11,
status,
reason: Self::reason_for_status(status),
headers: HashMap::new(),
body: Vec::new(),
}
}
pub fn reason_for_status(status: u16) -> String {
match status {
200 => "OK",
201 => "Created",
204 => "No Content",
301 => "Moved Permanently",
302 => "Found",
304 => "Not Modified",
400 => "Bad Request",
401 => "Unauthorized",
403 => "Forbidden",
404 => "Not Found",
405 => "Method Not Allowed",
408 => "Request Timeout",
429 => "Too Many Requests",
500 => "Internal Server Error",
502 => "Bad Gateway",
503 => "Service Unavailable",
_ => "Unknown",
}
.to_string()
}
pub fn set_header(&mut self, key: &str, value: &str) {
self.headers.insert(key.to_string(), value.to_string());
}
pub fn get_header(&self, key: &str) -> Option<&str> {
self.headers.get(key).map(|s| s.as_str())
}
pub fn content_length(&self) -> Option<usize> {
self.get_header("Content-Length")
.and_then(|v| v.parse().ok())
}
pub fn is_chunked(&self) -> bool {
self.get_header("Transfer-Encoding")
.map(|v| v.to_lowercase().contains("chunked"))
.unwrap_or(false)
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut resp = format!(
"{} {} {}\r\n",
self.version.as_str(),
self.status,
self.reason,
);
for (k, v) in &self.headers {
resp.push_str(&format!("{}: {}\r\n", k, v));
}
if !self.body.is_empty() && !self.headers.contains_key("Content-Length") {
resp.push_str(&format!("Content-Length: {}\r\n", self.body.len()));
}
resp.push_str("\r\n");
let mut bytes = resp.into_bytes();
bytes.extend_from_slice(&self.body);
bytes
}
}
#[derive(Debug, Clone)]
pub struct X86URL {
pub scheme: String,
pub userinfo: Option<String>,
pub host: Option<String>,
pub port: Option<u16>,
pub path: String,
pub query: Option<String>,
pub fragment: Option<String>,
}
impl X86URL {
pub fn parse(url_str: &str) -> Result<Self, String> {
let s = url_str;
let (scheme, rest) = if let Some(pos) = s.find("://") {
let scheme = &s[..pos];
let rest = &s[pos + 3..];
(scheme.to_lowercase(), rest.to_string())
} else {
return Err("Missing scheme".to_string());
};
let (authority, path_query_frag) = if let Some(pos) = rest.find('/') {
(Some(rest[..pos].to_string()), rest[pos..].to_string())
} else if rest.contains('?') || rest.contains('#') {
(None, format!("/{}", rest))
} else {
(Some(rest.clone()), "/".to_string())
};
let (host, port) = if let Some(auth) = authority {
let host_port = if let Some(pos) = auth.rfind('@') {
auth[pos + 1..].to_string()
} else {
auth
};
if let Some(pos) = host_port.rfind(':') {
if let Some(pos2) = host_port[..pos].rfind(':') {
let host_str = &host_port[..pos];
let port_str = &host_port[pos + 1..];
(Some(host_str.to_string()), port_str.parse::<u16>().ok())
} else {
let host_str = &host_port[..pos];
let port_str = &host_port[pos + 1..];
(Some(host_str.to_string()), port_str.parse::<u16>().ok())
}
} else {
(Some(host_port), None)
}
} else {
(None, None)
};
let (path, query, fragment) = {
let p = path_query_frag;
let (path_part, rest) = if let Some(pos) = p.find('?') {
(&p[..pos], Some(&p[pos + 1..]))
} else if let Some(pos) = p.find('#') {
(&p[..pos], Some(&p[pos..]))
} else {
(p.as_str(), None)
};
let (query, fragment) = if let Some(r) = rest {
if r.starts_with('#') {
(None, Some(r[1..].to_string()))
} else if let Some(pos) = r.find('#') {
(Some(r[..pos].to_string()), Some(r[pos + 1..].to_string()))
} else {
(Some(r.to_string()), None)
}
} else {
(None, None)
};
(path_part.to_string(), query, fragment)
};
let port = port.or_else(|| match scheme.as_str() {
"http" => Some(80),
"https" => Some(443),
"ftp" => Some(21),
"ssh" => Some(22),
_ => None,
});
Ok(Self {
scheme,
userinfo: None,
host,
port,
path,
query,
fragment,
})
}
pub fn path_and_query(&self) -> String {
let mut s = self.path.clone();
if let Some(ref q) = self.query {
s.push('?');
s.push_str(q);
}
s
}
pub fn to_string(&self) -> String {
let mut s = format!("{}://", self.scheme);
if let Some(ref host) = self.host {
s.push_str(host);
}
if let Some(port) = self.port {
s.push_str(&format!(":{}", port));
}
s.push_str(&self.path_and_query());
if let Some(ref frag) = self.fragment {
s.push('#');
s.push_str(frag);
}
s
}
}
impl fmt::Display for X86URL {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_string())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86HTTP2FrameType {
Data,
Headers,
Priority,
RstStream,
Settings,
PushPromise,
Ping,
GoAway,
WindowUpdate,
Continuation,
}
impl X86HTTP2FrameType {
pub fn code(&self) -> u8 {
match self {
Self::Data => 0x0,
Self::Headers => 0x1,
Self::Priority => 0x2,
Self::RstStream => 0x3,
Self::Settings => 0x4,
Self::PushPromise => 0x5,
Self::Ping => 0x6,
Self::GoAway => 0x7,
Self::WindowUpdate => 0x8,
Self::Continuation => 0x9,
}
}
}
pub mod http2_settings {
pub const SETTINGS_HEADER_TABLE_SIZE: u16 = 0x1;
pub const SETTINGS_ENABLE_PUSH: u16 = 0x2;
pub const SETTINGS_MAX_CONCURRENT_STREAMS: u16 = 0x3;
pub const SETTINGS_INITIAL_WINDOW_SIZE: u16 = 0x4;
pub const SETTINGS_MAX_FRAME_SIZE: u16 = 0x5;
pub const SETTINGS_MAX_HEADER_LIST_SIZE: u16 = 0x6;
}
#[derive(Debug, Clone)]
pub struct X86HTTP2Frame {
pub length: u32,
pub frame_type: X86HTTP2FrameType,
pub flags: u8,
pub stream_id: u32,
pub payload: Vec<u8>,
}
impl X86HTTP2Frame {
pub fn new(frame_type: X86HTTP2FrameType, stream_id: u32) -> Self {
Self {
length: 0,
frame_type,
flags: 0,
stream_id,
payload: Vec::new(),
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut buf = Vec::new();
let len = (self.payload.len() as u32) & 0xFFFFFF;
buf.extend_from_slice(&len.to_be_bytes()[1..]);
buf.push(self.frame_type.code());
buf.push(self.flags);
buf.extend_from_slice(&self.stream_id.to_be_bytes());
buf[7] &= 0x7F; buf.extend_from_slice(&self.payload);
buf
}
}
#[derive(Debug, Clone)]
pub struct X86QUICConfig {
pub max_idle_timeout_ms: u64,
pub max_udp_payload_size: u64,
pub initial_max_data: u64,
pub initial_max_stream_data_bidi_local: u64,
pub initial_max_stream_data_bidi_remote: u64,
pub initial_max_stream_data_uni: u64,
pub initial_max_streams_bidi: u64,
pub initial_max_streams_uni: u64,
pub ack_delay_exponent: u8,
pub max_ack_delay: u8,
pub disable_active_migration: bool,
pub supported_versions: Vec<u32>,
}
impl Default for X86QUICConfig {
fn default() -> Self {
Self {
max_idle_timeout_ms: 30000,
max_udp_payload_size: 65527,
initial_max_data: 1048576,
initial_max_stream_data_bidi_local: 262144,
initial_max_stream_data_bidi_remote: 262144,
initial_max_stream_data_uni: 262144,
initial_max_streams_bidi: 100,
initial_max_streams_uni: 100,
ack_delay_exponent: 3,
max_ack_delay: 25,
disable_active_migration: false,
supported_versions: vec![1],
}
}
}
pub struct X86HTTPSupport {
pub http11_enabled: bool,
pub http2_enabled: bool,
pub http3_enabled: bool,
pub max_header_size: usize,
pub max_body_size: usize,
pub enable_chunked_encoding: bool,
pub enable_compression: bool,
pub keep_alive_timeout_ms: u64,
pub max_connections: u32,
pub quic_config: X86QUICConfig,
}
impl X86HTTPSupport {
pub fn new() -> Self {
Self {
http11_enabled: true,
http2_enabled: false,
http3_enabled: false,
max_header_size: 65536,
max_body_size: 10 * 1024 * 1024,
enable_chunked_encoding: true,
enable_compression: true,
keep_alive_timeout_ms: 7200000,
max_connections: 256,
quic_config: X86QUICConfig::default(),
}
}
pub fn parse_request_line(line: &str) -> Option<(X86HTTPMethod, String, X86HTTPVersion)> {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() < 3 {
return None;
}
let method = X86HTTPMethod::from_str(parts[0])?;
let uri = parts[1].to_string();
let version = X86HTTPVersion::from_str(parts[2]).unwrap_or(X86HTTPVersion::HTTP11);
Some((method, uri, version))
}
pub fn parse_status_line(line: &str) -> Option<(X86HTTPVersion, u16, String)> {
let parts: Vec<&str> = line.splitn(3, ' ').collect();
if parts.len() < 2 {
return None;
}
let version = X86HTTPVersion::from_str(parts[0])?;
let status = parts[1].parse::<u16>().ok()?;
let reason = parts.get(2).map(|s| s.to_string()).unwrap_or_default();
Some((version, status, reason))
}
pub fn parse_headers(raw: &[u8]) -> Option<HashMap<String, String>> {
let text = std::str::from_utf8(raw).ok()?;
let mut headers = HashMap::new();
for line in text.lines() {
if line.is_empty() {
break;
}
if let Some(pos) = line.find(':') {
let key = line[..pos].trim().to_string();
let value = line[pos + 1..].trim().to_string();
headers.insert(key, value);
}
}
Some(headers)
}
pub fn content_type_for_extension(ext: &str) -> &'static str {
match ext.to_lowercase().as_str() {
"html" | "htm" => "text/html; charset=utf-8",
"css" => "text/css; charset=utf-8",
"js" | "mjs" => "text/javascript; charset=utf-8",
"json" => "application/json",
"xml" => "application/xml",
"txt" => "text/plain; charset=utf-8",
"png" => "image/png",
"jpg" | "jpeg" => "image/jpeg",
"gif" => "image/gif",
"svg" => "image/svg+xml",
"ico" => "image/x-icon",
"webp" => "image/webp",
"pdf" => "application/pdf",
"zip" => "application/zip",
"gz" => "application/gzip",
"tar" => "application/x-tar",
"mp3" => "audio/mpeg",
"mp4" => "video/mp4",
"ogg" => "audio/ogg",
"wav" => "audio/wav",
"wasm" => "application/wasm",
_ => "application/octet-stream",
}
}
pub fn chunked_encode(data: &[u8]) -> Vec<u8> {
let mut result = Vec::new();
let mut offset = 0;
while offset < data.len() {
let chunk_size = (data.len() - offset).min(16384);
result.extend_from_slice(format!("{:X}\r\n", chunk_size).as_bytes());
result.extend_from_slice(&data[offset..offset + chunk_size]);
result.extend_from_slice(b"\r\n");
offset += chunk_size;
}
result.extend_from_slice(b"0\r\n\r\n");
result
}
pub fn chunked_decode(data: &[u8]) -> Result<Vec<u8>, String> {
let mut result = Vec::new();
let mut pos = 0;
while pos < data.len() {
let line_end = match data[pos..].windows(2).position(|w| w == b"\r\n") {
Some(idx) => pos + idx,
None => break,
};
let size_str = std::str::from_utf8(&data[pos..line_end])
.map_err(|_| "Invalid chunk size".to_string())?;
let size = usize::from_str_radix(size_str, 16)
.map_err(|_| "Invalid chunk size hex".to_string())?;
if size == 0 {
break; }
pos = line_end + 2;
if pos + size > data.len() {
return Err("Truncated chunk".to_string());
}
result.extend_from_slice(&data[pos..pos + size]);
pos += size + 2; }
Ok(result)
}
pub fn http2_preface() -> Vec<u8> {
b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".to_vec()
}
pub fn http2_initial_settings() -> X86HTTP2Frame {
let mut frame = X86HTTP2Frame::new(X86HTTP2FrameType::Settings, 0);
frame.payload = vec![
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, ];
frame.length = frame.payload.len() as u32;
frame
}
pub fn http3_alpn() -> &'static [u8] {
b"\x05h3-29\x05h3-28\x02h3"
}
pub fn describe(&self) -> String {
format!(
"X86HTTPSupport {{ http1.1: {}, http2: {}, http3: {}, chunked: {}, keep_alive: {}ms }}",
self.http11_enabled,
self.http2_enabled,
self.http3_enabled,
self.enable_chunked_encoding,
self.keep_alive_timeout_ms,
)
}
pub fn to_clang_flags(&self) -> Vec<String> {
let mut flags = Vec::new();
if self.http2_enabled {
flags.push("-DHTTP2_SUPPORTED".to_string());
}
if self.http3_enabled {
flags.push("-DHTTP3_SUPPORTED".to_string());
}
flags
}
}
impl Default for X86HTTPSupport {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum X86DNSRecordType {
A,
NS,
MD,
MF,
CNAME,
SOA,
MB,
MG,
MR,
NULL,
WKS,
PTR,
HINFO,
MINFO,
MX,
TXT,
AAAA,
SRV,
CAA,
HTTPS,
SVCB,
TLSA,
NSEC,
NSEC3,
NSEC3PARAM,
RRSIG,
DNSKEY,
DS,
CDS,
CDNSKEY,
OPENPGPKEY,
CSYNC,
ZONEMD,
SVCBPARAM,
Unknown(u16),
}
impl X86DNSRecordType {
pub fn code(&self) -> u16 {
match self {
Self::A => 1,
Self::NS => 2,
Self::MD => 3,
Self::MF => 4,
Self::CNAME => 5,
Self::SOA => 6,
Self::MB => 7,
Self::MG => 8,
Self::MR => 9,
Self::NULL => 10,
Self::WKS => 11,
Self::PTR => 12,
Self::HINFO => 13,
Self::MINFO => 14,
Self::MX => 15,
Self::TXT => 16,
Self::AAAA => 28,
Self::SRV => 33,
Self::CAA => 257,
Self::HTTPS => 65,
Self::SVCB => 64,
Self::TLSA => 52,
Self::NSEC => 47,
Self::NSEC3 => 50,
Self::NSEC3PARAM => 51,
Self::RRSIG => 46,
Self::DNSKEY => 48,
Self::DS => 43,
Self::CDS => 59,
Self::CDNSKEY => 60,
Self::OPENPGPKEY => 61,
Self::CSYNC => 62,
Self::ZONEMD => 63,
Self::SVCBPARAM => 64,
Self::Unknown(code) => *code,
}
}
pub fn from_code(code: u16) -> Self {
match code {
1 => Self::A,
2 => Self::NS,
5 => Self::CNAME,
6 => Self::SOA,
12 => Self::PTR,
15 => Self::MX,
16 => Self::TXT,
28 => Self::AAAA,
33 => Self::SRV,
43 => Self::DS,
46 => Self::RRSIG,
47 => Self::NSEC,
48 => Self::DNSKEY,
50 => Self::NSEC3,
51 => Self::NSEC3PARAM,
52 => Self::TLSA,
59 => Self::CDS,
60 => Self::CDNSKEY,
61 => Self::OPENPGPKEY,
62 => Self::CSYNC,
63 => Self::ZONEMD,
64 => Self::SVCB,
65 => Self::HTTPS,
257 => Self::CAA,
_ => Self::Unknown(code),
}
}
pub fn as_str(&self) -> &'static str {
match self {
Self::A => "A",
Self::NS => "NS",
Self::CNAME => "CNAME",
Self::SOA => "SOA",
Self::PTR => "PTR",
Self::MX => "MX",
Self::TXT => "TXT",
Self::AAAA => "AAAA",
Self::SRV => "SRV",
Self::CAA => "CAA",
Self::HTTPS => "HTTPS",
Self::SVCB => "SVCB",
Self::TLSA => "TLSA",
Self::RRSIG => "RRSIG",
Self::DNSKEY => "DNSKEY",
Self::DS => "DS",
Self::NSEC => "NSEC",
Self::NSEC3 => "NSEC3",
_ => "UNKNOWN",
}
}
}
#[derive(Debug, Clone)]
pub struct X86DNSRecord {
pub name: String,
pub record_type: X86DNSRecordType,
pub class: u16,
pub ttl: u32,
pub rdata: Vec<u8>,
}
impl X86DNSRecord {
pub fn new(name: &str, record_type: X86DNSRecordType, ttl: u32, rdata: Vec<u8>) -> Self {
Self {
name: name.to_string(),
record_type,
class: 1, ttl,
rdata,
}
}
pub fn rdata_as_ipv4(&self) -> Option<X86InAddr> {
if self.record_type == X86DNSRecordType::A && self.rdata.len() >= 4 {
Some(X86InAddr::from_octets(
self.rdata[0],
self.rdata[1],
self.rdata[2],
self.rdata[3],
))
} else {
None
}
}
pub fn rdata_as_ipv6(&self) -> Option<X86In6Addr> {
if self.record_type == X86DNSRecordType::AAAA && self.rdata.len() >= 16 {
let mut addr = [0u8; 16];
addr.copy_from_slice(&self.rdata[..16]);
Some(X86In6Addr::new(addr))
} else {
None
}
}
pub fn rdata_as_string(&self) -> Option<String> {
if self.record_type == X86DNSRecordType::TXT && self.rdata.len() > 1 {
let len = self.rdata[0] as usize;
if len + 1 <= self.rdata.len() {
return String::from_utf8(self.rdata[1..1 + len].to_vec()).ok();
}
}
if self.record_type == X86DNSRecordType::CNAME
|| self.record_type == X86DNSRecordType::NS
|| self.record_type == X86DNSRecordType::PTR
{
return dns_name_decode(&self.rdata);
}
None
}
}
#[derive(Debug, Clone, Copy)]
pub struct X86DNSFlags {
pub raw: u16,
}
impl X86DNSFlags {
pub fn new_query() -> Self {
Self { raw: 0x0100 } }
pub fn new_response() -> Self {
Self { raw: 0x8180 } }
pub fn is_query(&self) -> bool {
(self.raw & 0x8000) == 0
}
pub fn is_response(&self) -> bool {
(self.raw & 0x8000) != 0
}
pub fn opcode(&self) -> u8 {
((self.raw >> 11) & 0x0F) as u8
}
pub fn authoritative(&self) -> bool {
(self.raw & 0x0400) != 0
}
pub fn truncated(&self) -> bool {
(self.raw & 0x0200) != 0
}
pub fn recursion_desired(&self) -> bool {
(self.raw & 0x0100) != 0
}
pub fn recursion_available(&self) -> bool {
(self.raw & 0x0080) != 0
}
pub fn rcode(&self) -> u8 {
(self.raw & 0x000F) as u8
}
pub fn set_rcode(&mut self, rcode: u8) {
self.raw = (self.raw & 0xFFF0) | (rcode as u16 & 0x0F);
}
}
#[derive(Debug, Clone)]
pub struct X86DNSMessage {
pub id: u16,
pub flags: X86DNSFlags,
pub questions: Vec<X86DNSQuestion>,
pub answers: Vec<X86DNSRecord>,
pub authorities: Vec<X86DNSRecord>,
pub additionals: Vec<X86DNSRecord>,
}
#[derive(Debug, Clone)]
pub struct X86DNSQuestion {
pub qname: String,
pub qtype: X86DNSRecordType,
pub qclass: u16,
}
impl X86DNSQuestion {
pub fn new(name: &str, qtype: X86DNSRecordType) -> Self {
Self {
qname: name.to_string(),
qtype,
qclass: 1, }
}
}
fn dns_name_encode(name: &str) -> Vec<u8> {
let mut encoded = Vec::new();
for label in name.split('.') {
if label.is_empty() {
continue;
}
encoded.push(label.len() as u8);
encoded.extend_from_slice(label.as_bytes());
}
encoded.push(0); encoded
}
fn dns_name_decode(data: &[u8]) -> Option<String> {
let mut name = String::new();
let mut pos = 0;
let mut jumped = false;
let mut jump_count = 0;
while pos < data.len() {
if data[pos] == 0 {
if !jumped {}
break;
}
if (data[pos] & 0xC0) == 0xC0 {
if pos + 1 >= data.len() {
return None;
}
let offset = (((data[pos] & 0x3F) as usize) << 8) | (data[pos + 1] as usize);
if offset >= data.len() {
return None;
}
pos = offset;
jumped = true;
jump_count += 1;
if jump_count > 10 {
return None; }
continue;
}
let len = data[pos] as usize;
if len == 0 {
pos += 1;
break;
}
if pos + 1 + len > data.len() {
return None;
}
if !name.is_empty() {
name.push('.');
}
name.push_str(std::str::from_utf8(&data[pos + 1..pos + 1 + len]).ok()?);
pos += 1 + len;
}
if name.is_empty() {
None
} else {
Some(name)
}
}
#[derive(Debug, Clone)]
pub struct X86EDNS0Options {
pub udp_payload_size: u16,
pub ext_rcode: u8,
pub version: u8,
pub dnssec_ok: bool,
pub options: Vec<X86EDNS0Option>,
}
#[derive(Debug, Clone)]
pub struct X86EDNS0Option {
pub code: u16,
pub data: Vec<u8>,
}
impl Default for X86EDNS0Options {
fn default() -> Self {
Self {
udp_payload_size: 1232,
ext_rcode: 0,
version: 0,
dnssec_ok: false,
options: Vec::new(),
}
}
}
pub mod dnssec_algorithms {
pub const RSAMD5: u8 = 1;
pub const DH: u8 = 2;
pub const DSA: u8 = 3;
pub const RSASHA1: u8 = 5;
pub const DSA_NSEC3_SHA1: u8 = 6;
pub const RSASHA1_NSEC3_SHA1: u8 = 7;
pub const RSASHA256: u8 = 8;
pub const RSASHA512: u8 = 10;
pub const ECC_GOST: u8 = 12;
pub const ECDSAP256SHA256: u8 = 13;
pub const ECDSAP384SHA384: u8 = 14;
pub const ED25519: u8 = 15;
pub const ED448: u8 = 16;
pub const INDIRECT: u8 = 252;
pub const PRIVATEDNS: u8 = 253;
pub const PRIVATEOID: u8 = 254;
}
pub mod dnssec_digests {
pub const SHA1: u8 = 1;
pub const SHA256: u8 = 2;
pub const GOST: u8 = 3;
pub const SHA384: u8 = 4;
}
pub struct X86DNSResolver {
pub nameservers: Vec<String>,
pub timeout_ms: u64,
pub retries: u32,
pub search_domains: Vec<String>,
pub edns0_enabled: bool,
pub dnssec_enabled: bool,
pub max_response_size: usize,
pub cache: BTreeMap<String, Vec<X86DNSRecord>>,
pub edns0: X86EDNS0Options,
cache_hits: u64,
cache_misses: u64,
}
impl X86DNSResolver {
pub fn new_default() -> Self {
Self {
nameservers: vec!["8.8.8.8:53".to_string(), "1.1.1.1:53".to_string()],
timeout_ms: 5000,
retries: 3,
search_domains: Vec::new(),
edns0_enabled: true,
dnssec_enabled: false,
max_response_size: 4096,
cache: BTreeMap::new(),
edns0: X86EDNS0Options::default(),
cache_hits: 0,
cache_misses: 0,
}
}
pub fn with_nameserver(mut self, ns: &str) -> Self {
self.nameservers.push(ns.to_string());
self
}
pub fn build_query(name: &str, record_type: X86DNSRecordType) -> Vec<u8> {
let mut query = Vec::new();
let id = (SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.subsec_nanos() as u16)
% 65535;
query.extend_from_slice(&id.to_be_bytes());
query.extend_from_slice(&0x0100u16.to_be_bytes());
query.extend_from_slice(&1u16.to_be_bytes()); query.extend_from_slice(&0u16.to_be_bytes()); query.extend_from_slice(&0u16.to_be_bytes()); query.extend_from_slice(&0u16.to_be_bytes());
let qname = dns_name_encode(name);
query.extend_from_slice(&qname);
query.extend_from_slice(&record_type.code().to_be_bytes());
query.extend_from_slice(&1u16.to_be_bytes());
query
}
pub fn build_query_edns0(
name: &str,
record_type: X86DNSRecordType,
edns0: &X86EDNS0Options,
) -> Vec<u8> {
let mut query = Self::build_query(name, record_type);
let arcount_offset = 10;
query[arcount_offset..arcount_offset + 2].copy_from_slice(&1u16.to_be_bytes());
query.push(0x00); query.extend_from_slice(&41u16.to_be_bytes());
query.extend_from_slice(&edns0.udp_payload_size.to_be_bytes());
query.push(edns0.ext_rcode);
query.push(edns0.version);
let mut flags: u16 = 0;
if edns0.dnssec_ok {
flags |= 0x8000; }
query.extend_from_slice(&flags.to_be_bytes());
let rdlen: u16 = 0;
query.extend_from_slice(&rdlen.to_be_bytes());
query
}
pub fn parse_response(data: &[u8]) -> Option<X86DNSMessage> {
if data.len() < 12 {
return None;
}
let id = u16::from_be_bytes([data[0], data[1]]);
let flags = X86DNSFlags {
raw: u16::from_be_bytes([data[2], data[3]]),
};
let qdcount = u16::from_be_bytes([data[4], data[5]]);
let ancount = u16::from_be_bytes([data[6], data[7]]);
let nscount = u16::from_be_bytes([data[8], data[9]]);
let arcount = u16::from_be_bytes([data[10], data[11]]);
let mut pos = 12;
let mut questions = Vec::new();
for _ in 0..qdcount {
if let Some(name) = dns_name_decode(&data[pos..]) {
let name_len = dns_name_encode(&name).len();
pos += name_len;
if pos + 4 > data.len() {
break;
}
let qtype = u16::from_be_bytes([data[pos], data[pos + 1]]);
let qclass = u16::from_be_bytes([data[pos + 2], data[pos + 3]]);
pos += 4;
questions.push(X86DNSQuestion {
qname: name,
qtype: X86DNSRecordType::from_code(qtype),
qclass,
});
} else {
break;
}
}
let answers = Self::parse_records(data, &mut pos, ancount);
let authorities = Self::parse_records(data, &mut pos, nscount);
let additionals = Self::parse_records(data, &mut pos, arcount);
Some(X86DNSMessage {
id,
flags,
questions,
answers,
authorities,
additionals,
})
}
fn parse_records(data: &[u8], pos: &mut usize, count: u16) -> Vec<X86DNSRecord> {
let mut records = Vec::new();
for _ in 0..count {
if *pos >= data.len() {
break;
}
if let Some(name) = dns_name_decode(&data[*pos..]) {
let name_len = dns_name_encode(&name).len();
*pos += name_len;
if *pos + 10 > data.len() {
break;
}
let rtype = u16::from_be_bytes([data[*pos], data[*pos + 1]]);
let rclass = u16::from_be_bytes([data[*pos + 2], data[*pos + 3]]);
let ttl = u32::from_be_bytes([
data[*pos + 4],
data[*pos + 5],
data[*pos + 6],
data[*pos + 7],
]);
let rdlength = u16::from_be_bytes([data[*pos + 8], data[*pos + 9]]) as usize;
*pos += 10;
if *pos + rdlength > data.len() {
break;
}
let rdata = data[*pos..*pos + rdlength].to_vec();
*pos += rdlength;
records.push(X86DNSRecord {
name,
record_type: X86DNSRecordType::from_code(rtype),
class: rclass,
ttl,
rdata,
});
} else {
break;
}
}
records
}
pub fn resolve(&mut self, hostname: &str, record_type: X86DNSRecordType) -> Vec<X86DNSRecord> {
if let Some(cached) = self.cache.get(hostname) {
self.cache_hits += 1;
return cached.clone();
}
self.cache_misses += 1;
let mut records = Vec::new();
if hostname == "localhost" {
if record_type == X86DNSRecordType::A || record_type == X86DNSRecordType::A {
records.push(X86DNSRecord::new(
hostname,
X86DNSRecordType::A,
300,
vec![127, 0, 0, 1],
));
records.push(X86DNSRecord::new(
hostname,
X86DNSRecordType::AAAA,
300,
vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
));
}
} else if hostname == "example.com" {
records.push(X86DNSRecord::new(
hostname,
X86DNSRecordType::A,
3600,
vec![93, 184, 216, 34],
));
} else if hostname.contains('.') {
let rdata: Vec<u8> = match record_type {
X86DNSRecordType::A => vec![192, 0, 2, 1],
X86DNSRecordType::AAAA => {
let mut v6 = vec![0x20, 0x01, 0x0d, 0xb8];
v6.extend_from_slice(&[0u8; 12]);
v6
}
X86DNSRecordType::MX => {
let mut mx = vec![0x00, 0x0A]; mx.extend_from_slice(&dns_name_encode("mail.example.com"));
mx
}
X86DNSRecordType::TXT => {
let txt = b"v=spf1 include:_spf.example.com ~all";
let mut rdata = vec![txt.len() as u8];
rdata.extend_from_slice(txt);
rdata
}
X86DNSRecordType::CNAME => dns_name_encode("target.example.com"),
_ => vec![192, 0, 2, 1],
};
records.push(X86DNSRecord::new(hostname, record_type, 3600, rdata));
}
self.cache.insert(hostname.to_string(), records.clone());
records
}
pub fn reverse_lookup(&mut self, addr: &X86InAddr) -> Option<String> {
let b = addr.to_octets();
let ptr_name = format!("{}.{}.{}.{}.in-addr.arpa", b[3], b[2], b[1], b[0]);
let records = self.resolve(&ptr_name, X86DNSRecordType::PTR);
records.first().and_then(|r| r.rdata_as_string())
}
pub fn flush_cache(&mut self) {
self.cache.clear();
self.cache_hits = 0;
self.cache_misses = 0;
}
pub fn cache_stats(&self) -> (u64, u64) {
(self.cache_hits, self.cache_misses)
}
pub fn describe(&self) -> String {
format!(
"X86DNSResolver {{ nameservers: {:?}, timeout: {}ms, edns0: {}, dnssec: {}, cache_size: {}, hits: {}, misses: {} }}",
self.nameservers,
self.timeout_ms,
self.edns0_enabled,
self.dnssec_enabled,
self.cache.len(),
self.cache_hits,
self.cache_misses,
)
}
}
impl Default for X86DNSResolver {
fn default() -> Self {
Self::new_default()
}
}
pub struct X86NetworkingDriver {
pub networking: X86Networking,
pub source_files: Vec<String>,
pub output_file: Option<String>,
pub verbose: bool,
pub compile_for_platform: X86NetPlatform,
}
impl X86NetworkingDriver {
pub fn new(platform: X86NetPlatform) -> Self {
Self {
networking: match platform {
X86NetPlatform::Linux => X86Networking::new_linux_x86_64(),
X86NetPlatform::Windows => X86Networking::new_windows_x86_64(),
X86NetPlatform::MacOS => X86Networking::new_macos_x86_64(),
X86NetPlatform::FreeBSD => X86Networking::new_freebsd_x86_64(),
_ => X86Networking::default(),
},
source_files: Vec::new(),
output_file: None,
verbose: false,
compile_for_platform: platform,
}
}
pub fn add_source(&mut self, file: &str) {
self.source_files.push(file.to_string());
}
pub fn set_output(&mut self, file: &str) {
self.output_file = Some(file.to_string());
}
pub fn compile_flags(&self) -> Vec<String> {
let mut flags = Vec::new();
flags.extend(
self.networking
.to_include_directives()
.into_iter()
.map(|inc| {
format!(
"-include {}",
inc.trim_start_matches("#include ")
.trim_matches(|c: char| c == '<' || c == '>' || c == '"')
)
}),
);
if self.compile_for_platform.has_epoll() {
flags.push("-DHAS_EPOLL".to_string());
}
if self.compile_for_platform.has_kqueue() {
flags.push("-DHAS_KQUEUE".to_string());
}
if self.compile_for_platform.has_iocp() {
flags.push("-DHAS_IOCP".to_string());
}
flags
}
pub fn linkage_flags(&self) -> Vec<String> {
let mut flags = Vec::new();
match self.compile_for_platform {
X86NetPlatform::Linux => {
flags.push("-lpthread".to_string());
flags.push("-ldl".to_string());
}
X86NetPlatform::Windows => {
flags.push("-lws2_32".to_string());
flags.push("-lsecur32".to_string());
}
_ => {}
}
flags
}
pub fn describe(&self) -> String {
format!(
"X86NetworkingDriver {{ platform: {}, files: {}, output: {:?}, net: {} }}",
self.compile_for_platform.as_str(),
self.source_files.len(),
self.output_file,
self.networking.describe(),
)
}
}
impl Default for X86NetworkingDriver {
fn default() -> Self {
Self::new(X86NetPlatform::Linux)
}
}
pub struct X86NetworkingValidator {
pub warnings: Vec<String>,
pub errors: Vec<String>,
}
impl X86NetworkingValidator {
pub fn new() -> Self {
Self {
warnings: Vec::new(),
errors: Vec::new(),
}
}
pub fn validate(&mut self, networking: &X86Networking) {
match networking.platform {
X86NetPlatform::Windows => {
if networking.tcp_fastopen {
self.warnings
.push("TCP Fast Open is not supported on Windows".to_string());
}
if networking.reuse_port_supported {
self.warnings
.push("SO_REUSEPORT is not supported on Windows".to_string());
}
}
X86NetPlatform::MacOS => {
if networking.so_mark_supported {
self.warnings
.push("SO_MARK is not supported on macOS".to_string());
}
}
_ => {}
}
if !networking.ipv6_enabled {
self.warnings
.push("IPv6 is disabled — some features may not work".to_string());
}
}
pub fn report(&self) -> String {
let mut report = String::new();
if !self.errors.is_empty() {
report.push_str("Errors:\n");
for e in &self.errors {
report.push_str(&format!(" - {}\n", e));
}
}
if !self.warnings.is_empty() {
report.push_str("Warnings:\n");
for w in &self.warnings {
report.push_str(&format!(" - {}\n", w));
}
}
if report.is_empty() {
report.push_str("Configuration is valid.\n");
}
report
}
pub fn is_valid(&self) -> bool {
self.errors.is_empty()
}
}
impl Default for X86NetworkingValidator {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_af_constants() {
assert_eq!(af::AF_INET, 2);
assert_eq!(af::AF_INET6, 10);
assert_eq!(af::AF_UNIX, 1);
assert_eq!(af::AF_NETLINK, 16);
assert_eq!(af::AF_PACKET, 17);
assert_eq!(af::AF_UNSPEC, 0);
}
#[test]
fn test_sock_type_constants() {
assert_eq!(sock_type::SOCK_STREAM, 1);
assert_eq!(sock_type::SOCK_DGRAM, 2);
assert_eq!(sock_type::SOCK_RAW, 3);
assert_eq!(sock_type::SOCK_SEQPACKET, 5);
}
#[test]
fn test_ipproto_constants() {
assert_eq!(ipproto::IPPROTO_TCP, 6);
assert_eq!(ipproto::IPPROTO_UDP, 17);
assert_eq!(ipproto::IPPROTO_ICMP, 1);
assert_eq!(ipproto::IPPROTO_RAW, 255);
}
#[test]
fn test_sockopt_constants() {
assert_eq!(sockopt::SO_REUSEADDR, 2);
assert_eq!(sockopt::SO_REUSEPORT, 15);
assert_eq!(sockopt::SO_KEEPALIVE, 9);
assert_eq!(sockopt::SO_ERROR, 4);
}
#[test]
fn test_tcp_constants() {
assert_eq!(tcp::TCP_NODELAY, 1);
assert_eq!(tcp::TCP_KEEPIDLE, 4);
assert_eq!(tcp::TCP_QUICKACK, 12);
}
#[test]
fn test_epoll_constants() {
assert_eq!(epoll::EPOLL_CTL_ADD, 1);
assert_eq!(epoll::EPOLL_CTL_DEL, 2);
assert_eq!(epoll::EPOLL_CTL_MOD, 3);
assert_eq!(epoll::EPOLLIN, 0x001);
}
#[test]
fn test_poll_constants() {
assert_eq!(poll::POLLIN, 0x001);
assert_eq!(poll::POLLOUT, 0x004);
assert_eq!(poll::POLLERR, 0x008);
}
#[test]
fn test_msg_constants() {
assert_eq!(msg::MSG_OOB, 0x01);
assert_eq!(msg::MSG_PEEK, 0x02);
assert_eq!(msg::MSG_DONTWAIT, 0x40);
}
#[test]
fn test_ai_constants() {
assert_eq!(ai::AI_PASSIVE, 0x0001);
assert_eq!(ai::AI_CANONNAME, 0x0002);
assert_eq!(ai::AI_NUMERICHOST, 0x0004);
}
#[test]
fn test_ni_constants() {
assert_eq!(ni::NI_NUMERICHOST, 0x02);
assert_eq!(ni::NI_NUMERICSERV, 0x08);
assert_eq!(ni::NI_NOFQDN, 0x01);
}
#[test]
fn test_shutdown_constants() {
assert_eq!(shutdown::SHUT_RD, 0);
assert_eq!(shutdown::SHUT_WR, 1);
assert_eq!(shutdown::SHUT_RDWR, 2);
}
#[test]
fn test_in_addr_creation() {
let addr = X86InAddr::from_octets(192, 168, 1, 1);
assert_eq!(addr.to_octets(), [192, 168, 1, 1]);
}
#[test]
fn test_in_addr_loopback() {
let addr = X86InAddr::from_octets(127, 0, 0, 1);
assert!(addr.is_loopback());
}
#[test]
fn test_in_addr_private() {
let addr1 = X86InAddr::from_octets(10, 0, 0, 1);
assert!(addr1.is_private());
let addr2 = X86InAddr::from_octets(172, 16, 0, 1);
assert!(addr2.is_private());
let addr3 = X86InAddr::from_octets(192, 168, 1, 1);
assert!(addr3.is_private());
let addr4 = X86InAddr::from_octets(8, 8, 8, 8);
assert!(!addr4.is_private());
}
#[test]
fn test_in_addr_multicast() {
let addr = X86InAddr::from_octets(224, 0, 0, 1);
assert!(addr.is_multicast());
let addr2 = X86InAddr::from_octets(192, 168, 1, 1);
assert!(!addr2.is_multicast());
}
#[test]
fn test_in_addr_display() {
let addr = X86InAddr::from_octets(192, 168, 1, 1);
assert_eq!(format!("{}", addr), "192.168.1.1");
}
#[test]
fn test_in6_addr_creation() {
let addr = X86In6Addr::from_segments(0x2001, 0x0db8, 0, 0, 0, 0, 0, 1);
assert_eq!(addr.to_segments()[0], 0x2001);
}
#[test]
fn test_in6_addr_loopback() {
let addr = X86In6Addr::loopback();
assert!(addr.is_loopback());
}
#[test]
fn test_in6_addr_unspecified() {
let addr = X86In6Addr::any();
assert!(addr.is_unspecified());
}
#[test]
fn test_in6_addr_v4_mapped() {
let mut addr = X86In6Addr::any();
addr.s6_addr[10] = 0xFF;
addr.s6_addr[11] = 0xFF;
addr.s6_addr[12] = 192;
addr.s6_addr[15] = 1;
assert!(addr.is_v4_mapped());
}
#[test]
fn test_in6_addr_display() {
let addr = X86In6Addr::loopback();
assert_eq!(format!("{}", addr), "::1");
}
#[test]
fn test_sockaddr_in_creation() {
let addr = X86InAddr::from_octets(127, 0, 0, 1);
let sin = X86SockAddrIn::new(addr, 8080);
assert_eq!(sin.sin_family, af::AF_INET);
assert_eq!(sin.port(), 8080);
}
#[test]
fn test_sockaddr_in6_creation() {
let addr = X86In6Addr::loopback();
let sin6 = X86SockAddrIn6::new(addr, 443);
assert_eq!(sin6.sin6_family, af::AF_INET6);
}
#[test]
fn test_sockaddr_un_creation() {
let sun = X86SockAddrUn::new("/tmp/test.sock");
assert_eq!(sun.sun_family, af::AF_UNIX);
assert!(sun.path().unwrap().starts_with("/tmp/test.sock"));
}
#[test]
fn test_addrinfo_default() {
let ai = X86AddrInfo::new();
assert_eq!(ai.ai_family, af::AF_UNSPEC as i32);
assert!(ai.ai_canonname.is_none());
}
#[test]
fn test_addrinfo_chain_length() {
let mut ai1 = X86AddrInfo::new();
let ai2 = X86AddrInfo::new();
ai1.ai_next = Some(Box::new(ai2));
assert_eq!(ai1.chain_length(), 2);
}
#[test]
fn test_iovec_creation() {
let data = b"hello world".to_vec();
let iov = X86IoVec::new(data.clone());
assert_eq!(iov.iov_len, 11);
assert_eq!(iov.as_slice(), b"hello world");
}
#[test]
fn test_msghdr_default() {
let msg = X86MsgHdr::default();
assert_eq!(msg.total_data_len(), 0);
}
#[test]
fn test_msghdr_with_iov() {
let iov = vec![
X86IoVec::from_slice(b"hello "),
X86IoVec::from_slice(b"world"),
];
let msg = X86MsgHdr::new().with_iov(iov);
assert_eq!(msg.total_data_len(), 11);
}
#[test]
fn test_cmsghdr_creation() {
let data = vec![1, 2, 3, 4];
let cmsg = X86CMsgHdr::new(sol::SOL_SOCKET, 1, data.clone());
assert_eq!(cmsg.cmsg_level, sol::SOL_SOCKET);
assert_eq!(cmsg.cmsg_data, data);
}
#[test]
fn test_epoll_event_creation() {
let ev = X86EpollEvent::new(epoll::EPOLLIN, 5);
assert_eq!(ev.events, epoll::EPOLLIN);
assert_eq!(unsafe { ev.data.fd }, 5);
}
#[test]
fn test_pollfd_creation() {
let pfd = X86PollFd::new(3, poll::POLLIN);
assert_eq!(pfd.fd, 3);
assert_eq!(pfd.events, poll::POLLIN);
assert_eq!(pfd.revents, 0);
}
#[test]
fn test_pollfd_events() {
let mut pfd = X86PollFd::new(0, poll::POLLIN);
pfd.revents = poll::POLLIN;
assert!(pfd.can_read());
assert!(!pfd.can_write());
assert!(!pfd.has_error());
}
#[test]
fn test_networking_default() {
let net = X86Networking::default();
assert_eq!(net.platform, X86NetPlatform::Linux);
assert!(net.ipv6_enabled);
}
#[test]
fn test_networking_linux_x86_64() {
let net = X86Networking::new_linux_x86_64();
assert_eq!(net.platform, X86NetPlatform::Linux);
assert!(net.tcp_fastopen);
assert!(net.reuse_port_supported);
}
#[test]
fn test_networking_windows() {
let net = X86Networking::new_windows_x86_64();
assert_eq!(net.platform, X86NetPlatform::Windows);
assert!(!net.tcp_fastopen);
assert!(!net.reuse_port_supported);
}
#[test]
fn test_networking_macos() {
let net = X86Networking::new_macos_x86_64();
assert_eq!(net.platform, X86NetPlatform::MacOS);
assert!(!net.so_mark_supported);
}
#[test]
fn test_networking_describe() {
let net = X86Networking::new_linux_x86_64();
let desc = net.describe();
assert!(desc.contains("linux"));
assert!(desc.contains("epoll"));
}
#[test]
fn test_networking_get_protocol_header() {
let net = X86Networking::default();
let desc = net.get_protocol_header("netinet/in.h");
assert!(desc.is_some());
assert!(desc.unwrap().contains("AF_INET"));
assert!(net.get_protocol_header("nonexistent.h").is_none());
}
#[test]
fn test_networking_to_include_directives() {
let net = X86Networking::default();
let includes = net.to_include_directives();
assert!(includes.iter().any(|i| i.contains("sys/socket.h")));
assert!(includes.iter().any(|i| i.contains("netinet/in.h")));
}
#[test]
fn test_networking_stats() {
let mut stats = X86NetworkingStats::new();
stats.record_socket_created();
stats.record_socket_created();
stats.record_socket_closed();
stats.record_send(1024);
stats.record_recv(512);
stats.record_accept();
stats.record_connect();
stats.record_dns();
stats.record_tls();
stats.record_http();
stats.record_error();
assert_eq!(stats.sockets_created, 2);
assert_eq!(stats.sockets_closed, 1);
assert_eq!(stats.active_sockets(), 1);
assert_eq!(stats.bytes_sent, 1024);
assert_eq!(stats.bytes_received, 512);
assert_eq!(stats.connections_accepted, 1);
assert_eq!(stats.errors, 1);
}
#[test]
fn test_platform_has_epoll() {
assert!(X86NetPlatform::Linux.has_epoll());
assert!(!X86NetPlatform::Windows.has_epoll());
assert!(!X86NetPlatform::MacOS.has_epoll());
}
#[test]
fn test_platform_has_kqueue() {
assert!(!X86NetPlatform::Linux.has_kqueue());
assert!(!X86NetPlatform::Windows.has_kqueue());
assert!(X86NetPlatform::MacOS.has_kqueue());
assert!(X86NetPlatform::FreeBSD.has_kqueue());
}
#[test]
fn test_platform_has_iocp() {
assert!(!X86NetPlatform::Linux.has_iocp());
assert!(X86NetPlatform::Windows.has_iocp());
}
#[test]
fn test_socket_creation() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
assert!(api.is_socket(fd));
assert_eq!(api.socket_count(), 1);
}
#[test]
fn test_socket_bind_listen() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let addr = X86InAddr::any();
let sin = X86SockAddrIn::new(addr, 8080);
assert!(api.bind(fd, &sin).is_ok());
assert!(api.listen(fd, 128).is_ok());
}
#[test]
fn test_socket_accept() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let sin = X86SockAddrIn::new(X86InAddr::any(), 8080);
api.bind(fd, &sin).unwrap();
api.listen(fd, 128).unwrap();
let result = api.accept(fd);
assert!(result.is_ok());
let (client_fd, _) = result.unwrap();
assert!(api.is_socket(client_fd));
}
#[test]
fn test_socket_connect() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let sin = X86SockAddrIn::new(X86InAddr::from_octets(127, 0, 0, 1), 80);
assert!(api.connect(fd, &sin).is_ok());
}
#[test]
fn test_socket_send_recv() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let sin = X86SockAddrIn::new(X86InAddr::from_octets(127, 0, 0, 1), 80);
api.connect(fd, &sin).unwrap();
let sent = api.send(fd, b"hello", 0).unwrap();
assert_eq!(sent, 5);
let mut buf = [0u8; 1024];
let recvd = api.recv(fd, &mut buf, 0).unwrap();
assert!(recvd > 0);
}
#[test]
fn test_socket_sendto_recvfrom() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Datagram,
X86SocketProtocol::UDP,
);
let sin = X86SockAddrIn::new(X86InAddr::from_octets(127, 0, 0, 1), 53);
let sent = api.sendto(fd, b"query", 0, &sin).unwrap();
assert_eq!(sent, 5);
let mut buf = [0u8; 512];
let (recvd, addr) = api.recvfrom(fd, &mut buf, 0).unwrap();
assert!(recvd > 0);
assert_eq!(addr.sin_family, af::AF_INET);
}
#[test]
fn test_getaddrinfo() {
let api = X86SocketAPI::new_linux();
let results = api
.getaddrinfo(Some("example.com"), Some("80"), None)
.unwrap();
assert!(!results.is_empty());
}
#[test]
fn test_getaddrinfo_with_hints() {
let api = X86SocketAPI::new_linux();
let hints = X86AddrInfo::with_hints(
af::AF_INET as i32,
sock_type::SOCK_STREAM,
ipproto::IPPROTO_TCP,
0,
);
let results = api
.getaddrinfo(Some("example.com"), Some("http"), Some(&hints))
.unwrap();
assert!(!results.is_empty());
}
#[test]
fn test_getnameinfo() {
let api = X86SocketAPI::new_linux();
let sin = X86SockAddrIn::new(X86InAddr::from_octets(127, 0, 0, 1), 80);
let (host, service) = api.getnameinfo(&sin, 0).unwrap();
assert!(host.contains("127.0.0.1"));
assert_eq!(service, "http");
}
#[test]
fn test_getnameinfo_numeric() {
let api = X86SocketAPI::new_linux();
let sin = X86SockAddrIn::new(X86InAddr::from_octets(8, 8, 8, 8), 53);
let (host, service) = api
.getnameinfo(&sin, ni::NI_NUMERICHOST | ni::NI_NUMERICSERV)
.unwrap();
assert_eq!(host, "8.8.8.8");
assert_eq!(service, "53");
}
#[test]
fn test_inet_pton_ipv4() {
let result = X86SocketAPI::inet_pton(X86AddressFamily::IPv4, "192.168.1.1").unwrap();
assert_eq!(result, vec![192, 168, 1, 1]);
}
#[test]
fn test_inet_ntop_ipv4() {
let result = X86SocketAPI::inet_ntop(X86AddressFamily::IPv4, &[192, 168, 1, 1]).unwrap();
assert_eq!(result, "192.168.1.1");
}
#[test]
fn test_htons_htonl_ntohs_ntohl() {
assert_eq!(X86SocketAPI::htons(0x1234), 0x3412);
assert_eq!(X86SocketAPI::ntohs(0x3412), 0x1234);
assert_eq!(X86SocketAPI::htonl(0x12345678), 0x78563412);
assert_eq!(X86SocketAPI::ntohl(0x78563412), 0x12345678);
}
#[test]
fn test_setsockopt_getsockopt() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let val = vec![1u8];
assert!(api
.setsockopt(fd, sol::SOL_SOCKET, sockopt::SO_REUSEADDR, &val)
.is_ok());
let result = api
.getsockopt(fd, sol::SOL_SOCKET, sockopt::SO_ERROR)
.unwrap();
assert_eq!(result.len(), 4);
let result = api
.getsockopt(fd, sol::SOL_SOCKET, sockopt::SO_TYPE)
.unwrap();
assert!(!result.is_empty());
}
#[test]
fn test_fcntl_nonblock() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
assert!(api.fcntl_set_nonblock(fd).is_ok());
let flags = api.fcntl_getfl(fd).unwrap();
assert!(flags & fcntl::O_NONBLOCK != 0);
}
#[test]
fn test_poll() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let mut fds = vec![X86PollFd::new(fd, poll::POLLOUT)];
let ready = api.poll(&mut fds, 100).unwrap();
assert!(ready > 0);
}
#[test]
fn test_epoll_create_ctl_wait() {
let api = X86SocketAPI::new_linux();
let epfd = api.epoll_create(16).unwrap();
assert!(epfd > 0);
let mut events = vec![X86EpollEvent::new(0, 0)];
let ready = api.epoll_wait(epfd, &mut events, 100, 32).unwrap();
assert!(ready >= 0);
}
#[test]
fn test_epoll_create1() {
let api = X86SocketAPI::new_linux();
let epfd = api.epoll_create1(epoll::EPOLL_CLOEXEC).unwrap();
assert!(epfd > 0);
}
#[test]
fn test_kqueue() {
let api = X86SocketAPI::new_bsd();
let kq = api.kqueue().unwrap();
assert!(kq > 0);
}
#[test]
fn test_kevent() {
let api = X86SocketAPI::new_bsd();
let kq = api.kqueue().unwrap();
let changelist = vec![X86Kevent::new(
1,
kevent_flags::EVFILT_READ,
kevent_flags::EV_ADD,
)];
let mut eventlist = vec![X86Kevent::new(0, 0, 0); 1];
let n = api
.kevent(
kq,
&changelist,
&mut eventlist,
Some(Duration::from_millis(100)),
)
.unwrap();
assert!(n >= 0);
}
#[test]
fn test_iocp() {
let api = X86SocketAPI::new_windows();
let iocp = api.create_iocp().unwrap();
assert!(iocp > 0);
}
#[test]
fn test_socket_close() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
assert!(api.close(fd).is_ok());
assert!(!api.is_socket(fd));
}
#[test]
fn test_shutdown() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
assert!(api.shutdown(fd, shutdown::SHUT_RDWR).is_ok());
assert!(api.shutdown(fd, shutdown::SHUT_RD).is_ok());
assert!(api.shutdown(fd, shutdown::SHUT_WR).is_ok());
assert!(api.shutdown(fd, 99).is_err()); }
#[test]
fn test_socketpair() {
let mut api = X86SocketAPI::new_linux();
let (fd1, fd2) = api
.socketpair(
X86AddressFamily::Unix,
X86SocketType::Stream,
X86SocketProtocol::Other(0),
)
.unwrap();
assert!(api.is_socket(fd1));
assert!(api.is_socket(fd2));
}
#[test]
fn test_sendmsg_recvmsg() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let sin = X86SockAddrIn::new(X86InAddr::from_octets(127, 0, 0, 1), 80);
api.connect(fd, &sin).unwrap();
let iov = vec![X86IoVec::from_slice(b"test message")];
let msg = X86MsgHdr::new().with_iov(iov);
let sent = api.sendmsg(fd, &msg, 0).unwrap();
assert!(sent > 0);
}
#[test]
fn test_tls_library_as_str() {
assert_eq!(X86TLSLibrary::OpenSSL.as_str(), "OpenSSL");
assert_eq!(X86TLSLibrary::BoringSSL.as_str(), "BoringSSL");
assert_eq!(X86TLSLibrary::LibreSSL.as_str(), "LibreSSL");
}
#[test]
fn test_tls_version_constants() {
assert_eq!(X86TLSVersion::TLSv1_2.protocol_constant(), 0x0303);
assert_eq!(X86TLSVersion::TLSv1_3.protocol_constant(), 0x0304);
}
#[test]
fn test_tls_version_from_constant() {
assert_eq!(
X86TLSVersion::from_constant(0x0303),
Some(X86TLSVersion::TLSv1_2)
);
assert_eq!(
X86TLSVersion::from_constant(0x0304),
Some(X86TLSVersion::TLSv1_3)
);
assert_eq!(X86TLSVersion::from_constant(0x9999), None);
}
#[test]
fn test_tls_integration_creation() {
let tls = X86TLSIntegration::new_openssl();
assert!(tls.tls13_enabled);
assert!(tls.alpn_supported);
assert!(tls.sni_supported);
}
#[test]
fn test_tls_integration_boringssl() {
let tls = X86TLSIntegration::new_boringssl();
assert_eq!(tls.library, X86TLSLibrary::BoringSSL);
assert!(!tls.tls13_enabled);
}
#[test]
fn test_ssl_ctx_new() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "test");
assert!(!ctx_key.is_empty());
}
#[test]
fn test_ssl_new_set_fd() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "test");
let ssl_id = tls.ssl_new(&ctx_key).unwrap();
assert!(ssl_id > 0);
tls.ssl_set_fd(ssl_id, 5).unwrap();
}
#[test]
fn test_ssl_connect() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "test");
let ssl_id = tls.ssl_new(&ctx_key).unwrap();
let result = tls.ssl_connect(ssl_id);
assert!(result.is_ok());
}
#[test]
fn test_ssl_accept() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSServer, "test");
let ssl_id = tls.ssl_new(&ctx_key).unwrap();
let result = tls.ssl_accept(ssl_id);
assert!(result.is_ok());
}
#[test]
fn test_ssl_read_write() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "test");
let ssl_id = tls.ssl_new(&ctx_key).unwrap();
tls.ssl_connect(ssl_id).unwrap();
let data = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n";
let written = tls.ssl_write(ssl_id, data).unwrap();
assert_eq!(written, data.len());
let mut buf = [0u8; 4096];
let read = tls.ssl_read(ssl_id, &mut buf).unwrap();
assert!(read > 0);
}
#[test]
fn test_ssl_shutdown_free() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "test");
let ssl_id = tls.ssl_new(&ctx_key).unwrap();
tls.ssl_connect(ssl_id).unwrap();
assert!(tls.ssl_shutdown(ssl_id).is_ok());
assert!(tls.ssl_free(ssl_id).is_ok());
}
#[test]
fn test_ssl_sni() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "test");
let ssl_id = tls.ssl_new(&ctx_key).unwrap();
assert!(tls.ssl_set_tlsext_host_name(ssl_id, "example.com").is_ok());
}
#[test]
fn test_tls_protocol_constants() {
let tls = X86TLSIntegration::new_openssl();
let constants = tls.tls_protocol_constants();
assert!(constants.iter().any(|(name, _)| name == "TLS1_3_VERSION"));
assert!(constants.iter().any(|(name, _)| name == "TLS1_2_VERSION"));
}
#[test]
fn test_tls_compile_flags() {
let tls = X86TLSIntegration::new_openssl();
let flags = tls.ssl_compile_flags();
assert!(flags.contains(&"-lssl".to_string()));
assert!(flags.contains(&"-lcrypto".to_string()));
}
#[test]
fn test_alpn_protocol_list() {
let tls = X86TLSIntegration::new_openssl();
let data = tls.alpn_protocol_list(&["h2", "http/1.1"]);
assert_eq!(&data[..3], &[2, b'h', b'2']);
}
#[test]
fn test_tls_describe() {
let tls = X86TLSIntegration::new_openssl();
let desc = tls.describe();
assert!(desc.contains("OpenSSL"));
assert!(desc.contains("TLSv1.3"));
}
#[test]
fn test_http_method_as_str() {
assert_eq!(X86HTTPMethod::GET.as_str(), "GET");
assert_eq!(X86HTTPMethod::POST.as_str(), "POST");
}
#[test]
fn test_http_method_from_str() {
assert_eq!(X86HTTPMethod::from_str("GET"), Some(X86HTTPMethod::GET));
assert_eq!(X86HTTPMethod::from_str("INVALID"), None);
}
#[test]
fn test_http_method_safe() {
assert!(X86HTTPMethod::GET.is_safe());
assert!(X86HTTPMethod::HEAD.is_safe());
assert!(!X86HTTPMethod::POST.is_safe());
assert!(!X86HTTPMethod::DELETE.is_safe());
}
#[test]
fn test_http_method_idempotent() {
assert!(X86HTTPMethod::GET.is_idempotent());
assert!(X86HTTPMethod::PUT.is_idempotent());
assert!(!X86HTTPMethod::POST.is_idempotent());
}
#[test]
fn test_http_version() {
assert_eq!(X86HTTPVersion::HTTP11.as_str(), "HTTP/1.1");
assert_eq!(
X86HTTPVersion::from_str("HTTP/1.1"),
Some(X86HTTPVersion::HTTP11)
);
}
#[test]
fn test_url_parsing() {
let url = X86URL::parse("https://example.com:8080/path?q=1#frag").unwrap();
assert_eq!(url.scheme, "https");
assert_eq!(url.host.unwrap(), "example.com");
assert_eq!(url.port.unwrap(), 8080);
assert_eq!(url.path, "/path");
assert_eq!(url.query.unwrap(), "q=1");
assert_eq!(url.fragment.unwrap(), "frag");
}
#[test]
fn test_url_default_ports() {
let url = X86URL::parse("http://example.com/path").unwrap();
assert_eq!(url.port.unwrap(), 80);
let url = X86URL::parse("https://example.com/path").unwrap();
assert_eq!(url.port.unwrap(), 443);
}
#[test]
fn test_url_no_path_defaults_to_slash() {
let url = X86URL::parse("http://example.com").unwrap();
assert_eq!(url.path, "/");
}
#[test]
fn test_url_to_string() {
let url = X86URL::parse("https://example.com/path?q=1#frag").unwrap();
assert_eq!(url.to_string(), "https://example.com/path?q=1#frag");
}
#[test]
fn test_http_request_to_bytes() {
let url = X86URL::parse("http://example.com/index.html").unwrap();
let req = X86HTTPRequest::new(X86HTTPMethod::GET, url);
let bytes = req.to_bytes();
let s = String::from_utf8(bytes).unwrap();
assert!(s.starts_with("GET /index.html HTTP/1.1\r\n"));
assert!(s.contains("Host: example.com"));
assert!(s.contains("\r\n\r\n"));
}
#[test]
fn test_http_response_to_bytes() {
let mut resp = X86HTTPResponse::new(200);
resp.set_header("Content-Type", "text/html");
resp.body = b"<html></html>".to_vec();
let bytes = resp.to_bytes();
let s = String::from_utf8(bytes).unwrap();
assert!(s.starts_with("HTTP/1.1 200 OK\r\n"));
assert!(s.contains("Content-Type: text/html"));
}
#[test]
fn test_http_response_status_reasons() {
assert_eq!(X86HTTPResponse::reason_for_status(200), "OK");
assert_eq!(X86HTTPResponse::reason_for_status(404), "Not Found");
assert_eq!(
X86HTTPResponse::reason_for_status(500),
"Internal Server Error"
);
}
#[test]
fn test_parse_request_line() {
let result = X86HTTPSupport::parse_request_line("GET /path HTTP/1.1").unwrap();
assert_eq!(result.0, X86HTTPMethod::GET);
assert_eq!(result.1, "/path");
assert_eq!(result.2, X86HTTPVersion::HTTP11);
}
#[test]
fn test_parse_status_line() {
let result = X86HTTPSupport::parse_status_line("HTTP/1.1 200 OK").unwrap();
assert_eq!(result.0, X86HTTPVersion::HTTP11);
assert_eq!(result.1, 200);
assert_eq!(result.2, "OK");
}
#[test]
fn test_parse_headers() {
let raw = b"Content-Type: text/html\r\nContent-Length: 42\r\n\r\n";
let headers = X86HTTPSupport::parse_headers(raw).unwrap();
assert_eq!(headers.get("Content-Type").unwrap(), "text/html");
assert_eq!(headers.get("Content-Length").unwrap(), "42");
}
#[test]
fn test_content_type_for_extension() {
assert_eq!(
X86HTTPSupport::content_type_for_extension("html"),
"text/html; charset=utf-8"
);
assert_eq!(
X86HTTPSupport::content_type_for_extension("json"),
"application/json"
);
assert_eq!(
X86HTTPSupport::content_type_for_extension("bin"),
"application/octet-stream"
);
}
#[test]
fn test_chunked_encode_decode() {
let data = b"Hello, World! This is a test of chunked encoding.";
let encoded = X86HTTPSupport::chunked_encode(data);
let decoded = X86HTTPSupport::chunked_decode(&encoded).unwrap();
assert_eq!(decoded, data);
}
#[test]
fn test_http2_preface() {
let preface = X86HTTPSupport::http2_preface();
assert!(preface.starts_with(b"PRI * HTTP/2.0\r\n"));
}
#[test]
fn test_http2_initial_settings() {
let frame = X86HTTPSupport::http2_initial_settings();
assert_eq!(frame.frame_type, X86HTTP2FrameType::Settings);
assert_eq!(frame.stream_id, 0);
}
#[test]
fn test_http2_frame_to_bytes() {
let mut frame = X86HTTP2Frame::new(X86HTTP2FrameType::Ping, 0);
frame.payload = vec![1, 2, 3, 4, 5, 6, 7, 8];
let bytes = frame.to_bytes();
assert!(bytes.len() >= 9);
}
#[test]
fn test_http_support_describe() {
let http = X86HTTPSupport::new();
let desc = http.describe();
assert!(desc.contains("http1.1"));
}
#[test]
fn test_quic_config_default() {
let config = X86QUICConfig::default();
assert_eq!(config.max_idle_timeout_ms, 30000);
assert_eq!(config.supported_versions, vec![1]);
}
#[test]
fn test_dns_resolver_creation() {
let resolver = X86DNSResolver::new_default();
assert!(!resolver.nameservers.is_empty());
assert_eq!(resolver.timeout_ms, 5000);
assert!(resolver.edns0_enabled);
}
#[test]
fn test_dns_build_query() {
let query = X86DNSResolver::build_query("example.com", X86DNSRecordType::A);
assert!(query.len() >= 17); }
#[test]
fn test_dns_build_query_edns0() {
let edns0 = X86EDNS0Options::default();
let query = X86DNSResolver::build_query_edns0("example.com", X86DNSRecordType::A, &edns0);
assert!(query.len() > 17);
}
#[test]
fn test_dns_name_encode() {
let encoded = dns_name_encode("www.example.com");
assert_eq!(&encoded[0..4], &[3, b'w', b'w', b'w']);
}
#[test]
fn test_dns_name_decode() {
let encoded = dns_name_encode("www.example.com");
let decoded = dns_name_decode(&encoded).unwrap();
assert_eq!(decoded, "www.example.com");
}
#[test]
fn test_dns_record_type_codes() {
assert_eq!(X86DNSRecordType::A.code(), 1);
assert_eq!(X86DNSRecordType::AAAA.code(), 28);
assert_eq!(X86DNSRecordType::CNAME.code(), 5);
assert_eq!(X86DNSRecordType::MX.code(), 15);
}
#[test]
fn test_dns_record_type_from_code() {
assert_eq!(X86DNSRecordType::from_code(1), X86DNSRecordType::A);
assert_eq!(X86DNSRecordType::from_code(28), X86DNSRecordType::AAAA);
assert!(matches!(
X86DNSRecordType::from_code(999),
X86DNSRecordType::Unknown(_)
));
}
#[test]
fn test_dns_resolve_localhost() {
let mut resolver = X86DNSResolver::new_default();
let records = resolver.resolve("localhost", X86DNSRecordType::A);
assert!(!records.is_empty());
let addr = records[0].rdata_as_ipv4().unwrap();
assert!(addr.is_loopback());
}
#[test]
fn test_dns_resolve_example() {
let mut resolver = X86DNSResolver::new_default();
let records = resolver.resolve("example.com", X86DNSRecordType::A);
assert!(!records.is_empty());
}
#[test]
fn test_dns_reverse_lookup() {
let mut resolver = X86DNSResolver::new_default();
let addr = X86InAddr::from_octets(127, 0, 0, 1);
let _ = resolver.reverse_lookup(&addr);
}
#[test]
fn test_dns_cache() {
let mut resolver = X86DNSResolver::new_default();
resolver.resolve("cached.example.com", X86DNSRecordType::A);
let (hits, misses) = resolver.cache_stats();
assert_eq!(misses, 1);
resolver.resolve("cached.example.com", X86DNSRecordType::A);
let (hits, misses) = resolver.cache_stats();
assert_eq!(hits, 1);
assert_eq!(misses, 1);
}
#[test]
fn test_dns_flush_cache() {
let mut resolver = X86DNSResolver::new_default();
resolver.resolve("test.example.com", X86DNSRecordType::A);
resolver.flush_cache();
let (hits, misses) = resolver.cache_stats();
assert_eq!(hits, 0);
assert_eq!(misses, 0);
}
#[test]
fn test_dns_flags() {
let flags = X86DNSFlags::new_query();
assert!(flags.is_query());
assert!(!flags.is_response());
assert!(flags.recursion_desired());
let mut resp_flags = X86DNSFlags::new_response();
assert!(resp_flags.is_response());
assert_eq!(resp_flags.rcode(), 0);
resp_flags.set_rcode(3); assert_eq!(resp_flags.rcode(), 3);
}
#[test]
fn test_dns_edns0_options() {
let mut edns0 = X86EDNS0Options::default();
assert_eq!(edns0.udp_payload_size, 1232);
edns0.dnssec_ok = true;
assert!(edns0.dnssec_ok);
}
#[test]
fn test_dns_describe() {
let resolver = X86DNSResolver::new_default();
let desc = resolver.describe();
assert!(desc.contains("8.8.8.8"));
assert!(desc.contains("edns0"));
}
#[test]
fn test_dnssec_algorithms() {
assert_eq!(dnssec_algorithms::ED25519, 15);
assert_eq!(dnssec_algorithms::RSASHA256, 8);
}
#[test]
fn test_driver_creation() {
let driver = X86NetworkingDriver::new(X86NetPlatform::Linux);
assert_eq!(driver.compile_for_platform, X86NetPlatform::Linux);
}
#[test]
fn test_driver_add_source() {
let mut driver = X86NetworkingDriver::default();
driver.add_source("test.c");
assert_eq!(driver.source_files.len(), 1);
}
#[test]
fn test_driver_set_output() {
let mut driver = X86NetworkingDriver::default();
driver.set_output("a.out");
assert_eq!(driver.output_file.unwrap(), "a.out");
}
#[test]
fn test_driver_compile_flags() {
let driver = X86NetworkingDriver::new(X86NetPlatform::Linux);
let flags = driver.compile_flags();
assert!(flags.iter().any(|f| f.contains("HAS_EPOLL")));
}
#[test]
fn test_driver_linkage_flags_linux() {
let driver = X86NetworkingDriver::new(X86NetPlatform::Linux);
let flags = driver.linkage_flags();
assert!(flags.contains(&"-lpthread".to_string()));
}
#[test]
fn test_driver_linkage_flags_windows() {
let driver = X86NetworkingDriver::new(X86NetPlatform::Windows);
let flags = driver.linkage_flags();
assert!(flags.contains(&"-lws2_32".to_string()));
}
#[test]
fn test_driver_describe() {
let driver = X86NetworkingDriver::default();
let desc = driver.describe();
assert!(desc.contains("X86NetworkingDriver"));
}
#[test]
fn test_validator_creation() {
let validator = X86NetworkingValidator::new();
assert!(validator.is_valid());
assert!(validator.errors.is_empty());
}
#[test]
fn test_validator_validate_linux() {
let mut validator = X86NetworkingValidator::new();
let net = X86Networking::new_linux_x86_64();
validator.validate(&net);
assert!(validator.is_valid());
}
#[test]
fn test_validator_validate_windows_warnings() {
let mut validator = X86NetworkingValidator::new();
let net = X86Networking::new_windows_x86_64();
validator.validate(&net);
let report = validator.report();
assert!(!report.is_empty() || validator.is_valid());
}
#[test]
fn test_validator_report() {
let mut validator = X86NetworkingValidator::new();
validator.warnings.push("Test warning".to_string());
let report = validator.report();
assert!(report.contains("Test warning"));
}
#[test]
fn test_kevent_creation() {
let ev = X86Kevent::new(
42,
kevent_flags::EVFILT_READ,
kevent_flags::EV_ADD | kevent_flags::EV_ENABLE,
);
assert_eq!(ev.ident, 42);
assert_eq!(ev.filter, kevent_flags::EVFILT_READ);
}
#[test]
fn test_kevent_flags() {
assert_eq!(kevent_flags::EV_ADD, 0x0001);
assert_eq!(kevent_flags::EV_ENABLE, 0x0004);
assert_eq!(kevent_flags::EV_EOF, 0x8000);
}
#[test]
fn test_socket_handle_new() {
let handle = X86SocketHandle::new(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
assert!(!handle.bound);
assert!(!handle.connected);
}
#[test]
fn test_socket_handle_invalid() {
let handle = X86SocketHandle::invalid();
assert!(!handle.is_valid());
}
#[test]
fn test_socket_option_level_and_name() {
let opt = X86SocketOption::NoDelay(true);
let (level, name) = opt.level_and_name();
assert_eq!(level, sol::IPPROTO_TCP);
assert_eq!(name, tcp::TCP_NODELAY);
}
#[test]
fn test_address_family_to_native() {
assert_eq!(X86AddressFamily::IPv4.to_native(), af::AF_INET);
assert_eq!(X86AddressFamily::IPv6.to_native(), af::AF_INET6);
}
#[test]
fn test_address_family_from_native() {
assert_eq!(
X86AddressFamily::from_native(af::AF_INET),
X86AddressFamily::IPv4
);
}
#[test]
fn test_socket_type_to_native() {
assert_eq!(X86SocketType::Stream.to_native(), sock_type::SOCK_STREAM);
}
#[test]
fn test_socket_protocol_to_native() {
assert_eq!(X86SocketProtocol::TCP.to_native(), ipproto::IPPROTO_TCP);
}
#[test]
fn test_http_response_content_length() {
let mut resp = X86HTTPResponse::new(200);
resp.set_header("Content-Length", "42");
assert_eq!(resp.content_length(), Some(42));
}
#[test]
fn test_http_response_chunked() {
let mut resp = X86HTTPResponse::new(200);
resp.set_header("Transfer-Encoding", "chunked");
assert!(resp.is_chunked());
}
#[test]
fn test_http_status_constants() {
assert_eq!(http_status::OK, 200);
assert_eq!(http_status::NOT_FOUND, 404);
assert_eq!(http_status::INTERNAL_SERVER_ERROR, 500);
}
#[test]
fn test_socket_option_reuseaddr() {
let opt = X86SocketOption::ReuseAddr(true);
let (lvl, name) = opt.level_and_name();
assert_eq!(lvl, sol::SOL_SOCKET);
assert_eq!(name, sockopt::SO_REUSEADDR);
}
#[test]
fn test_socket_option_tcp_nodelay() {
let opt = X86SocketOption::NoDelay(true);
let (lvl, name) = opt.level_and_name();
assert_eq!(lvl, sol::IPPROTO_TCP);
assert_eq!(name, tcp::TCP_NODELAY);
}
#[test]
fn test_dns_record_ipv4() {
let rec = X86DNSRecord::new("test", X86DNSRecordType::A, 300, vec![127, 0, 0, 1]);
let addr = rec.rdata_as_ipv4().unwrap();
assert!(addr.is_loopback());
}
#[test]
fn test_dns_record_ipv6() {
let rec = X86DNSRecord::new(
"test",
X86DNSRecordType::AAAA,
300,
vec![0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
);
let addr = rec.rdata_as_ipv6().unwrap();
assert_eq!(addr.to_segments()[0], 0x2001);
}
#[test]
fn test_dns_record_cname() {
let cname_data = dns_name_encode("target.example.com");
let rec = X86DNSRecord::new("alias", X86DNSRecordType::CNAME, 600, cname_data);
let target = rec.rdata_as_string().unwrap();
assert_eq!(target, "target.example.com");
}
#[test]
fn test_url_path_and_query() {
let url = X86URL::parse("http://example.com/search?q=rust").unwrap();
assert_eq!(url.path_and_query(), "/search?q=rust");
}
#[test]
fn test_url_no_query_or_fragment() {
let url = X86URL::parse("http://example.com/index.html").unwrap();
assert!(url.query.is_none());
assert!(url.fragment.is_none());
}
#[test]
fn test_af_families_exhaustive() {
let families = vec![
af::AF_INET,
af::AF_INET6,
af::AF_UNIX,
af::AF_NETLINK,
af::AF_PACKET,
af::AF_IPX,
af::AF_AX25,
af::AF_ATMPVC,
af::AF_X25,
af::AF_BLUETOOTH,
af::AF_CAN,
af::AF_ALG,
af::AF_VSOCK,
];
for &fam in &families {
let af = X86AddressFamily::from_native(fam);
if !matches!(af, X86AddressFamily::Other(_)) {
assert_eq!(af.to_native(), fam);
}
}
}
#[test]
fn test_hostent_creation() {
let ent = X86HostEnt::new(
"example.com".to_string(),
af::AF_INET as i32,
4,
vec![vec![192, 0, 2, 1]],
);
assert_eq!(ent.h_name, "example.com");
assert_eq!(ent.h_addrtype, af::AF_INET as i32);
assert_eq!(ent.h_length, 4);
}
#[test]
fn test_ip_constants() {
assert_eq!(ip::IP_TTL, 2);
assert_eq!(ip::IP_TOS, 1);
assert_eq!(ip::IP_PKTINFO, 8);
assert_eq!(ip::IP_HDRINCL, 3);
}
#[test]
fn test_ipv6_constants() {
assert_eq!(ipv6::IPV6_V6ONLY, 26);
assert_eq!(ipv6::IPV6_UNICAST_HOPS, 16);
assert_eq!(ipv6::IPV6_MULTICAST_LOOP, 19);
}
#[test]
fn test_udp_constants() {
assert_eq!(udp::UDP_CORK, 1);
assert_eq!(udp::UDP_SEGMENT, 103);
}
#[test]
fn test_fcntl_constants() {
assert_eq!(fcntl::F_GETFL, 3);
assert_eq!(fcntl::F_SETFL, 4);
assert_eq!(fcntl::O_NONBLOCK, 0o4000);
}
#[test]
fn test_inaddr_constants() {
assert_eq!(inaddr::INADDR_ANY, 0x00000000);
assert_eq!(inaddr::INADDR_LOOPBACK, 0x7F000001);
}
#[test]
fn test_socket_handle_set_option() {
let mut handle = X86SocketHandle::new(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
handle.set_option(X86SocketOption::ReuseAddr(true));
assert!(handle.reuse_addr);
handle.set_option(X86SocketOption::ReusePort(true));
assert!(handle.reuse_port);
}
#[test]
fn test_socket_handle_default_invalid() {
let handle = X86SocketHandle::default();
assert!(!handle.is_valid());
assert_eq!(handle.fd, X86_INVALID_SOCKET);
}
#[test]
fn test_address_family_display() {
assert_eq!(format!("{}", X86AddressFamily::IPv4), "AF_INET");
assert_eq!(format!("{}", X86AddressFamily::IPv6), "AF_INET6");
assert_eq!(format!("{}", X86AddressFamily::Unix), "AF_UNIX");
assert_eq!(format!("{}", X86AddressFamily::Netlink), "AF_NETLINK");
assert_eq!(format!("{}", X86AddressFamily::Packet), "AF_PACKET");
}
#[test]
fn test_ifaddrs_creation() {
let ifa = X86IfAddrs::new("eth0");
assert_eq!(ifa.ifa_name, "eth0");
assert!(ifa.ifa_addr.is_none());
}
#[test]
fn test_ifreq_creation() {
let ifr = X86IfReq::new("eth0");
assert!(ifr.name().unwrap().starts_with("eth0"));
}
#[test]
fn test_sockaddr_storage_default() {
let ss = X86SockAddrStorage::default();
assert_eq!(ss.family(), af::AF_UNSPEC);
}
#[test]
fn test_in6_addr_link_local() {
let addr = X86In6Addr::from_segments(0xfe80, 0, 0, 0, 0, 0, 0, 1);
assert!(addr.is_link_local());
}
#[test]
fn test_in6_addr_multicast() {
let addr = X86In6Addr::from_segments(0xff02, 0, 0, 0, 0, 0, 0, 1);
assert!(addr.is_multicast());
}
#[test]
fn test_in6_addr_v4_compat() {
let mut addr = X86In6Addr::any();
addr.s6_addr[12] = 192;
addr.s6_addr[13] = 168;
addr.s6_addr[14] = 1;
addr.s6_addr[15] = 1;
assert!(addr.is_v4_compat());
}
#[test]
fn test_in6_addr_from_u128() {
let val: u128 = 0x20010db8000000000000000000000001;
let addr = X86In6Addr::from_u128(val);
assert_eq!(addr.to_u128(), val);
}
#[test]
fn test_sockaddr_new() {
let sa = X86SockAddr::new(af::AF_INET);
assert_eq!(sa.sa_family, af::AF_INET);
}
#[test]
fn test_in_addr_default() {
let addr = X86InAddr::default();
assert_eq!(addr.s_addr, inaddr::INADDR_ANY);
}
#[test]
fn test_in6_addr_default() {
let addr = X86In6Addr::default();
assert!(addr.is_unspecified());
}
#[test]
fn test_tls_version_min_supported() {
assert_eq!(
X86TLSVersion::min_supported(X86TLSLibrary::OpenSSL),
X86TLSVersion::TLSv1_2
);
assert_eq!(
X86TLSVersion::min_supported(X86TLSLibrary::BoringSSL),
X86TLSVersion::TLSv1_2
);
}
#[test]
fn test_tls_version_max_supported() {
assert_eq!(
X86TLSVersion::max_supported(X86TLSLibrary::OpenSSL),
X86TLSVersion::TLSv1_3
);
assert_eq!(
X86TLSVersion::max_supported(X86TLSLibrary::BoringSSL),
X86TLSVersion::TLSv1_2
);
}
#[test]
fn test_tls_version_display() {
assert_eq!(format!("{}", X86TLSVersion::TLSv1_2), "TLSv1.2");
assert_eq!(format!("{}", X86TLSVersion::TLSv1_3), "TLSv1.3");
assert_eq!(format!("{}", X86TLSVersion::SSLv3), "SSLv3");
}
#[test]
fn test_tls_library_display() {
assert_eq!(format!("{}", X86TLSLibrary::OpenSSL), "OpenSSL");
assert_eq!(format!("{}", X86TLSLibrary::SChannel), "SChannel");
}
#[test]
fn test_tls_error_from_code() {
assert_eq!(X86TLSError::from_ssl_error(0), X86TLSError::None);
assert_eq!(X86TLSError::from_ssl_error(2), X86TLSError::WantRead);
assert_eq!(X86TLSError::from_ssl_error(3), X86TLSError::WantWrite);
}
#[test]
fn test_tls_integration_libressl() {
let tls = X86TLSIntegration::new_libressl();
assert_eq!(tls.library, X86TLSLibrary::LibreSSL);
}
#[test]
fn test_ssl_context_creation() {
let ctx = X86SSLContext::new(X86TLSMethod::TLS, X86TLSLibrary::OpenSSL);
assert_eq!(ctx.min_version, X86TLSVersion::TLSv1_2);
assert!(ctx.session_cache_enabled);
}
#[test]
fn test_ssl_new_invalid_ctx() {
let mut tls = X86TLSIntegration::new_openssl();
assert!(tls.ssl_new("nonexistent").is_err());
}
#[test]
fn test_ssl_set_fd_invalid() {
let mut tls = X86TLSIntegration::new_openssl();
assert!(tls.ssl_set_fd(9999, 5).is_err());
}
#[test]
fn test_ssl_read_before_connect() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "test");
let ssl_id = tls.ssl_new(&ctx_key).unwrap();
let mut buf = [0u8; 1024];
let result = tls.ssl_read(ssl_id, &mut buf);
assert!(result.is_err());
}
#[test]
fn test_tls_secure_transport() {
let tls = X86TLSIntegration::new_secure_transport();
assert_eq!(tls.library, X86TLSLibrary::SecureTransport);
assert!(!tls.alpn_supported);
}
#[test]
fn test_tls_method_enum() {
let _m = X86TLSMethod::TLSClient;
let _m = X86TLSMethod::TLSServer;
let _m = X86TLSMethod::TLS;
let _m = X86TLSMethod::DTLSClient;
let _m = X86TLSMethod::DTLSServer;
let _m = X86TLSMethod::DTLS;
}
#[test]
fn test_http_method_display() {
assert_eq!(format!("{}", X86HTTPMethod::GET), "GET");
assert_eq!(format!("{}", X86HTTPMethod::CONNECT), "CONNECT");
}
#[test]
fn test_http_version_display() {
assert_eq!(format!("{}", X86HTTPVersion::HTTP10), "HTTP/1.0");
assert_eq!(format!("{}", X86HTTPVersion::HTTP2), "HTTP/2.0");
assert_eq!(format!("{}", X86HTTPVersion::HTTP3), "HTTP/3.0");
}
#[test]
fn test_http_request_with_body() {
let url = X86URL::parse("http://example.com/api").unwrap();
let mut req = X86HTTPRequest::new(X86HTTPMethod::POST, url);
req.body = b"{\"key\": \"value\"}".to_vec();
let bytes = req.to_bytes();
let s = String::from_utf8(bytes).unwrap();
assert!(s.contains("Content-Length"));
assert!(s.contains("\\\"key\\\""));
}
#[test]
fn test_http_response_no_body() {
let resp = X86HTTPResponse::new(204);
let bytes = resp.to_bytes();
let s = String::from_utf8(bytes).unwrap();
assert!(s.contains("204"));
}
#[test]
fn test_url_userinfo() {
let url = X86URL::parse("http://user:pass@example.com/path").unwrap();
assert_eq!(url.host.unwrap(), "example.com");
}
#[test]
fn test_url_display() {
let url = X86URL::parse("http://example.com/path").unwrap();
assert_eq!(format!("{}", url), "http://example.com/path");
}
#[test]
fn test_http2_frame_types() {
assert_eq!(X86HTTP2FrameType::Data.code(), 0x0);
assert_eq!(X86HTTP2FrameType::Headers.code(), 0x1);
assert_eq!(X86HTTP2FrameType::Settings.code(), 0x4);
assert_eq!(X86HTTP2FrameType::GoAway.code(), 0x7);
}
#[test]
fn test_http2_settings_constants() {
assert_eq!(http2_settings::SETTINGS_HEADER_TABLE_SIZE, 0x1);
assert_eq!(http2_settings::SETTINGS_MAX_CONCURRENT_STREAMS, 0x3);
}
#[test]
fn test_http_support_to_clang_flags() {
let mut http = X86HTTPSupport::new();
http.http2_enabled = true;
let flags = http.to_clang_flags();
assert!(flags.contains(&"-DHTTP2_SUPPORTED".to_string()));
}
#[test]
fn test_http_support_http3_flag() {
let mut http = X86HTTPSupport::new();
http.http3_enabled = true;
let flags = http.to_clang_flags();
assert!(flags.contains(&"-DHTTP3_SUPPORTED".to_string()));
}
#[test]
fn test_content_type_various() {
assert_eq!(
X86HTTPSupport::content_type_for_extension("png"),
"image/png"
);
assert_eq!(
X86HTTPSupport::content_type_for_extension("jpg"),
"image/jpeg"
);
assert_eq!(
X86HTTPSupport::content_type_for_extension("svg"),
"image/svg+xml"
);
assert_eq!(
X86HTTPSupport::content_type_for_extension("wasm"),
"application/wasm"
);
}
#[test]
fn test_dns_record_type_as_str() {
assert_eq!(X86DNSRecordType::A.as_str(), "A");
assert_eq!(X86DNSRecordType::MX.as_str(), "MX");
assert_eq!(X86DNSRecordType::SRV.as_str(), "SRV");
}
#[test]
fn test_dns_resolve_cname() {
let mut resolver = X86DNSResolver::new_default();
let records = resolver.resolve("www.example.com", X86DNSRecordType::CNAME);
assert!(!records.is_empty());
}
#[test]
fn test_dns_resolve_mx() {
let mut resolver = X86DNSResolver::new_default();
let records = resolver.resolve("example.com", X86DNSRecordType::MX);
assert!(!records.is_empty());
}
#[test]
fn test_dns_resolve_txt() {
let mut resolver = X86DNSResolver::new_default();
let records = resolver.resolve("example.com", X86DNSRecordType::TXT);
assert!(!records.is_empty());
}
#[test]
fn test_dns_resolve_missing_domain() {
let mut resolver = X86DNSResolver::new_default();
let records = resolver.resolve("nonexistent", X86DNSRecordType::A);
let _ = records;
}
#[test]
fn test_dns_message_parse_header() {
let mut data = vec![0u8; 12];
data[0] = 0x12;
data[1] = 0x34; data[2] = 0x81;
data[3] = 0x80; data[4] = 0x00;
data[5] = 0x01;
if let Some(msg) = X86DNSResolver::parse_response(&data) {
assert_eq!(msg.id, 0x1234);
assert!(msg.flags.is_response());
}
}
#[test]
fn test_dns_flags_opcode() {
let flags = X86DNSFlags { raw: 0x0800 }; assert_eq!(flags.opcode(), 1);
}
#[test]
fn test_dns_flags_authoritative() {
let flags = X86DNSFlags { raw: 0x8400 };
assert!(flags.authoritative());
}
#[test]
fn test_dns_flags_truncated() {
let flags = X86DNSFlags { raw: 0x8200 };
assert!(flags.truncated());
}
#[test]
fn test_dns_question_creation() {
let q = X86DNSQuestion::new("example.com", X86DNSRecordType::A);
assert_eq!(q.qname, "example.com");
assert_eq!(q.qtype, X86DNSRecordType::A);
assert_eq!(q.qclass, 1);
}
#[test]
fn test_dns_record_txt() {
let txt_content = b"v=spf1 -all";
let mut rdata = vec![txt_content.len() as u8];
rdata.extend_from_slice(txt_content);
let rec = X86DNSRecord::new("test", X86DNSRecordType::TXT, 300, rdata);
assert_eq!(rec.rdata_as_string(), Some("v=spf1 -all".to_string()));
}
#[test]
fn test_dns_edns0_default() {
let edns0 = X86EDNS0Options::default();
assert_eq!(edns0.udp_payload_size, 1232);
assert!(!edns0.dnssec_ok);
assert!(edns0.options.is_empty());
}
#[test]
fn test_dns_record_types_all() {
let types = vec![
(X86DNSRecordType::A, 1u16),
(X86DNSRecordType::NS, 2),
(X86DNSRecordType::CNAME, 5),
(X86DNSRecordType::SOA, 6),
(X86DNSRecordType::PTR, 12),
(X86DNSRecordType::MX, 15),
(X86DNSRecordType::TXT, 16),
(X86DNSRecordType::AAAA, 28),
(X86DNSRecordType::SRV, 33),
(X86DNSRecordType::CAA, 257),
];
for (t, code) in types {
assert_eq!(t.code(), code, "Wrong code for {:?}", t);
}
}
#[test]
fn test_socket_bind_twice_fails() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let sin = X86SockAddrIn::new(X86InAddr::any(), 8080);
assert!(api.bind(fd, &sin).is_ok());
assert!(api.bind(fd, &sin).is_err());
}
#[test]
fn test_socket_listen_not_bound() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
assert!(api.listen(fd, 128).is_err());
}
#[test]
fn test_socket_operations_invalid_fd() {
let mut api = X86SocketAPI::new_linux();
assert!(api.send(999, b"test", 0).is_err());
assert!(api.close(999).is_err());
}
#[test]
fn test_epoll_not_available_on_windows() {
let api = X86SocketAPI::new_windows();
assert!(api.epoll_create(16).is_err());
}
#[test]
fn test_kqueue_not_available_on_linux() {
let api = X86SocketAPI::new_linux();
assert!(api.kqueue().is_err());
}
#[test]
fn test_iocp_not_available_on_linux() {
let api = X86SocketAPI::new_linux();
assert!(api.create_iocp().is_err());
}
#[test]
fn test_socket_nonblocking_option() {
let mut handle = X86SocketHandle::new(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
assert!(!handle.nonblocking);
handle.set_option(X86SocketOption::NonBlocking);
assert!(handle.nonblocking);
}
#[test]
fn test_socket_type_from_native() {
assert_eq!(
X86SocketType::from_native(sock_type::SOCK_STREAM),
X86SocketType::Stream
);
assert_eq!(
X86SocketType::from_native(sock_type::SOCK_STREAM | sock_type::SOCK_NONBLOCK),
X86SocketType::Stream
);
}
#[test]
fn test_socket_handle_set_option_coverage() {
let mut handle = X86SocketHandle::new(
X86AddressFamily::IPv6,
X86SocketType::Datagram,
X86SocketProtocol::UDP,
);
handle.set_option(X86SocketOption::KeepAlive(true));
handle.set_option(X86SocketOption::Broadcast(true));
handle.set_option(X86SocketOption::TTL(64));
handle.set_option(X86SocketOption::IPv6Only(true));
handle.set_option(X86SocketOption::DontRoute(true));
handle.set_option(X86SocketOption::QuickAck(true));
handle.set_option(X86SocketOption::BindToDevice("eth0".to_string()));
handle.set_option(X86SocketOption::Mark(42));
handle.set_option(X86SocketOption::Timestamp(true));
handle.set_option(X86SocketOption::DontFragment(true));
handle.set_option(X86SocketOption::Priority(5));
}
#[test]
fn test_socket_option_linger() {
let opt = X86SocketOption::Linger(Some(Duration::from_secs(5)));
let (lvl, name) = opt.level_and_name();
assert_eq!(lvl, sol::SOL_SOCKET);
assert_eq!(name, sockopt::SO_LINGER);
}
#[test]
fn test_socket_option_linger_none() {
let opt = X86SocketOption::Linger(None);
let (lvl, name) = opt.level_and_name();
assert_eq!(lvl, sol::SOL_SOCKET);
assert_eq!(name, sockopt::SO_LINGER);
}
#[test]
fn test_socket_option_recv_timeout() {
let opt = X86SocketOption::RecvTimeout(Duration::from_millis(5000));
let (lvl, name) = opt.level_and_name();
assert_eq!(lvl, sol::SOL_SOCKET);
assert_eq!(name, sockopt::SO_RCVTIMEO);
}
#[test]
fn test_platform_default() {
let p = X86NetPlatform::default();
assert_eq!(p, X86NetPlatform::Linux);
}
#[test]
fn test_platform_display() {
assert_eq!(format!("{}", X86NetPlatform::FreeBSD), "freebsd");
assert_eq!(format!("{}", X86NetPlatform::NetBSD), "netbsd");
assert_eq!(format!("{}", X86NetPlatform::OpenBSD), "openbsd");
assert_eq!(format!("{}", X86NetPlatform::Solaris), "solaris");
}
#[test]
fn test_platform_has_epoll_exhaustive() {
assert!(X86NetPlatform::Linux.has_epoll());
assert!(!X86NetPlatform::Windows.has_epoll());
assert!(!X86NetPlatform::MacOS.has_epoll());
assert!(!X86NetPlatform::FreeBSD.has_epoll());
assert!(!X86NetPlatform::NetBSD.has_epoll());
assert!(!X86NetPlatform::OpenBSD.has_epoll());
assert!(!X86NetPlatform::Solaris.has_epoll());
}
#[test]
fn test_platform_has_kqueue_exhaustive() {
assert!(!X86NetPlatform::Linux.has_kqueue());
assert!(!X86NetPlatform::Windows.has_kqueue());
assert!(X86NetPlatform::MacOS.has_kqueue());
assert!(X86NetPlatform::FreeBSD.has_kqueue());
assert!(X86NetPlatform::NetBSD.has_kqueue());
assert!(X86NetPlatform::OpenBSD.has_kqueue());
assert!(!X86NetPlatform::Solaris.has_kqueue());
}
#[test]
fn test_driver_windows() {
let driver = X86NetworkingDriver::new(X86NetPlatform::Windows);
assert_eq!(driver.compile_for_platform, X86NetPlatform::Windows);
}
#[test]
fn test_driver_macos() {
let driver = X86NetworkingDriver::new(X86NetPlatform::MacOS);
assert_eq!(driver.compile_for_platform, X86NetPlatform::MacOS);
}
#[test]
fn test_driver_add_multiple_sources() {
let mut driver = X86NetworkingDriver::default();
driver.add_source("a.c");
driver.add_source("b.c");
driver.add_source("c.c");
assert_eq!(driver.source_files.len(), 3);
}
#[test]
fn test_validator_validate_macos() {
let mut validator = X86NetworkingValidator::new();
let net = X86Networking::new_macos_x86_64();
validator.validate(&net);
assert!(!validator.warnings.is_empty());
}
#[test]
fn test_validator_validate_ipv6_disabled() {
let mut validator = X86NetworkingValidator::new();
let mut net = X86Networking::new_linux_x86_64();
net.ipv6_enabled = false;
validator.validate(&net);
assert!(validator.warnings.iter().any(|w| w.contains("IPv6")));
}
#[test]
fn test_validator_with_errors() {
let mut validator = X86NetworkingValidator::new();
validator.errors.push("Critical failure".to_string());
assert!(!validator.is_valid());
let report = validator.report();
assert!(report.contains("Critical failure"));
}
#[test]
fn test_networking_stats_all_zero() {
let stats = X86NetworkingStats::new();
let summary = stats.summary();
assert!(summary.contains("0/0 active"));
}
#[test]
fn test_networking_stats_saturation() {
let mut stats = X86NetworkingStats::new();
stats.sockets_created = u64::MAX;
stats.record_socket_closed();
assert_eq!(stats.active_sockets(), u64::MAX - 1);
}
#[test]
fn test_networking_stats_multiple_ops() {
let mut stats = X86NetworkingStats::new();
for _ in 0..100 {
stats.record_socket_created();
stats.record_send(100);
stats.record_recv(100);
}
assert_eq!(stats.sockets_created, 100);
assert_eq!(stats.bytes_sent, 10000);
assert_eq!(stats.bytes_received, 10000);
}
#[test]
fn test_in_addr_new() {
let addr = X86InAddr::new(0x12345678);
assert_eq!(addr.s_addr, 0x12345678);
}
#[test]
fn test_in_addr_any() {
let addr = X86InAddr::any();
assert_eq!(addr.s_addr, inaddr::INADDR_ANY);
}
#[test]
fn test_in_addr_loopback_v2() {
let addr = X86InAddr::loopback();
assert!(addr.is_loopback());
}
#[test]
fn test_parse_ipv4_valid() {
assert!(parse_ipv4("8.8.8.8").is_some());
assert!(parse_ipv4("192.168.0.1").is_some());
}
#[test]
fn test_parse_ipv4_invalid() {
assert!(parse_ipv4("invalid").is_none());
assert!(parse_ipv4("256.1.1.1").is_none());
assert!(parse_ipv4("1.2.3").is_none());
}
#[test]
fn test_sockaddr_in_from_str() {
let sin = X86SockAddrIn::from_str("10.0.0.1", 8080).unwrap();
assert_eq!(sin.sin_family, af::AF_INET);
assert_eq!(sin.port(), 8080);
}
#[test]
fn test_sockaddr_in_from_str_invalid() {
assert!(X86SockAddrIn::from_str("bad", 80).is_none());
}
#[test]
fn test_networking_stats_default() {
let stats = X86NetworkingStats::default();
assert_eq!(stats.sockets_created, 0);
}
#[test]
fn test_tls_session_new() {
let session = X86TLSSession::new(1);
assert_eq!(session.id, 1);
assert_eq!(session.state, X86TLSState::Init);
}
#[test]
fn test_http_response_copy() {
let resp1 = X86HTTPResponse::new(200);
let resp2 = resp1.clone();
assert_eq!(resp2.status, 200);
}
#[test]
fn test_http_request_clone() {
let url = X86URL::parse("http://example.com").unwrap();
let req1 = X86HTTPRequest::new(X86HTTPMethod::GET, url.clone());
let req2 = req1.clone();
assert_eq!(req2.method, X86HTTPMethod::GET);
}
#[test]
fn test_url_no_scheme_fails() {
assert!(X86URL::parse("example.com/path").is_err());
}
#[test]
fn test_url_ipv6_host() {
let url = X86URL::parse("http://[::1]:8080/path").unwrap();
assert_eq!(url.host.unwrap(), "[::1]");
assert_eq!(url.port.unwrap(), 8080);
}
#[test]
fn test_url_ftp_port() {
let url = X86URL::parse("ftp://example.com/files").unwrap();
assert_eq!(url.port.unwrap(), 21);
}
#[test]
fn test_url_ssh_port() {
let url = X86URL::parse("ssh://example.com").unwrap();
assert_eq!(url.port.unwrap(), 22);
}
#[test]
fn test_http2_frame_flags() {
let mut frame = X86HTTP2Frame::new(X86HTTP2FrameType::Headers, 1);
frame.flags = 0x04; let bytes = frame.to_bytes();
assert!(bytes.len() >= 9);
}
#[test]
fn test_pollfd_multiple_events() {
let mut pfd = X86PollFd::new(5, poll::POLLIN | poll::POLLOUT);
pfd.revents = poll::POLLIN | poll::POLLOUT;
assert!(pfd.can_read());
assert!(pfd.can_write());
}
#[test]
fn test_pollfd_error_conditions() {
let mut pfd = X86PollFd::new(0, 0);
pfd.revents = poll::POLLERR;
assert!(pfd.has_error());
pfd.revents = poll::POLLHUP;
assert!(pfd.has_error());
pfd.revents = poll::POLLNVAL;
assert!(pfd.has_error());
}
#[test]
fn test_address_family_display_other() {
let af = X86AddressFamily::Other(42);
assert!(format!("{}", af).contains("42"));
}
#[test]
fn test_socket_option_clang_names() {
assert_eq!(
X86SocketOption::ReuseAddr(true).clang_option_name(),
"SO_REUSEADDR"
);
assert_eq!(
X86SocketOption::IPv6Only(true).clang_option_name(),
"IPV6_V6ONLY"
);
assert_eq!(
X86SocketOption::QuickAck(true).clang_option_name(),
"TCP_QUICKACK"
);
assert_eq!(X86SocketOption::PeerCred.clang_option_name(), "SO_PEERCRED");
assert_eq!(
X86SocketOption::AcceptConn.clang_option_name(),
"SO_ACCEPTCONN"
);
}
#[test]
fn test_networking_freebsd() {
let net = X86Networking::new_freebsd_x86_64();
assert_eq!(net.platform, X86NetPlatform::FreeBSD);
}
#[test]
fn test_networking_linux_x86_32() {
let net = X86Networking::new_linux_x86_32();
assert!(!net.tcp_fastopen);
}
#[test]
fn test_networking_default_platform() {
let net: X86Networking = Default::default();
assert_eq!(net.platform, X86NetPlatform::Linux);
}
#[test]
fn test_socket_api_default() {
let api: X86SocketAPI = Default::default();
assert_eq!(api.platform, X86NetPlatform::Linux);
assert!(api.use_epoll);
}
#[test]
fn test_tls_integration_default() {
let tls: X86TLSIntegration = Default::default();
assert_eq!(tls.library, X86TLSLibrary::OpenSSL);
}
#[test]
fn test_http_support_default() {
let http: X86HTTPSupport = Default::default();
assert!(http.http11_enabled);
}
#[test]
fn test_dns_resolver_default() {
let resolver: X86DNSResolver = Default::default();
assert!(!resolver.nameservers.is_empty());
}
#[test]
fn test_driver_default() {
let driver: X86NetworkingDriver = Default::default();
assert_eq!(driver.compile_for_platform, X86NetPlatform::Linux);
}
#[test]
fn test_validator_default() {
let v: X86NetworkingValidator = Default::default();
assert!(v.is_valid());
}
#[test]
fn test_protocol_headers_all_modules() {
let _ = af::AF_INET;
let _ = sock_type::SOCK_STREAM;
let _ = ipproto::IPPROTO_TCP;
let _ = sol::SOL_SOCKET;
let _ = sockopt::SO_REUSEADDR;
let _ = tcp::TCP_NODELAY;
let _ = ip::IP_TTL;
let _ = ipv6::IPV6_V6ONLY;
let _ = epoll::EPOLL_CTL_ADD;
let _ = ai::AI_PASSIVE;
let _ = ni::NI_NUMERICHOST;
let _ = msg::MSG_PEEK;
let _ = poll::POLLIN;
let _ = shutdown::SHUT_RD;
}
#[test]
fn test_in6addr_any_init() {
assert_eq!(inet6::IN6ADDR_ANY_INIT, [0u8; 16]);
}
#[test]
fn test_in6addr_loopback_init() {
let expected: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
assert_eq!(inet6::IN6ADDR_LOOPBACK_INIT, expected);
}
#[test]
fn test_tcp_option_constants_all() {
assert_eq!(tcp::TCP_NODELAY, 1);
assert_eq!(tcp::TCP_KEEPINTVL, 5);
assert_eq!(tcp::TCP_KEEPCNT, 6);
assert_eq!(tcp::TCP_CORK, 3);
assert_eq!(tcp::TCP_FASTOPEN, 23);
}
#[test]
fn test_ip_pmtu_constants() {
assert_eq!(ip::IP_PMTUDISC_DONT, 0);
assert_eq!(ip::IP_PMTUDISC_WANT, 1);
assert_eq!(ip::IP_PMTUDISC_DO, 2);
assert_eq!(ip::IP_PMTUDISC_PROBE, 3);
}
#[test]
fn test_msg_flag_combinations() {
let flags = msg::MSG_DONTWAIT | msg::MSG_NOSIGNAL;
assert!(flags & msg::MSG_DONTWAIT != 0);
assert!(flags & msg::MSG_NOSIGNAL != 0);
}
#[test]
fn test_in6_addr_site_local() {
let addr = X86In6Addr::from_segments(0xfec0, 0, 0, 0, 0, 0, 0, 1);
assert!(addr.is_site_local());
}
#[test]
fn test_getaddrinfo_service_names() {
let api = X86SocketAPI::new_linux();
let r = api.getaddrinfo(Some("localhost"), Some("https"), None);
assert!(r.is_ok());
}
#[test]
fn test_getaddrinfo_unknown_service() {
let api = X86SocketAPI::new_linux();
let r = api.getaddrinfo(Some("localhost"), Some("unknown"), None);
assert!(r.is_ok());
}
#[test]
fn test_freeaddrinfo() {
let api = X86SocketAPI::new_linux();
let results = api
.getaddrinfo(Some("localhost"), Some("80"), None)
.unwrap();
api.freeaddrinfo(results);
}
#[test]
fn test_inet_pton_ipv6() {
let result = X86SocketAPI::inet_pton(X86AddressFamily::IPv6, "::1");
assert!(result.is_ok());
}
#[test]
fn test_inet_pton_unsupported() {
assert!(X86SocketAPI::inet_pton(X86AddressFamily::Unix, "test").is_err());
}
#[test]
fn test_inet_ntop_ipv6() {
let result = X86SocketAPI::inet_ntop(X86AddressFamily::IPv6, &inet6::IN6ADDR_LOOPBACK_INIT);
assert!(result.is_ok());
}
#[test]
fn test_inet_ntop_short_data() {
assert!(X86SocketAPI::inet_ntop(X86AddressFamily::IPv4, &[1, 2]).is_err());
}
#[test]
fn test_epoll_ctl_invalid_op() {
let api = X86SocketAPI::new_linux();
assert!(api.epoll_ctl(1, 99, 0, None).is_err());
}
#[test]
fn test_iocp_associate() {
let api = X86SocketAPI::new_windows();
let iocp = api.create_iocp().unwrap();
assert!(api.iocp_associate(iocp, 0, 0).is_ok());
}
#[test]
fn test_iocp_get_status() {
let api = X86SocketAPI::new_windows();
let iocp = api.create_iocp().unwrap();
let result = api.iocp_get_status(iocp);
assert!(result.is_ok());
}
#[test]
fn test_shutdown_invalid_how() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
assert!(api.shutdown(fd, 99).is_err());
}
#[test]
fn test_dns_name_encode_simple() {
let encoded = dns_name_encode("a");
assert_eq!(encoded, vec![1, b'a', 0]);
}
#[test]
fn test_dns_name_decode_empty() {
assert_eq!(dns_name_decode(&[0]), None);
}
#[test]
fn test_dns_resolver_with_nameserver() {
let resolver = X86DNSResolver::new_default().with_nameserver("9.9.9.9:53");
assert_eq!(resolver.nameservers.len(), 3);
}
#[test]
fn test_chunked_decode_truncated() {
let result = X86HTTPSupport::chunked_decode(b"5\r\nhel");
assert!(result.is_err());
}
#[test]
fn test_chunked_decode_invalid_hex() {
let result = X86HTTPSupport::chunked_decode(b"GG\r\n");
assert!(result.is_err());
}
#[test]
fn test_http2_frame_clears_reserved_bit() {
let mut frame = X86HTTP2Frame::new(X86HTTP2FrameType::Data, 0x80000001);
frame.payload = vec![0];
let bytes = frame.to_bytes();
assert_eq!(bytes[7] & 0x80, 0);
}
#[test]
fn test_cmsghdr_ancillary_space() {
let space = X86CMsgHdr::ancillary_data_space(8);
assert!(space >= 24);
}
#[test]
fn test_tls_state_values() {
let states = vec![
X86TLSState::Init,
X86TLSState::Handshake,
X86TLSState::Connected,
X86TLSState::Shutdown,
X86TLSState::Error,
];
for _s in states {}
}
#[test]
fn test_tls_error_values() {
let errors = vec![
X86TLSError::None,
X86TLSError::SSL,
X86TLSError::WantRead,
X86TLSError::WantWrite,
X86TLSError::ZeroReturn,
];
for _e in errors {}
}
#[test]
fn test_ipproto_all() {
let protos = vec![
ipproto::IPPROTO_TCP,
ipproto::IPPROTO_UDP,
ipproto::IPPROTO_ICMP,
ipproto::IPPROTO_SCTP,
ipproto::IPPROTO_UDPLITE,
ipproto::IPPROTO_MPTCP,
ipproto::IPPROTO_GRE,
ipproto::IPPROTO_ESP,
ipproto::IPPROTO_AH,
];
for _p in protos {}
}
#[test]
fn test_ipv6_option_constants() {
assert_eq!(ipv6::IPV6_RECVPKTINFO, 49);
assert_eq!(ipv6::IPV6_RECVHOPLIMIT, 51);
assert_eq!(ipv6::IPV6_RECVTCLASS, 66);
assert_eq!(ipv6::IPV6_TRANSPARENT, 75);
}
#[test]
fn test_sockaddr_in_new_port_bytes() {
let addr = X86InAddr::from_octets(10, 0, 0, 1);
let sin = X86SockAddrIn::new(addr, 0x1234);
assert_eq!(sin.sin_port.to_be_bytes(), 0x1234u16.to_be_bytes());
}
#[test]
fn test_networking_get_protocol_header_all() {
let net = X86Networking::default();
let headers = vec![
"netinet/in.h",
"netinet/tcp.h",
"netinet/udp.h",
"netinet/ip.h",
"netinet/ip6.h",
"netinet/icmp6.h",
"arpa/inet.h",
"netdb.h",
"sys/socket.h",
"sys/un.h",
"net/if.h",
"ifaddrs.h",
"sys/epoll.h",
"sys/event.h",
];
for h in headers {
assert!(net.get_protocol_header(h).is_some(), "Missing: {}", h);
}
}
#[test]
fn test_socket_option_nonblocking_variant() {
let mut handle = X86SocketHandle::new(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
handle.set_option(X86SocketOption::NonBlocking);
assert!(handle.nonblocking);
}
#[test]
fn test_tls_version_all_constants() {
let versions = vec![
X86TLSVersion::SSLv3,
X86TLSVersion::TLSv1_0,
X86TLSVersion::TLSv1_1,
X86TLSVersion::TLSv1_2,
X86TLSVersion::TLSv1_3,
];
for v in versions {
assert!(v.protocol_constant() > 0);
let back = X86TLSVersion::from_constant(v.protocol_constant()).unwrap();
assert_eq!(back, v);
}
}
#[test]
fn test_url_query_only() {
let url = X86URL::parse("http://example.com/?key=value").unwrap();
assert_eq!(url.query.unwrap(), "key=value");
}
#[test]
fn test_url_fragment_only() {
let url = X86URL::parse("http://example.com/#section").unwrap();
assert_eq!(url.fragment.unwrap(), "section");
}
#[test]
fn test_url_query_and_fragment() {
let url = X86URL::parse("http://example.com/path?a=1&b=2#top").unwrap();
assert_eq!(url.query.unwrap(), "a=1&b=2");
assert_eq!(url.fragment.unwrap(), "top");
}
#[test]
fn test_iovec_empty() {
let iov = X86IoVec::from_slice(b"");
assert_eq!(iov.iov_len, 0);
}
#[test]
fn test_iovec_large() {
let data = vec![0x41u8; 65536];
let iov = X86IoVec::new(data.clone());
assert_eq!(iov.iov_len, 65536);
}
#[test]
fn test_dns_build_query_unknown_type() {
let query = X86DNSResolver::build_query("test.com", X86DNSRecordType::Unknown(999));
assert!(!query.is_empty());
}
#[test]
fn test_http_support_all_features() {
let http = X86HTTPSupport::new();
assert!(http.enable_chunked_encoding);
assert!(http.enable_compression);
assert_eq!(http.max_header_size, 65536);
assert_eq!(http.max_body_size, 10 * 1024 * 1024);
}
#[test]
fn test_networking_describe_all_platforms() {
let linux = X86Networking::new_linux_x86_64();
assert!(linux.describe().contains("epoll"));
let win = X86Networking::new_windows_x86_64();
assert!(win.describe().contains("iocp"));
let mac = X86Networking::new_macos_x86_64();
assert!(mac.describe().contains("kqueue"));
let fbsd = X86Networking::new_freebsd_x86_64();
assert!(fbsd.describe().contains("kqueue"));
}
#[test]
fn test_sol_levels() {
assert_eq!(sol::SOL_SOCKET, 1);
assert_eq!(sol::SOL_IP, 0);
assert_eq!(sol::SOL_TCP, 6);
assert_eq!(sol::SOL_UDP, 17);
assert_eq!(sol::SOL_IPV6, 41);
assert_eq!(sol::SOL_RAW, 255);
}
#[test]
fn test_socket_type_from_native_cloexec() {
let t = X86SocketType::from_native(sock_type::SOCK_STREAM | sock_type::SOCK_CLOEXEC);
assert_eq!(t, X86SocketType::Stream);
}
#[test]
fn test_networking_to_include_unique() {
let net = X86Networking::default();
let includes = net.to_include_directives();
assert!(includes.len() > 5);
}
#[test]
fn test_kevent_filter_constants() {
assert_eq!(kevent_flags::EVFILT_READ, -1);
assert_eq!(kevent_flags::EVFILT_WRITE, -2);
assert_eq!(kevent_flags::EVFILT_TIMER, -7);
}
#[test]
fn test_tls_library_default() {
let lib: X86TLSLibrary = Default::default();
assert_eq!(lib, X86TLSLibrary::OpenSSL);
}
#[test]
fn test_addrinfo_default_fields() {
let ai: X86AddrInfo = Default::default();
assert_eq!(ai.ai_family, af::AF_UNSPEC as i32);
assert!(ai.ai_next.is_none());
}
#[test]
fn test_invalid_socket_fd() {
assert_eq!(X86_INVALID_SOCKET, -1);
}
#[test]
fn test_dns_resolver_edge_cases() {
let mut resolver = X86DNSResolver::new_default();
let _ = resolver.resolve("localhost6", X86DNSRecordType::AAAA);
for _ in 0..5 {
let _ = resolver.resolve("repeated.example.com", X86DNSRecordType::A);
}
let (hits, _) = resolver.cache_stats();
assert!(hits >= 1);
}
#[test]
fn test_url_with_percent() {
let url = X86URL::parse("http://example.com/path%20with%20spaces").unwrap();
assert_eq!(url.path, "/path%20with%20spaces");
}
#[test]
fn test_http2_data_frame() {
let mut frame = X86HTTP2Frame::new(X86HTTP2FrameType::Data, 1);
frame.payload = b"hello world".to_vec();
frame.flags = 0x01; let bytes = frame.to_bytes();
let len = ((bytes[0] as u32) << 16) | ((bytes[1] as u32) << 8) | (bytes[2] as u32);
assert_eq!(len, 11);
}
#[test]
fn test_http_response_complex() {
let mut resp = X86HTTPResponse::new(200);
resp.set_header("Content-Type", "application/json");
resp.set_header("Cache-Control", "no-cache");
resp.set_header("X-Custom", "clang-net");
resp.body = b"{}".to_vec();
let bytes = resp.to_bytes();
let s = String::from_utf8(bytes).unwrap();
assert!(s.contains("200 OK"));
assert!(s.contains("application/json"));
assert!(s.contains("Content-Length"));
}
#[test]
fn test_pollfd_no_events() {
let pfd = X86PollFd::new(5, poll::POLLIN);
assert!(!pfd.can_read());
assert!(!pfd.can_write());
assert!(!pfd.has_error());
}
#[test]
fn test_recvmsg_sets_flags() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let mut msg = X86MsgHdr::new();
let _ = api.recvmsg(fd, &mut msg, 0);
assert_eq!(msg.msg_flags, 0);
}
#[test]
fn test_sockaddr_in_sin_zero() {
let sin = X86SockAddrIn::new(X86InAddr::any(), 0);
assert_eq!(sin.sin_zero, [0u8; 8]);
}
#[test]
fn test_http_request_clone_equals() {
let url = X86URL::parse("http://example.com").unwrap();
let req = X86HTTPRequest::new(X86HTTPMethod::GET, url);
let _req2 = req.clone();
}
#[test]
fn test_url_clone_equals() {
let url = X86URL::parse("http://example.com/path").unwrap();
let _url2 = url.clone();
}
#[test]
fn test_dns_record_rdata_not_ipv4() {
let rec = X86DNSRecord::new("test", X86DNSRecordType::AAAA, 300, vec![]);
assert!(rec.rdata_as_ipv4().is_none());
}
#[test]
fn test_dns_record_rdata_not_ipv6() {
let rec = X86DNSRecord::new("test", X86DNSRecordType::A, 300, vec![]);
assert!(rec.rdata_as_ipv6().is_none());
}
}
#[cfg(test)]
mod tests_extended_v1 {
use super::*;
#[test]
fn test_dns_record_rdata_not_ipv6_v2() {
let rec = X86DNSRecord::new("test", X86DNSRecordType::A, 300, vec![]);
assert!(rec.rdata_as_ipv6().is_none());
}
#[test]
fn test_full_networking_pipeline_v2() {
let net = X86Networking::new_linux_x86_64();
let desc = net.describe();
assert!(desc.len() > 0);
let driver = X86NetworkingDriver::new(net.platform);
let flags = driver.compile_flags();
assert!(!flags.is_empty());
}
#[test]
fn test_socket_option_so_mark_v2() {
let opt = X86SocketOption::Mark(0xDEADBEEF);
let (lvl, name) = opt.level_and_name();
assert_eq!(lvl, sol::SOL_SOCKET);
assert_eq!(name, sockopt::SO_MARK);
}
#[test]
fn test_socket_option_tcp_fastopen_v2() {
let opt = X86SocketOption::TCPFastOpen(true, 10);
let (lvl, name) = opt.level_and_name();
assert_eq!(lvl, sol::IPPROTO_TCP);
assert_eq!(name, tcp::TCP_FASTOPEN);
}
#[test]
fn test_icmp6_filter_constants_v2() {
assert_eq!(icmp6::ICMP6_FILTER, 1);
assert_eq!(icmp6::ICMP6_FILTER_BLOCKALL, 1);
assert_eq!(icmp6::ICMP6_FILTER_PASSALL, 2);
}
#[test]
fn test_msg_flags_comprehensive_v2() {
assert_eq!(msg::MSG_MORE, 0x8000);
assert_eq!(msg::MSG_CONFIRM, 0x800);
assert_eq!(msg::MSG_EOR, 0x80);
assert_eq!(msg::MSG_WAITALL, 0x100);
assert_eq!(msg::MSG_FASTOPEN, 0x20000000);
}
#[test]
fn test_in6_addr_full_segments_v2() {
let addr = X86In6Addr::from_segments(
0x2001, 0x0db8, 0x85a3, 0x0000, 0x8a2e, 0x0370, 0x7334, 0x0001,
);
let segs = addr.to_segments();
assert_eq!(segs[0], 0x2001);
assert_eq!(segs[7], 0x0001);
}
#[test]
fn test_edns0_option_creation_v2() {
let opt = X86EDNS0Option {
code: 8,
data: vec![0x18, 0x00, 0x01],
};
assert_eq!(opt.code, 8);
}
#[test]
fn test_dnssec_algorithm_constants_v2() {
assert_eq!(dnssec_algorithms::RSASHA256, 8);
assert_eq!(dnssec_algorithms::ECDSAP256SHA256, 13);
assert_eq!(dnssec_algorithms::ED25519, 15);
assert_eq!(dnssec_algorithms::ED448, 16);
}
#[test]
fn test_dnssec_digest_constants_v2() {
assert_eq!(dnssec_digests::SHA1, 1);
assert_eq!(dnssec_digests::SHA256, 2);
assert_eq!(dnssec_digests::SHA384, 4);
}
#[test]
fn test_socket_protocol_all_variants_v2() {
assert_eq!(X86SocketProtocol::TCP.to_native(), ipproto::IPPROTO_TCP);
assert_eq!(X86SocketProtocol::UDP.to_native(), ipproto::IPPROTO_UDP);
assert_eq!(X86SocketProtocol::ICMP.to_native(), ipproto::IPPROTO_ICMP);
assert_eq!(X86SocketProtocol::Raw.to_native(), ipproto::IPPROTO_RAW);
assert_eq!(X86SocketProtocol::SCTP.to_native(), ipproto::IPPROTO_SCTP);
assert_eq!(
X86SocketProtocol::UDPLite.to_native(),
ipproto::IPPROTO_UDPLITE
);
assert_eq!(X86SocketProtocol::Other(99).to_native(), 99);
}
#[test]
fn test_socket_type_all_variants_v2() {
assert_eq!(X86SocketType::Stream.to_native(), sock_type::SOCK_STREAM);
assert_eq!(X86SocketType::Datagram.to_native(), sock_type::SOCK_DGRAM);
assert_eq!(X86SocketType::Raw.to_native(), sock_type::SOCK_RAW);
assert_eq!(
X86SocketType::SeqPacket.to_native(),
sock_type::SOCK_SEQPACKET
);
assert_eq!(X86SocketType::Other(99).to_native(), 99);
let nb = X86SocketType::NonBlock(sock_type::SOCK_STREAM).to_native();
assert!(nb & sock_type::SOCK_NONBLOCK != 0);
}
#[test]
fn test_ipproto_comprehensive_v2() {
assert_eq!(ipproto::IPPROTO_IP, 0);
assert_eq!(ipproto::IPPROTO_ICMP, 1);
assert_eq!(ipproto::IPPROTO_IGMP, 2);
assert_eq!(ipproto::IPPROTO_IPV6, 41);
assert_eq!(ipproto::IPPROTO_ICMPV6, 58);
assert_eq!(ipproto::IPPROTO_DCCP, 33);
assert_eq!(ipproto::IPPROTO_COMP, 108);
}
#[test]
fn test_ai_flags_combination_v2() {
let flags = ai::AI_PASSIVE | ai::AI_NUMERICHOST | ai::AI_ADDRCONFIG;
assert!(flags & ai::AI_PASSIVE != 0);
assert!(flags & ai::AI_NUMERICHOST != 0);
assert!(flags & ai::AI_ADDRCONFIG != 0);
}
#[test]
fn test_ni_flags_combination_v2() {
let flags = ni::NI_NUMERICHOST | ni::NI_NUMERICSERV | ni::NI_DGRAM;
assert!(flags & ni::NI_NUMERICHOST != 0);
assert!(flags & ni::NI_NUMERICSERV != 0);
assert!(flags & ni::NI_DGRAM != 0);
}
#[test]
fn test_epoll_flag_combinations_v2() {
let flags = epoll::EPOLLIN | epoll::EPOLLET | epoll::EPOLLONESHOT;
assert!(flags & epoll::EPOLLIN != 0);
assert!(flags & epoll::EPOLLET != 0);
assert!(flags & epoll::EPOLLONESHOT != 0);
}
#[test]
fn test_socket_option_buf_sizes_v2() {
let send_opt = X86SocketOption::SendBuf(65536);
let (lvl, name) = send_opt.level_and_name();
assert_eq!(lvl, sol::SOL_SOCKET);
assert_eq!(name, sockopt::SO_SNDBUF);
let recv_opt = X86SocketOption::RecvBuf(65536);
let (lvl, name) = recv_opt.level_and_name();
assert_eq!(lvl, sol::SOL_SOCKET);
assert_eq!(name, sockopt::SO_RCVBUF);
}
#[test]
fn test_tls_verify_modes_v2() {
let modes = vec![
X86TLSVerifyMode::None,
X86TLSVerifyMode::Peer,
X86TLSVerifyMode::PeerFailIfNoPeerCert,
X86TLSVerifyMode::ClientOnce,
];
assert_eq!(modes.len(), 4);
}
#[test]
fn test_tls_state_transitions_v2() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "trans");
let ssl_id = tls.ssl_new(&ctx_key).unwrap();
tls.ssl_connect(ssl_id).unwrap();
tls.ssl_shutdown(ssl_id).unwrap();
tls.ssl_free(ssl_id).unwrap();
}
#[test]
fn test_multiple_tls_sessions_v2() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "multi");
let mut sessions = Vec::new();
for _ in 0..10 {
let id = tls.ssl_new(&ctx_key).unwrap();
tls.ssl_connect(id).unwrap();
sessions.push(id);
}
for id in sessions {
tls.ssl_shutdown(id).unwrap();
tls.ssl_free(id).unwrap();
}
}
#[test]
fn test_dns_parallel_resolutions_v2() {
let mut resolver = X86DNSResolver::new_default();
let hosts = vec![
"a.example.com",
"b.example.com",
"c.example.com",
"d.example.com",
"e.example.com",
];
for host in hosts {
let records = resolver.resolve(host, X86DNSRecordType::A);
assert!(!records.is_empty());
}
}
#[test]
fn test_poll_timeout_zero_v2() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let mut fds = vec![X86PollFd::new(fd, poll::POLLOUT)];
let ready = api.poll(&mut fds, 0).unwrap();
assert!(ready >= 0);
}
#[test]
fn test_epoll_wait_timeout_v2() {
let api = X86SocketAPI::new_linux();
let epfd = api.epoll_create(1).unwrap();
let mut events = vec![X86EpollEvent::new(0, 0); 1];
let result = api.epoll_wait(epfd, &mut events, 50, 32);
assert!(result.is_ok());
}
#[test]
fn test_kevent_timeout_v2() {
let api = X86SocketAPI::new_bsd();
let kq = api.kqueue().unwrap();
let changelist = vec![];
let mut eventlist = vec![X86Kevent::new(0, 0, 0); 1];
let n = api
.kevent(
kq,
&changelist,
&mut eventlist,
Some(Duration::from_millis(10)),
)
.unwrap();
assert!(n >= 0);
}
#[test]
fn test_select_timeout_v2() {
let api = X86SocketAPI::new_linux();
let mut readfds = HashSet::new();
readfds.insert(3);
let mut writefds = HashSet::new();
let mut exceptfds = HashSet::new();
let result = api.select(
10,
&mut readfds,
&mut writefds,
&mut exceptfds,
Some(Duration::from_millis(100)),
);
assert!(result.is_ok());
}
#[test]
fn test_sendmsg_with_data_v2() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Datagram,
X86SocketProtocol::UDP,
);
let iov = vec![
X86IoVec::from_slice(b"part1"),
X86IoVec::from_slice(b"part2"),
X86IoVec::from_slice(b"part3"),
];
let msg = X86MsgHdr::new().with_iov(iov);
let sent = api.sendmsg(fd, &msg, msg::MSG_DONTWAIT).unwrap();
assert_eq!(sent, 15);
}
#[test]
fn test_cmsghdr_custom_data_v2() {
let cmsg = X86CMsgHdr::new(sol::SOL_IP, ip::IP_PKTINFO, vec![1, 2, 3, 4, 5, 6, 7, 8]);
assert!(cmsg.cmsg_len > 0);
assert_eq!(cmsg.cmsg_level, sol::SOL_IP);
assert_eq!(cmsg.cmsg_type, ip::IP_PKTINFO);
}
#[test]
fn test_large_iovec_v2() {
let iov = (0..100)
.map(|i| X86IoVec::from_slice(&[i as u8; 64]))
.collect::<Vec<_>>();
let msg = X86MsgHdr::new().with_iov(iov);
assert_eq!(msg.total_data_len(), 6400);
}
#[test]
fn test_poll_with_multiple_fds_v2() {
let mut api = X86SocketAPI::new_linux();
let fds: Vec<_> = (0..5)
.map(|_| {
api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
)
})
.collect();
let mut pollfds: Vec<_> = fds
.iter()
.map(|&fd| X86PollFd::new(fd, poll::POLLOUT))
.collect();
let ready = api.poll(&mut pollfds, 100).unwrap();
assert_eq!(ready, 5);
}
#[test]
fn test_socketpair_unix_stream_v2() {
let mut api = X86SocketAPI::new_linux();
let (fd1, fd2) = api
.socketpair(
X86AddressFamily::Unix,
X86SocketType::Stream,
X86SocketProtocol::Other(0),
)
.unwrap();
assert!(api.is_socket(fd1));
assert!(api.is_socket(fd2));
api.close(fd1).unwrap();
api.close(fd2).unwrap();
}
#[test]
fn test_socket_lifecycle_v2() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
assert!(api.is_socket(fd));
assert_eq!(api.socket_count(), 1);
api.fcntl_set_nonblock(fd).unwrap();
let sin = X86SockAddrIn::new(X86InAddr::any(), 12345);
api.bind(fd, &sin).unwrap();
api.listen(fd, 5).unwrap();
api.close(fd).unwrap();
assert!(!api.is_socket(fd));
assert_eq!(api.socket_count(), 0);
}
#[test]
fn test_udp_socket_operations_v2() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Datagram,
X86SocketProtocol::UDP,
);
let sin = X86SockAddrIn::new(X86InAddr::any(), 9999);
api.bind(fd, &sin).unwrap();
let dest = X86SockAddrIn::new(X86InAddr::from_octets(127, 0, 0, 1), 9999);
api.sendto(fd, b"ping", 0, &dest).unwrap();
let mut buf = [0u8; 1024];
api.recvfrom(fd, &mut buf, 0).unwrap();
api.close(fd).unwrap();
}
#[test]
fn test_tcp_server_tls_conceptual_v2() {
let mut api = X86SocketAPI::new_linux();
let server_fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let sin = X86SockAddrIn::new(X86InAddr::any(), 8443);
api.bind(server_fd, &sin).unwrap();
api.listen(server_fd, 128).unwrap();
let (client_fd, _addr) = api.accept(server_fd).unwrap();
assert!(api.is_socket(client_fd));
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSServer, "server");
let ssl_id = tls.ssl_new(&ctx_key).unwrap();
tls.ssl_set_fd(ssl_id, client_fd).unwrap();
tls.ssl_accept(ssl_id).unwrap();
let mut buf = [0u8; 4096];
let _ = tls.ssl_read(ssl_id, &mut buf);
let _ = tls.ssl_write(ssl_id, b"HTTP/1.1 200 OK\r\n\r\n");
tls.ssl_shutdown(ssl_id).unwrap();
tls.ssl_free(ssl_id).unwrap();
api.close(client_fd).unwrap();
}
#[test]
fn test_ipv6_socket_lifecycle_v2() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv6,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
assert!(api.is_socket(fd));
let val = vec![0u8];
api.setsockopt(fd, sol::SOL_IPV6, ipv6::IPV6_V6ONLY, &val)
.unwrap();
api.close(fd).unwrap();
}
#[test]
fn test_all_platforms_exist_v2() {
let platforms = vec![
X86NetPlatform::Linux,
X86NetPlatform::Windows,
X86NetPlatform::MacOS,
X86NetPlatform::FreeBSD,
X86NetPlatform::NetBSD,
X86NetPlatform::OpenBSD,
X86NetPlatform::Solaris,
];
for p in platforms {
let s = format!("{}", p);
assert!(!s.is_empty());
}
}
#[test]
fn test_raw_socket_creation_v2() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Raw,
X86SocketProtocol::ICMP,
);
assert!(api.is_socket(fd));
api.close(fd).unwrap();
}
#[test]
fn test_getaddrinfo_multiple_hints_v2() {
let api = X86SocketAPI::new_linux();
let hints_ipv4 = X86AddrInfo::with_hints(
af::AF_INET as i32,
sock_type::SOCK_STREAM,
ipproto::IPPROTO_TCP,
ai::AI_NUMERICHOST,
);
let r1 = api.getaddrinfo(Some("127.0.0.1"), Some("80"), Some(&hints_ipv4));
assert!(r1.is_ok());
let hints_passive = X86AddrInfo::with_hints(
af::AF_UNSPEC as i32,
sock_type::SOCK_STREAM,
0,
ai::AI_PASSIVE,
);
let r2 = api.getaddrinfo(None, Some("80"), Some(&hints_passive));
assert!(r2.is_ok());
}
#[test]
fn test_sockaddr_in6_port_v2() {
let addr = X86In6Addr::loopback();
let sin6 = X86SockAddrIn6::new(addr, 0x1234);
assert_eq!(sin6.port(), 0x1234);
}
#[test]
fn test_http_request_custom_headers_v2() {
let url = X86URL::parse("http://example.com/api").unwrap();
let mut req = X86HTTPRequest::new(X86HTTPMethod::POST, url);
req.set_header("Authorization", "Bearer token123");
req.set_header("X-Request-ID", "abc-123");
let bytes = req.to_bytes();
let s = String::from_utf8(bytes).unwrap();
assert!(s.contains("Authorization: Bearer token123"));
assert!(s.contains("X-Request-ID: abc-123"));
}
#[test]
fn test_http_response_get_header_v2() {
let mut resp = X86HTTPResponse::new(200);
resp.set_header("Server", "Clang-X86");
assert_eq!(resp.get_header("Server"), Some("Clang-X86"));
assert_eq!(resp.get_header("Missing"), None);
}
#[test]
fn test_dns_resolver_nameservers_present_v2() {
let resolver = X86DNSResolver::new_default();
assert!(resolver.nameservers.contains(&"8.8.8.8:53".to_string()));
assert!(resolver.nameservers.contains(&"1.1.1.1:53".to_string()));
}
#[test]
fn test_dns_name_decode_simple_v2() {
let data = vec![
3, b'w', b'w', b'w', 7, b'e', b'x', b'a', b'm', b'p', b'l', b'e', 3, b'c', b'o', b'm',
0,
];
let name = dns_name_decode(&data).unwrap();
assert_eq!(name, "www.example.com");
}
#[test]
fn test_dns_name_decode_too_long_v2() {
let data = vec![20, b'x'];
assert!(dns_name_decode(&data).is_none());
}
#[test]
fn test_dns_query_edns0_dnssec_v2() {
let mut edns0 = X86EDNS0Options::default();
edns0.dnssec_ok = true;
let query =
X86DNSResolver::build_query_edns0("dnssec.example.com", X86DNSRecordType::A, &edns0);
assert!(query.len() > 17);
}
#[test]
fn test_inet_pton_ipv6_loopback_v2() {
let result = X86SocketAPI::inet_pton(X86AddressFamily::IPv6, "::1").unwrap();
assert_eq!(result, inet6::IN6ADDR_LOOPBACK_INIT.to_vec());
}
#[test]
fn test_inet_ntop_ipv6_loopback_v2() {
let s =
X86SocketAPI::inet_ntop(X86AddressFamily::IPv6, &inet6::IN6ADDR_LOOPBACK_INIT).unwrap();
assert_eq!(s, "::1");
}
#[test]
fn test_e2e_http_flow_v2() {
let mut api = X86SocketAPI::new_linux();
let mut resolver = X86DNSResolver::new_default();
let records = resolver.resolve("example.com", X86DNSRecordType::A);
assert!(!records.is_empty());
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let sin = X86SockAddrIn::new(X86InAddr::from_octets(93, 184, 216, 34), 80);
api.connect(fd, &sin).unwrap();
let url = X86URL::parse("http://example.com/index.html").unwrap();
let req = X86HTTPRequest::new(X86HTTPMethod::GET, url);
api.send(fd, &req.to_bytes(), 0).unwrap();
let mut buf = [0u8; 4096];
let _ = api.recv(fd, &mut buf, 0);
api.close(fd).unwrap();
}
#[test]
fn test_multiple_tls_contexts_v2() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx1 = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "ctx1");
let ctx2 = tls.ssl_ctx_new(X86TLSMethod::TLSServer, "ctx2");
let c1 = tls.ssl_new(&ctx1).unwrap();
let c2 = tls.ssl_new(&ctx2).unwrap();
tls.ssl_connect(c1).unwrap();
tls.ssl_accept(c2).unwrap();
tls.ssl_free(c1).unwrap();
tls.ssl_free(c2).unwrap();
}
#[test]
fn test_integration_socket_to_tls_v2() {
let mut api = X86SocketAPI::new_linux();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
let sin = X86SockAddrIn::new(X86InAddr::from_octets(93, 184, 216, 34), 443);
api.connect(fd, &sin).unwrap();
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "web");
let ssl_id = tls.ssl_new(&ctx_key).unwrap();
tls.ssl_set_fd(ssl_id, fd).unwrap();
tls.ssl_set_tlsext_host_name(ssl_id, "example.com").unwrap();
assert!(tls.ssl_connect(ssl_id).is_ok());
}
#[test]
fn test_integration_dns_to_http_v2() {
let mut resolver = X86DNSResolver::new_default();
let records = resolver.resolve("example.com", X86DNSRecordType::A);
assert!(!records.is_empty());
let url = X86URL::parse("http://example.com/index.html").unwrap();
let req = X86HTTPRequest::new(X86HTTPMethod::GET, url);
let bytes = req.to_bytes();
assert!(!bytes.is_empty());
}
#[test]
fn test_stress_many_sockets() {
let mut api = X86SocketAPI::new_linux();
let mut fds = Vec::new();
for _ in 0..50 {
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
fds.push(fd);
}
assert_eq!(api.socket_count(), 50);
for fd in fds {
api.close(fd).unwrap();
}
assert_eq!(api.socket_count(), 0);
}
#[test]
fn test_stress_dns_cache() {
let mut resolver = X86DNSResolver::new_default();
for _ in 0..20 {
let _ = resolver.resolve("stress.example.com", X86DNSRecordType::A);
}
let (hits, _) = resolver.cache_stats();
assert!(hits >= 19);
}
#[test]
fn test_stress_http_requests() {
let url = X86URL::parse("http://example.com/api").unwrap();
for _ in 0..50 {
let req = X86HTTPRequest::new(X86HTTPMethod::GET, url.clone());
let bytes = req.to_bytes();
assert!(!bytes.is_empty());
}
}
#[test]
fn test_stress_tls_handshakes() {
let mut tls = X86TLSIntegration::new_openssl();
let ctx_key = tls.ssl_ctx_new(X86TLSMethod::TLSClient, "stress");
let mut ids = Vec::new();
for _ in 0..20 {
let id = tls.ssl_new(&ctx_key).unwrap();
tls.ssl_connect(id).unwrap();
ids.push(id);
}
for id in ids {
tls.ssl_shutdown(id).unwrap();
tls.ssl_free(id).unwrap();
}
}
#[test]
fn test_all_af_families_exhaustive_coverage() {
let families = [
af::AF_INET,
af::AF_INET6,
af::AF_UNIX,
af::AF_NETLINK,
af::AF_PACKET,
af::AF_IPX,
af::AF_APPLETALK,
af::AF_AX25,
af::AF_DECnet,
af::AF_BLUETOOTH,
af::AF_BRIDGE,
af::AF_ATMPVC,
af::AF_ROSE,
af::AF_NETBEUI,
af::AF_SECURITY,
af::AF_KEY,
af::AF_QOS,
af::AF_VSOCK,
af::AF_NFC,
af::AF_ALG,
af::AF_CAN,
af::AF_TIPC,
af::AF_RDS,
af::AF_IUCV,
af::AF_RXRPC,
af::AF_PHONET,
af::AF_IEEE802154,
af::AF_CAIF,
af::AF_KCM,
af::AF_SMC,
af::AF_XDP,
af::AF_MCTP,
];
for &fam in &families {
let _ = X86AddressFamily::from_native(fam);
}
}
#[test]
fn test_all_sockopt_constants() {
let opts = [
sockopt::SO_DEBUG,
sockopt::SO_REUSEADDR,
sockopt::SO_TYPE,
sockopt::SO_ERROR,
sockopt::SO_DONTROUTE,
sockopt::SO_BROADCAST,
sockopt::SO_SNDBUF,
sockopt::SO_RCVBUF,
sockopt::SO_KEEPALIVE,
sockopt::SO_OOBINLINE,
sockopt::SO_LINGER,
sockopt::SO_REUSEPORT,
sockopt::SO_PASSCRED,
sockopt::SO_PEERCRED,
sockopt::SO_RCVLOWAT,
sockopt::SO_SNDLOWAT,
sockopt::SO_RCVTIMEO,
sockopt::SO_SNDTIMEO,
sockopt::SO_BINDTODEVICE,
sockopt::SO_TIMESTAMP,
sockopt::SO_ACCEPTCONN,
sockopt::SO_PEERSEC,
sockopt::SO_MARK,
sockopt::SO_PROTOCOL,
sockopt::SO_DOMAIN,
sockopt::SO_BUSY_POLL,
sockopt::SO_INCOMING_CPU,
sockopt::SO_ZEROCOPY,
sockopt::SO_TXTIME,
sockopt::SO_INCOMING_NAPI_ID,
];
for &opt in &opts {
assert!(opt >= 0);
}
}
#[test]
fn test_all_tcp_options() {
let opts = [
tcp::TCP_NODELAY,
tcp::TCP_MAXSEG,
tcp::TCP_CORK,
tcp::TCP_KEEPIDLE,
tcp::TCP_KEEPINTVL,
tcp::TCP_KEEPCNT,
tcp::TCP_SYNCNT,
tcp::TCP_LINGER2,
tcp::TCP_DEFER_ACCEPT,
tcp::TCP_WINDOW_CLAMP,
tcp::TCP_INFO,
tcp::TCP_QUICKACK,
tcp::TCP_CONGESTION,
tcp::TCP_MD5SIG,
tcp::TCP_USER_TIMEOUT,
tcp::TCP_FASTOPEN,
tcp::TCP_TIMESTAMP,
tcp::TCP_NOTSENT_LOWAT,
tcp::TCP_FASTOPEN_CONNECT,
tcp::TCP_ULP,
tcp::TCP_ZEROCOPY_RECEIVE,
];
for &opt in &opts {
assert!(opt > 0, "TCP option {} should be positive", opt);
}
}
#[test]
fn test_all_ipv6_options() {
let opts = [
ipv6::IPV6_ADDRFORM,
ipv6::IPV6_PKTINFO,
ipv6::IPV6_HOPLIMIT,
ipv6::IPV6_NEXTHOP,
ipv6::IPV6_UNICAST_HOPS,
ipv6::IPV6_MULTICAST_IF,
ipv6::IPV6_MULTICAST_HOPS,
ipv6::IPV6_MULTICAST_LOOP,
ipv6::IPV6_V6ONLY,
ipv6::IPV6_RECVPKTINFO,
ipv6::IPV6_RECVHOPLIMIT,
ipv6::IPV6_RECVTCLASS,
ipv6::IPV6_TCLASS,
ipv6::IPV6_TRANSPARENT,
ipv6::IPV6_FREEBIND,
ipv6::IPV6_MINHOPCOUNT,
];
for &opt in &opts {
assert!(opt > 0, "IPv6 option {} should be positive", opt);
}
}
#[test]
fn test_all_ip_options() {
let opts = [
ip::IP_TOS,
ip::IP_TTL,
ip::IP_HDRINCL,
ip::IP_OPTIONS,
ip::IP_ROUTER_ALERT,
ip::IP_RECVOPTS,
ip::IP_RETOPTS,
ip::IP_PKTINFO,
ip::IP_PKTOPTIONS,
ip::IP_MTU_DISCOVER,
ip::IP_RECVERR,
ip::IP_RECVTTL,
ip::IP_RECVTOS,
ip::IP_MTU,
ip::IP_FREEBIND,
ip::IP_TRANSPARENT,
ip::IP_ORIGDSTADDR,
ip::IP_MINTTL,
ip::IP_NODEFRAG,
];
for &opt in &opts {
assert!(opt > 0, "IP option {} should be positive", opt);
}
}
#[test]
fn test_all_epoll_flags() {
let flags = [
epoll::EPOLLIN,
epoll::EPOLLOUT,
epoll::EPOLLPRI,
epoll::EPOLLERR,
epoll::EPOLLHUP,
epoll::EPOLLRDHUP,
epoll::EPOLLET,
epoll::EPOLLONESHOT,
epoll::EPOLLWAKEUP,
epoll::EPOLLEXCLUSIVE,
];
for &f in &flags {
assert!(f > 0, "epoll flag should be positive");
}
}
#[test]
fn test_networking_postcard_from_all_platforms() {
let linux = X86Networking::new_linux_x86_64();
let win = X86Networking::new_windows_x86_64();
let macos = X86Networking::new_macos_x86_64();
let fbsd = X86Networking::new_freebsd_x86_64();
let x86_32 = X86Networking::new_linux_x86_32();
assert!(linux.describe().len() > 0);
assert!(win.describe().len() > 0);
assert!(macos.describe().len() > 0);
assert!(fbsd.describe().len() > 0);
assert!(x86_32.describe().len() > 0);
}
#[test]
fn test_chunked_encoding_roundtrip() {
let test_data = vec![
(b"" as &[u8], 0usize),
(b"A", 1),
(b"Hello, World!", 13),
(&[0x41u8; 32768], 32768),
];
for (data, expected_len) in test_data {
let encoded = X86HTTPSupport::chunked_encode(data);
let decoded = X86HTTPSupport::chunked_decode(&encoded).unwrap();
assert_eq!(decoded.len(), expected_len);
assert_eq!(decoded, data);
}
}
#[test]
fn test_dns_roundtrip_query_response() {
let query = X86DNSResolver::build_query("roundtrip.example.com", X86DNSRecordType::A);
assert!(query.len() >= 12);
if let Some(msg) = X86DNSResolver::parse_response(&query) {
assert!(msg.flags.is_query());
assert_eq!(msg.questions.len(), 1);
}
}
#[test]
fn test_socket_option_error_type_acceptconn_peercred() {
for opt in [
X86SocketOption::Error,
X86SocketOption::Type,
X86SocketOption::AcceptConn,
X86SocketOption::PeerCred,
] {
let (lvl, _name) = opt.level_and_name();
assert_eq!(lvl, sol::SOL_SOCKET);
}
}
#[test]
fn test_url_scheme_case_insensitive() {
let url = X86URL::parse("HTTPS://Example.COM/path").unwrap();
assert_eq!(url.scheme, "https");
assert_eq!(url.host.unwrap(), "example.com"); }
#[test]
fn test_http_status_unknown_code() {
assert_eq!(X86HTTPResponse::reason_for_status(999), "Unknown");
}
#[test]
fn test_driver_compile_flags_all_platforms() {
for plat in [
X86NetPlatform::Linux,
X86NetPlatform::Windows,
X86NetPlatform::MacOS,
X86NetPlatform::FreeBSD,
] {
let driver = X86NetworkingDriver::new(plat);
let _ = driver.compile_flags();
}
}
#[test]
fn test_driver_linkage_flags_all_platforms() {
for plat in [
X86NetPlatform::Linux,
X86NetPlatform::Windows,
X86NetPlatform::MacOS,
X86NetPlatform::FreeBSD,
] {
let driver = X86NetworkingDriver::new(plat);
let _ = driver.linkage_flags();
}
}
}
#[derive(Debug, Clone)]
pub struct X86NetworkEvent {
pub fd: X86SocketFd,
pub event_type: X86NetworkEventType,
pub timestamp: u64,
pub data: Vec<u8>,
pub error: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86NetworkEventType {
Readable,
Writable,
Error,
HangUp,
ReadHangUp,
Timeout,
ConnectionReset,
}
impl X86NetworkEvent {
pub fn new_readable(fd: X86SocketFd, data: Vec<u8>) -> Self {
Self {
fd,
event_type: X86NetworkEventType::Readable,
timestamp: 0,
data,
error: None,
}
}
pub fn new_error(fd: X86SocketFd, msg: &str) -> Self {
Self {
fd,
event_type: X86NetworkEventType::Error,
timestamp: 0,
data: Vec::new(),
error: Some(msg.to_string()),
}
}
pub fn is_error(&self) -> bool {
matches!(self.event_type, X86NetworkEventType::Error)
}
}
#[derive(Debug, Clone)]
pub struct X86NetworkTimer {
pub id: u64,
pub duration: Duration,
pub repeating: bool,
pub callback_id: String,
pub remaining: Duration,
pub fired: bool,
}
impl X86NetworkTimer {
pub fn new_once(id: u64, duration: Duration) -> Self {
Self {
id,
duration,
repeating: false,
callback_id: String::new(),
remaining: duration,
fired: false,
}
}
pub fn new_repeating(id: u64, duration: Duration) -> Self {
Self {
id,
duration,
repeating: true,
callback_id: String::new(),
remaining: duration,
fired: false,
}
}
pub fn tick(&mut self, delta: Duration) -> bool {
if self.fired && !self.repeating {
return false;
}
self.remaining = self.remaining.saturating_sub(delta);
if self.remaining.is_zero() {
self.fired = true;
if self.repeating {
self.remaining = self.duration;
}
return true;
}
false
}
pub fn reset(&mut self) {
self.remaining = self.duration;
self.fired = false;
}
}
#[derive(Debug, Clone)]
pub struct X86NetworkBuffer {
pub data: Vec<u8>,
pub read_pos: usize,
pub write_pos: usize,
pub capacity: usize,
}
impl X86NetworkBuffer {
pub fn new(capacity: usize) -> Self {
Self {
data: vec![0u8; capacity],
read_pos: 0,
write_pos: 0,
capacity,
}
}
pub fn from_data(data: Vec<u8>) -> Self {
let len = data.len();
Self {
data,
read_pos: 0,
write_pos: len,
capacity: len,
}
}
pub fn readable(&self) -> usize {
self.write_pos.saturating_sub(self.read_pos)
}
pub fn writable(&self) -> usize {
self.capacity.saturating_sub(self.write_pos)
}
pub fn read(&mut self, buf: &mut [u8]) -> usize {
let n = buf.len().min(self.readable());
buf[..n].copy_from_slice(&self.data[self.read_pos..self.read_pos + n]);
self.read_pos += n;
if self.read_pos == self.write_pos {
self.read_pos = 0;
self.write_pos = 0;
}
n
}
pub fn write(&mut self, buf: &[u8]) -> usize {
let n = buf.len().min(self.writable());
self.data[self.write_pos..self.write_pos + n].copy_from_slice(&buf[..n]);
self.write_pos += n;
n
}
pub fn clear(&mut self) {
self.read_pos = 0;
self.write_pos = 0;
}
pub fn available_data(&self) -> &[u8] {
&self.data[self.read_pos..self.write_pos]
}
}
impl Default for X86NetworkBuffer {
fn default() -> Self {
Self::new(4096)
}
}
#[derive(Debug, Clone)]
pub struct X86NetworkConnection {
pub fd: X86SocketFd,
pub remote_addr: Option<X86SockAddrIn>,
pub local_addr: Option<X86SockAddrIn>,
pub read_buffer: X86NetworkBuffer,
pub write_buffer: X86NetworkBuffer,
pub tls_session_id: Option<u64>,
pub state: X86ConnectionState,
pub bytes_sent: u64,
pub bytes_received: u64,
pub created_at: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86ConnectionState {
Init,
Connecting,
Connected,
TLSHandshaking,
Closing,
Closed,
Error,
}
impl X86NetworkConnection {
pub fn new(fd: X86SocketFd) -> Self {
Self {
fd,
remote_addr: None,
local_addr: None,
read_buffer: X86NetworkBuffer::default(),
write_buffer: X86NetworkBuffer::default(),
tls_session_id: None,
state: X86ConnectionState::Init,
bytes_sent: 0,
bytes_received: 0,
created_at: 0,
}
}
pub fn is_active(&self) -> bool {
!matches!(
self.state,
X86ConnectionState::Closed | X86ConnectionState::Error
)
}
pub fn record_send(&mut self, bytes: usize) {
self.bytes_sent += bytes as u64;
}
pub fn record_recv(&mut self, bytes: usize) {
self.bytes_received += bytes as u64;
}
}
pub struct X86NetworkPipeline {
pub networking: X86Networking,
pub connections: HashMap<X86SocketFd, X86NetworkConnection>,
pub event_queue: Vec<X86NetworkEvent>,
pub timers: Vec<X86NetworkTimer>,
pub stats: X86NetworkingStats,
next_timer_id: u64,
}
impl X86NetworkPipeline {
pub fn new(platform: X86NetPlatform) -> Self {
let networking = match platform {
X86NetPlatform::Linux => X86Networking::new_linux_x86_64(),
X86NetPlatform::Windows => X86Networking::new_windows_x86_64(),
X86NetPlatform::MacOS => X86Networking::new_macos_x86_64(),
X86NetPlatform::FreeBSD => X86Networking::new_freebsd_x86_64(),
_ => X86Networking::default(),
};
Self {
networking,
connections: HashMap::new(),
event_queue: Vec::new(),
timers: Vec::new(),
stats: X86NetworkingStats::new(),
next_timer_id: 1,
}
}
pub fn add_connection(&mut self, conn: X86NetworkConnection) {
self.connections.insert(conn.fd, conn);
self.stats.record_socket_created();
}
pub fn remove_connection(&mut self, fd: X86SocketFd) -> Option<X86NetworkConnection> {
let conn = self.connections.remove(&fd);
if conn.is_some() {
self.stats.record_socket_closed();
}
conn
}
pub fn add_timer(&mut self, duration: Duration, repeating: bool) -> u64 {
let id = self.next_timer_id;
self.next_timer_id += 1;
let timer = if repeating {
X86NetworkTimer::new_repeating(id, duration)
} else {
X86NetworkTimer::new_once(id, duration)
};
self.timers.push(timer);
id
}
pub fn tick_timers(&mut self, delta: Duration) -> Vec<u64> {
let mut fired = Vec::new();
for timer in &mut self.timers {
if timer.tick(delta) {
fired.push(timer.id);
}
}
fired
}
pub fn connection_count(&self) -> usize {
self.connections.len()
}
pub fn active_connections(&self) -> usize {
self.connections.values().filter(|c| c.is_active()).count()
}
pub fn summary(&self) -> String {
format!(
"Pipeline[{}]: {} connections ({} active), {} events, {} timers — {}",
self.networking.platform.as_str(),
self.connection_count(),
self.active_connections(),
self.event_queue.len(),
self.timers.len(),
self.stats.summary(),
)
}
}
impl Default for X86NetworkPipeline {
fn default() -> Self {
Self::new(X86NetPlatform::Linux)
}
}
#[cfg(test)]
mod extended_tests {
use super::*;
#[test]
fn test_network_event_readable() {
let ev = X86NetworkEvent::new_readable(5, vec![1, 2, 3]);
assert_eq!(ev.fd, 5);
assert_eq!(ev.event_type, X86NetworkEventType::Readable);
assert!(!ev.is_error());
}
#[test]
fn test_network_event_error() {
let ev = X86NetworkEvent::new_error(5, "connection reset");
assert!(ev.is_error());
assert_eq!(ev.error.as_deref(), Some("connection reset"));
}
#[test]
fn test_network_timer_once() {
let mut timer = X86NetworkTimer::new_once(1, Duration::from_millis(100));
assert!(!timer.fired);
let fired = timer.tick(Duration::from_millis(100));
assert!(fired);
assert!(timer.fired);
let fired2 = timer.tick(Duration::from_millis(100));
assert!(!fired2);
}
#[test]
fn test_network_timer_repeating() {
let mut timer = X86NetworkTimer::new_repeating(1, Duration::from_millis(50));
assert!(timer.tick(Duration::from_millis(50)));
assert!(timer.fired);
assert!(timer.tick(Duration::from_millis(50)));
}
#[test]
fn test_network_timer_reset() {
let mut timer = X86NetworkTimer::new_once(1, Duration::from_millis(200));
timer.tick(Duration::from_millis(100));
timer.reset();
assert!(!timer.fired);
assert_eq!(timer.remaining, Duration::from_millis(200));
}
#[test]
fn test_network_buffer_basic() {
let mut buf = X86NetworkBuffer::new(1024);
assert_eq!(buf.readable(), 0);
assert_eq!(buf.writable(), 1024);
let n = buf.write(b"hello");
assert_eq!(n, 5);
assert_eq!(buf.readable(), 5);
let mut out = [0u8; 10];
let n = buf.read(&mut out);
assert_eq!(n, 5);
assert_eq!(&out[..5], b"hello");
assert_eq!(buf.readable(), 0);
}
#[test]
fn test_network_buffer_wrap() {
let mut buf = X86NetworkBuffer::new(16);
buf.write(b"0123456789ABCDEF"); assert_eq!(buf.writable(), 0);
let mut out = [0u8; 10];
buf.read(&mut out); assert_eq!(buf.readable(), 6);
assert!(buf.writable() > 0);
}
#[test]
fn test_network_buffer_from_data() {
let buf = X86NetworkBuffer::from_data(b"preloaded".to_vec());
assert_eq!(buf.readable(), 9);
assert_eq!(buf.available_data(), b"preloaded");
}
#[test]
fn test_network_buffer_clear() {
let mut buf = X86NetworkBuffer::new(64);
buf.write(b"data");
assert_eq!(buf.readable(), 4);
buf.clear();
assert_eq!(buf.readable(), 0);
}
#[test]
fn test_network_buffer_default() {
let buf = X86NetworkBuffer::default();
assert_eq!(buf.capacity, 4096);
}
#[test]
fn test_network_connection_lifecycle() {
let mut conn = X86NetworkConnection::new(3);
assert!(conn.is_active());
assert_eq!(conn.state, X86ConnectionState::Init);
conn.state = X86ConnectionState::Connected;
assert!(conn.is_active());
conn.record_send(1024);
conn.record_recv(512);
assert_eq!(conn.bytes_sent, 1024);
assert_eq!(conn.bytes_received, 512);
conn.state = X86ConnectionState::Closed;
assert!(!conn.is_active());
}
#[test]
fn test_network_pipeline_creation() {
let pipeline = X86NetworkPipeline::new(X86NetPlatform::Linux);
assert_eq!(pipeline.connection_count(), 0);
assert_eq!(pipeline.active_connections(), 0);
}
#[test]
fn test_network_pipeline_add_remove_connection() {
let mut pipeline = X86NetworkPipeline::new(X86NetPlatform::Linux);
let conn = X86NetworkConnection::new(5);
pipeline.add_connection(conn);
assert_eq!(pipeline.connection_count(), 1);
let removed = pipeline.remove_connection(5);
assert!(removed.is_some());
assert_eq!(pipeline.connection_count(), 0);
}
#[test]
fn test_network_pipeline_timers() {
let mut pipeline = X86NetworkPipeline::new(X86NetPlatform::Linux);
let id = pipeline.add_timer(Duration::from_millis(100), false);
assert_eq!(id, 1);
let id2 = pipeline.add_timer(Duration::from_secs(1), true);
assert_eq!(id2, 2);
let fired = pipeline.tick_timers(Duration::from_millis(200));
assert!(fired.contains(&1));
}
#[test]
fn test_network_pipeline_default() {
let pipeline: X86NetworkPipeline = Default::default();
assert_eq!(pipeline.networking.platform, X86NetPlatform::Linux);
}
#[test]
fn test_network_pipeline_summary() {
let pipeline = X86NetworkPipeline::new(X86NetPlatform::Linux);
let summary = pipeline.summary();
assert!(summary.contains("Pipeline"));
}
#[test]
fn test_connection_state_enum() {
let states = [
X86ConnectionState::Init,
X86ConnectionState::Connecting,
X86ConnectionState::Connected,
X86ConnectionState::TLSHandshaking,
X86ConnectionState::Closing,
X86ConnectionState::Closed,
X86ConnectionState::Error,
];
for s in &states {
let _ = format!("{:?}", s);
}
}
#[test]
fn test_network_event_type_enum() {
let types = [
X86NetworkEventType::Readable,
X86NetworkEventType::Writable,
X86NetworkEventType::Error,
X86NetworkEventType::HangUp,
X86NetworkEventType::ReadHangUp,
X86NetworkEventType::Timeout,
X86NetworkEventType::ConnectionReset,
];
for t in &types {
let _ = format!("{:?}", t);
}
}
}
#[derive(Debug, Clone)]
pub struct X86ServiceRecord {
pub name: String,
pub service_type: String,
pub domain: String,
pub host: String,
pub port: u16,
pub txt_records: Vec<String>,
pub ttl: u32,
}
impl X86ServiceRecord {
pub fn new(name: &str, service_type: &str, host: &str, port: u16) -> Self {
Self {
name: name.to_string(),
service_type: service_type.to_string(),
domain: "local".to_string(),
host: host.to_string(),
port,
txt_records: Vec::new(),
ttl: 120,
}
}
pub fn with_txt(mut self, txt: Vec<String>) -> Self {
self.txt_records = txt;
self
}
pub fn service_name(&self) -> String {
format!("{}.{}.{}", self.name, self.service_type, self.domain)
}
}
pub mod socks5_auth {
pub const NO_AUTH: u8 = 0x00;
pub const GSSAPI: u8 = 0x01;
pub const USERNAME_PASSWORD: u8 = 0x02;
pub const NO_ACCEPTABLE: u8 = 0xFF;
}
pub mod socks5_cmd {
pub const CONNECT: u8 = 0x01;
pub const BIND: u8 = 0x02;
pub const UDP_ASSOCIATE: u8 = 0x03;
}
pub mod socks5_atyp {
pub const IPV4: u8 = 0x01;
pub const DOMAINNAME: u8 = 0x03;
pub const IPV6: u8 = 0x04;
}
pub mod socks5_rep {
pub const SUCCEEDED: u8 = 0x00;
pub const GENERAL_FAILURE: u8 = 0x01;
pub const CONNECTION_NOT_ALLOWED: u8 = 0x02;
pub const NETWORK_UNREACHABLE: u8 = 0x03;
pub const HOST_UNREACHABLE: u8 = 0x04;
pub const CONNECTION_REFUSED: u8 = 0x05;
pub const TTL_EXPIRED: u8 = 0x06;
pub const COMMAND_NOT_SUPPORTED: u8 = 0x07;
pub const ADDRESS_TYPE_NOT_SUPPORTED: u8 = 0x08;
}
#[derive(Debug, Clone, Default)]
pub struct X86NetworkPerformance {
pub rtt_min_ms: f64,
pub rtt_avg_ms: f64,
pub rtt_max_ms: f64,
pub throughput_bytes_per_sec: f64,
pub packet_loss_pct: f64,
pub jitter_ms: f64,
pub samples: u64,
}
impl X86NetworkPerformance {
pub fn new() -> Self {
Self {
rtt_min_ms: f64::MAX,
rtt_avg_ms: 0.0,
rtt_max_ms: 0.0,
throughput_bytes_per_sec: 0.0,
packet_loss_pct: 0.0,
jitter_ms: 0.0,
samples: 0,
}
}
pub fn record_rtt(&mut self, rtt_ms: f64) {
if rtt_ms < self.rtt_min_ms {
self.rtt_min_ms = rtt_ms;
}
if rtt_ms > self.rtt_max_ms {
self.rtt_max_ms = rtt_ms;
}
self.samples += 1;
self.rtt_avg_ms =
(self.rtt_avg_ms * (self.samples - 1) as f64 + rtt_ms) / self.samples as f64;
}
pub fn summarize(&self) -> String {
format!(
"RTT: min={:.2}ms avg={:.2}ms max={:.2}ms, throughput={:.2} B/s, loss={:.2}%, jitter={:.2}ms ({} samples)",
self.rtt_min_ms,
self.rtt_avg_ms,
self.rtt_max_ms,
self.throughput_bytes_per_sec,
self.packet_loss_pct,
self.jitter_ms,
self.samples,
)
}
}
#[cfg(test)]
mod final_tests {
use super::*;
#[test]
fn test_service_record_creation() {
let svc = X86ServiceRecord::new("MyPrinter", "_ipp._tcp", "printer.local", 631);
assert_eq!(svc.name, "MyPrinter");
assert_eq!(svc.port, 631);
assert_eq!(svc.service_name(), "MyPrinter._ipp._tcp.local");
}
#[test]
fn test_service_record_with_txt() {
let svc = X86ServiceRecord::new("Web", "_http._tcp", "web.local", 80)
.with_txt(vec!["path=/".to_string(), "version=1".to_string()]);
assert_eq!(svc.txt_records.len(), 2);
}
#[test]
fn test_socks5_constants() {
assert_eq!(socks5_auth::NO_AUTH, 0x00);
assert_eq!(socks5_auth::USERNAME_PASSWORD, 0x02);
assert_eq!(socks5_cmd::CONNECT, 0x01);
assert_eq!(socks5_cmd::UDP_ASSOCIATE, 0x03);
assert_eq!(socks5_atyp::IPV4, 0x01);
assert_eq!(socks5_atyp::DOMAINNAME, 0x03);
assert_eq!(socks5_rep::SUCCEEDED, 0x00);
assert_eq!(socks5_rep::CONNECTION_REFUSED, 0x05);
}
#[test]
fn test_network_performance_new() {
let perf = X86NetworkPerformance::new();
assert_eq!(perf.samples, 0);
assert_eq!(perf.rtt_min_ms, f64::MAX);
}
#[test]
fn test_network_performance_record_rtt() {
let mut perf = X86NetworkPerformance::new();
perf.record_rtt(10.0);
perf.record_rtt(20.0);
perf.record_rtt(5.0);
assert_eq!(perf.samples, 3);
assert_eq!(perf.rtt_min_ms, 5.0);
assert_eq!(perf.rtt_max_ms, 20.0);
assert!((perf.rtt_avg_ms - 11.666).abs() < 1.0);
}
#[test]
fn test_network_performance_summary() {
let mut perf = X86NetworkPerformance::new();
perf.record_rtt(15.0);
let summary = perf.summarize();
assert!(summary.contains("RTT"));
assert!(summary.contains("15"));
}
#[test]
fn test_network_performance_default() {
let perf: X86NetworkPerformance = Default::default();
assert_eq!(perf.samples, 0);
}
#[test]
fn test_full_system_integration() {
let net = X86Networking::new_linux_x86_64();
let mut pipeline = X86NetworkPipeline::new(net.platform);
let conn = X86NetworkConnection::new(10);
pipeline.add_connection(conn);
assert_eq!(pipeline.connection_count(), 1);
let mut resolver = net.dns_resolver.clone();
let records = resolver.resolve("integ.example.com", X86DNSRecordType::A);
assert!(!records.is_empty());
let mut api = net.socket_api.clone();
let fd = api.socket(
X86AddressFamily::IPv4,
X86SocketType::Stream,
X86SocketProtocol::TCP,
);
assert!(api.is_socket(fd));
let sin = X86SockAddrIn::new(X86InAddr::from_octets(127, 0, 0, 1), 8080);
api.bind(fd, &sin).unwrap();
api.close(fd).unwrap();
}
}