use std::io;
use std::mem::ManuallyDrop;
#[cfg(not(target_os = "windows"))]
use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd};
use crate::filter::PacketFilter;
use crate::{Interface, Sniffer};
use mio::event::Source;
use mio::net::UdpSocket;
use mio::{Interest, Registry, Token};
pub struct AsyncSniffer {
sniffer: Sniffer,
io: ManuallyDrop<UdpSocket>,
}
impl AsyncSniffer {
#[inline]
pub fn new(iface: Interface) -> io::Result<Self> {
let sniffer = Sniffer::new(iface)?;
sniffer.set_nonblocking(true)?;
let io = unsafe { UdpSocket::from_raw_fd(sniffer.as_raw_fd()) };
Ok(Self {
sniffer,
io: ManuallyDrop::new(io),
})
}
#[inline]
pub fn activate(&mut self, filter: Option<PacketFilter>) -> io::Result<()> {
self.sniffer.activate(filter)
}
pub fn deactivate(&mut self) -> io::Result<()> {
self.sniffer.deactivate()
}
#[inline]
pub fn nonblocking(&self) -> io::Result<bool> {
self.sniffer.nonblocking()
}
#[inline]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.sniffer.set_nonblocking(nonblocking)
}
#[inline]
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
self.sniffer.send(buf)
}
#[inline]
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
self.sniffer.recv(buf)
}
}
impl Source for AsyncSniffer {
fn register(
&mut self,
registry: &Registry,
token: Token,
interests: Interest,
) -> io::Result<()> {
self.io.register(registry, token, interests)
}
fn reregister(
&mut self,
registry: &Registry,
token: Token,
interests: Interest,
) -> io::Result<()> {
self.io.reregister(registry, token, interests)
}
fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
self.io.deregister(registry)
}
}
impl Drop for AsyncSniffer {
fn drop(&mut self) {
let io = unsafe { ManuallyDrop::take(&mut self.io) };
let _ = io.into_raw_fd();
}
}