Skip to content

Commit 647d0b4

Browse files
committed
catch + resume unwinds out of the handler function
1 parent fd39fe1 commit 647d0b4

File tree

2 files changed

+26
-8
lines changed

2 files changed

+26
-8
lines changed

src/lib.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
//! ```
6060
6161
use bitflags::bitflags;
62+
use std::any::Any;
6263
use std::borrow::Borrow;
6364
use std::convert::TryFrom;
6465
use std::ffi::{self, CStr, CString};
@@ -69,6 +70,7 @@ use std::net::IpAddr;
6970
use std::ops::Deref;
7071
#[cfg(not(windows))]
7172
use std::os::unix::io::{AsRawFd, RawFd};
73+
use std::panic::{catch_unwind, resume_unwind, RefUnwindSafe};
7274
use std::path::Path;
7375
use std::ptr::{self, NonNull};
7476
use std::slice;
@@ -841,11 +843,13 @@ impl<T: State + ?Sized> From<NonNull<raw::pcap_t>> for Capture<T> {
841843
// pointer and the right data pointer to pcap_loop.
842844
struct Handler<F> {
843845
func: F,
846+
panic_payload: Option<Box<dyn Any + Send>>,
847+
handle: NonNull<raw::pcap_t>,
844848
}
845849

846850
impl<F> Handler<F>
847851
where
848-
F: FnMut(Packet),
852+
F: FnMut(Packet) + RefUnwindSafe,
849853
{
850854
extern "C" fn callback(
851855
slf: *mut libc::c_uchar,
@@ -859,25 +863,39 @@ where
859863
);
860864

861865
let slf = slf as *mut Self;
862-
((*slf).func)(packet)
866+
let func = std::ptr::addr_of_mut!((*slf).func);
867+
// If our handler function panics, we need to prevent it from unwinding across the
868+
// FFI boundary. If the handler panics we catch the unwind here, break out of
869+
// pcap_loop, and resume the unwind outside.
870+
if let Err(e) = catch_unwind(|| (*func)(packet)) {
871+
(*slf).panic_payload = Some(e);
872+
raw::pcap_breakloop((*slf).handle.as_ptr());
873+
}
863874
}
864875
}
865876
}
866877

867878
impl<T: State + ?Sized> Capture<T> {
868-
pub fn pcap_loop<F>(&mut self, handler: F)
879+
pub fn for_each<F>(&mut self, handler: F)
869880
where
870-
F: FnMut(Packet),
881+
F: FnMut(Packet) + RefUnwindSafe,
871882
{
872-
let mut handler = Handler { func: handler };
883+
let mut handler = Handler {
884+
func: handler,
885+
panic_payload: None,
886+
handle: self.handle,
887+
};
873888
unsafe {
874889
raw::pcap_loop(
875890
self.handle.as_ptr(),
876-
0,
891+
-1,
877892
Handler::<F>::callback,
878893
ptr::addr_of_mut!(handler).cast(),
879894
)
880895
};
896+
if let Some(e) = handler.panic_payload {
897+
resume_unwind(e);
898+
}
881899
}
882900

883901
fn new_raw<F>(path: Option<&str>, func: F) -> Result<Capture<T>, Error>

src/raw.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ pub struct pcap_send_queue {
101101

102102
// This is not Option<fn>, pcap functions do not check if the handler is null.
103103
pub type pcap_handler =
104-
extern "C" fn(arg1: *mut c_uchar, arg2: *const pcap_pkthdr, arg3: *const c_uchar) -> ();
104+
extern "C" fn(user: *mut c_uchar, h: *const pcap_pkthdr, bytes: *const c_uchar) -> ();
105105

106106
extern "C" {
107107
// [OBSOLETE] pub fn pcap_lookupdev(arg1: *mut c_char) -> *mut c_char;
@@ -134,7 +134,7 @@ extern "C" {
134134
arg2: *mut *mut pcap_pkthdr,
135135
arg3: *mut *const c_uchar,
136136
) -> c_int;
137-
// pub fn pcap_breakloop(arg1: *mut pcap_t);
137+
pub fn pcap_breakloop(arg1: *mut pcap_t);
138138
pub fn pcap_stats(arg1: *mut pcap_t, arg2: *mut pcap_stat) -> c_int;
139139
pub fn pcap_setfilter(arg1: *mut pcap_t, arg2: *mut bpf_program) -> c_int;
140140
pub fn pcap_setdirection(arg1: *mut pcap_t, arg2: pcap_direction_t) -> c_int;

0 commit comments

Comments
 (0)