diff --git a/Cargo.lock b/Cargo.lock index 3847f74..d443aad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -305,8 +305,10 @@ dependencies = [ [[package]] name = "nix" version = "0.25.0" -source = "git+https://github.com/Lochnair/nix?branch=add-icmp_proto#19e59985cdca5ded0eac9ad30bcc8ff39219c097" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" dependencies = [ + "autocfg", "bitflags", "cfg-if", "libc", @@ -459,6 +461,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "sqm-autorate-rust" version = "0.1.0" @@ -473,6 +485,7 @@ dependencies = [ "rand", "rust-uci", "serde", + "socket2", "thiserror", "time", ] diff --git a/Cargo.toml b/Cargo.toml index 97f782f..522546a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ etherparse = "0.12.0" neli = "0.6.2" rand = "0.8.5" rust-uci = { version = "0.1.5", optional = true } +socket2 = { version = "0.4", features = ["all"] } thiserror = "1.0.37" [dependencies.log] @@ -33,7 +34,7 @@ features = ["std"] version = "0.4.17" [dependencies.nix] -features = ["net", "socket", "time"] +features = ["time"] version = "0.25.0" [dependencies.serde] @@ -45,7 +46,4 @@ features = ["formatting", "macros"] version = "0.3.15" [features] -uci = ["dep:rust-uci"] - -[patch.crates-io] -nix = { git = "https://github.com/Lochnair/nix", branch = "add-icmp_proto" } +uci = ["dep:rust-uci"] \ No newline at end of file diff --git a/src/pinger.rs b/src/pinger.rs index ef895e3..12e312e 100644 --- a/src/pinger.rs +++ b/src/pinger.rs @@ -2,12 +2,8 @@ use crate::MeasurementType; use etherparse::ReadError; use log::{debug, error}; use nix::errno::Errno; -use nix::sys::socket::{ - recvfrom, sendto, socket, AddressFamily, MsgFlags, SockFlag, SockProtocol, SockType, - SockaddrIn, SockaddrIn6, SockaddrLike, -}; +use socket2::{Domain, Protocol, SockAddr, Socket, Type}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6}; -use std::os::unix::io::RawFd; use std::str::FromStr; use std::sync::mpsc::Sender; use std::sync::{Arc, RwLock}; @@ -47,30 +43,34 @@ pub struct PingReply { pub last_receive_time_s: f64, } -fn open_socket(type_: MeasurementType) -> nix::Result { +fn open_socket(type_: MeasurementType) -> std::io::Result { match type_ { MeasurementType::ICMP | MeasurementType::ICMPTimestamps => { - socket( - AddressFamily::Inet, - SockType::Raw, - SockFlag::empty(), /* value */ - SockProtocol::ICMP, - ) - } - MeasurementType::NTP => { - socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), /* value */ - SockProtocol::Udp, - ) + Socket::new(Domain::IPV4, Type::RAW, Some(Protocol::ICMPV4)) } + MeasurementType::NTP => Socket::new(Domain::IPV4, Type::DGRAM, None), _ => { unimplemented!() } } } +trait ReadFrom { + fn read_from(&mut self) -> io::Result<(Vec, SockAddr)>; +} + +impl ReadFrom for Socket { + fn read_from(&mut self) -> io::Result<(Vec, SockAddr)> { + let mut buffer = Vec::with_capacity(4096); + let (received, addr) = self.recv_from(buffer.spare_capacity_mut())?; + + unsafe { + buffer.set_len(received); + } + Ok((buffer, addr)) + } +} + pub trait PingListener { fn listen( &mut self, @@ -79,30 +79,26 @@ pub trait PingListener { reflectors_lock: Arc>>, stats_sender: Sender, ) -> anyhow::Result<()> { - let socket = open_socket(type_)?; + let socket = &mut open_socket(type_)?; loop { - let mut v: Vec = vec![0; 40]; - let mut buf = v.as_mut_slice(); - - let (size, sender) = match recvfrom::(socket, buf) { + let (buf, sender) = match socket.read_from() { Ok(val) => val, Err(_) => continue, }; // etherparse doesn't like when the size in the header doesn't match the buffer // so resize the buffer when actual packet size is known - buf = buf[..size].as_mut(); + //buf = buf[..size].as_mut(); - let addr_bytes = sender.expect("Should be an address here").ip(); - let addr = IpAddr::from(addr_bytes.to_be_bytes()); + let addr: IpAddr = sender.as_socket().unwrap().ip(); let reflectors = reflectors_lock.read().unwrap(); if !reflectors.contains(&addr) { continue; } - let reply = match self.parse_packet(id, addr, buf) { + let reply = match self.parse_packet(id, addr, buf.as_slice()) { Ok(val) => val, Err(_) => { // parse_packet will throw an error if it's an unknown protocol etc. @@ -126,7 +122,7 @@ pub trait PingSender { type_: MeasurementType, reflectors_lock: Arc>>, ) -> anyhow::Result<()> { - let socket = open_socket(type_)?; + let socket = &open_socket(type_)?; let mut seq: u16 = 0; let tick_duration_ms: u16 = 500; @@ -138,25 +134,25 @@ pub trait PingSender { drop(reflectors_unlocked); for reflector in reflectors.iter() { - let addr: Box; + let addr: SockAddr; match reflector.is_ipv4() { true => { let ip4 = Ipv4Addr::from_str(&*reflector.to_string()).unwrap(); let sock4 = SocketAddrV4::new(ip4, 0); - addr = Box::new(SockaddrIn::from(sock4)); + addr = sock4.into(); } false => { let ip6 = Ipv6Addr::from_str(&*reflector.to_string()).unwrap(); let sock6 = SocketAddrV6::new(ip6, 0, 0, 0); - addr = Box::new(SockaddrIn6::from(sock6)); + addr = sock6.into(); } } let buf_v = self.craft_packet(id, seq); let buf = buf_v.as_slice(); - sendto(socket, buf, addr.as_ref(), MsgFlags::empty()).expect("Couldn't send ping"); + socket.send_to(buf, &addr)?; } thread::sleep(sleep_duration);