pub mod activated;
pub mod inactive;
#[cfg(all(not(windows), feature = "capture-stream"))]
#[cfg_attr(docsrs, doc(cfg(all(not(windows), feature = "capture-stream"))))]
pub mod selectable;
use std::{
ffi::CString,
marker::PhantomData,
ptr::{self, NonNull},
sync::Arc,
};
#[cfg(windows)]
use windows_sys::Win32::Foundation::HANDLE;
use crate::{raw, Error};
pub enum Inactive {}
pub enum Active {}
pub enum Offline {}
pub enum Dead {}
pub trait Activated: State {}
impl Activated for Active {}
impl Activated for Offline {}
impl Activated for Dead {}
pub trait State {}
impl State for Inactive {}
impl State for Active {}
impl State for Offline {}
impl State for Dead {}
pub struct Capture<T: State + ?Sized> {
nonblock: bool,
handle: Arc<PcapHandle>,
_marker: PhantomData<T>,
}
struct PcapHandle {
handle: NonNull<raw::pcap_t>,
}
impl PcapHandle {
fn as_ptr(&self) -> *mut raw::pcap_t {
self.handle.as_ptr()
}
}
unsafe impl Send for PcapHandle {}
impl Drop for PcapHandle {
fn drop(&mut self) {
unsafe { raw::pcap_close(self.handle.as_ptr()) }
}
}
unsafe impl<T: State + ?Sized> Send for Capture<T> {}
#[allow(clippy::arc_with_non_send_sync)]
impl<T: State + ?Sized> From<NonNull<raw::pcap_t>> for Capture<T> {
fn from(handle: NonNull<raw::pcap_t>) -> Self {
Capture {
nonblock: false,
handle: Arc::new(PcapHandle { handle }),
_marker: PhantomData,
}
}
}
impl<T: State + ?Sized> Capture<T> {
fn new_raw<F>(path: Option<&str>, func: F) -> Result<Capture<T>, Error>
where
F: FnOnce(*const libc::c_char, *mut libc::c_char) -> *mut raw::pcap_t,
{
Error::with_errbuf(|err| {
let handle = match path {
None => func(ptr::null(), err),
Some(path) => {
let path = CString::new(path)?;
func(path.as_ptr(), err)
}
};
Ok(Capture::from(
NonNull::<raw::pcap_t>::new(handle).ok_or_else(|| unsafe { Error::new(err) })?,
))
})
}
pub fn is_nonblock(&self) -> bool {
self.nonblock
}
pub fn as_ptr(&self) -> *mut raw::pcap_t {
self.handle.as_ptr()
}
#[cfg(windows)]
pub fn min_to_copy(self, to: i32) -> Capture<T> {
unsafe {
raw::pcap_setmintocopy(self.handle.as_ptr(), to as _);
}
self
}
#[cfg(windows)]
pub unsafe fn get_event(&self) -> HANDLE {
raw::pcap_getevent(self.handle.as_ptr())
}
fn check_err(&self, success: bool) -> Result<(), Error> {
if success {
Ok(())
} else {
Err(self.get_err())
}
}
fn get_err(&self) -> Error {
unsafe { Error::new(raw::pcap_geterr(self.handle.as_ptr())) }
}
}
#[repr(u32)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Precision {
Micro = 0,
Nano = 1,
}
#[cfg(test)]
pub mod testmod {
use raw::testmod::RAWMTX;
use super::*;
pub struct TestCapture<T: State + ?Sized> {
pub capture: Capture<T>,
_close_ctx: raw::__pcap_close::Context,
}
pub fn test_capture<T: State + ?Sized>(pcap: *mut raw::pcap_t) -> TestCapture<T> {
assert!(RAWMTX.try_lock().is_err());
let ctx = raw::pcap_close_context();
ctx.checkpoint();
ctx.expect()
.withf_st(move |ptr| *ptr == pcap)
.return_once(|_| {});
TestCapture {
capture: Capture::<T>::from(NonNull::new(pcap).unwrap()),
_close_ctx: ctx,
}
}
}
#[cfg(test)]
mod tests {
use crate::{
capture::testmod::test_capture,
raw::testmod::{as_pcap_t, RAWMTX},
};
use super::*;
#[test]
fn test_capture_getters() {
let _m = RAWMTX.lock();
let mut dummy: isize = 777;
let pcap = as_pcap_t(&mut dummy);
let test_capture = test_capture::<Active>(pcap);
let capture = test_capture.capture;
assert!(!capture.is_nonblock());
assert_eq!(capture.as_ptr(), capture.handle.as_ptr());
}
#[test]
#[cfg(windows)]
fn test_min_to_copy() {
let _m = RAWMTX.lock();
let mut dummy: isize = 777;
let pcap = as_pcap_t(&mut dummy);
let test_capture = test_capture::<Active>(pcap);
let capture = test_capture.capture;
let ctx = raw::pcap_setmintocopy_context();
ctx.expect()
.withf_st(move |arg1, _| *arg1 == pcap)
.return_once(|_, _| 0);
let _capture = capture.min_to_copy(5);
}
#[test]
#[cfg(windows)]
fn test_get_event() {
let _m = RAWMTX.lock();
let mut dummy: isize = 777;
let pcap = as_pcap_t(&mut dummy);
let test_capture = test_capture::<Active>(pcap);
let capture = test_capture.capture;
let ctx = raw::pcap_getevent_context();
ctx.expect()
.withf_st(move |arg1| *arg1 == pcap)
.return_once(|_| 5);
let handle = unsafe { capture.get_event() };
assert_eq!(handle, 5);
}
#[test]
fn test_precision() {
assert_ne!(Precision::Micro, Precision::Nano);
}
}