@@ -4,8 +4,10 @@ pub mod iterator;
44pub mod offline;
55
66use std:: {
7+ any:: Any ,
78 ffi:: CString ,
89 fmt, mem,
10+ panic:: { catch_unwind, resume_unwind, AssertUnwindSafe } ,
911 path:: Path ,
1012 ptr:: { self , NonNull } ,
1113 slice,
@@ -199,6 +201,28 @@ impl<T: Activated + ?Sized> Capture<T> {
199201 PacketIter :: new ( self , codec)
200202 }
201203
204+ pub fn for_each < F > ( & mut self , handler : F )
205+ where
206+ F : FnMut ( Packet ) ,
207+ {
208+ let mut handler = Handler {
209+ func : AssertUnwindSafe ( handler) ,
210+ panic_payload : None ,
211+ handle : self . handle ,
212+ } ;
213+ unsafe {
214+ raw:: pcap_loop (
215+ self . handle . as_ptr ( ) ,
216+ -1 ,
217+ Handler :: < F > :: callback,
218+ & mut handler as * mut Handler < AssertUnwindSafe < F > > as * mut u8 ,
219+ )
220+ } ;
221+ if let Some ( e) = handler. panic_payload {
222+ resume_unwind ( e) ;
223+ }
224+ }
225+
202226 /// Compiles the string into a filter program using `pcap_compile`.
203227 pub fn compile ( & self , program : & str , optimize : bool ) -> Result < BpfProgram , Error > {
204228 let program = CString :: new ( program) ?;
@@ -241,6 +265,45 @@ impl<T: Activated + ?Sized> Capture<T> {
241265 }
242266}
243267
268+ // Handler and its associated function let us create an extern "C" fn which dispatches to a normal
269+ // Rust FnMut, which may be a closure with a captured environment. The *only* purpose of this
270+ // generic parameter is to ensure that in Capture::pcap_loop that we pass the right function
271+ // pointer and the right data pointer to pcap_loop.
272+ struct Handler < F > {
273+ func : F ,
274+ panic_payload : Option < Box < dyn Any + Send > > ,
275+ handle : NonNull < raw:: pcap_t > ,
276+ }
277+
278+ impl < F > Handler < F >
279+ where
280+ F : FnMut ( Packet ) ,
281+ {
282+ extern "C" fn callback (
283+ slf : * mut libc:: c_uchar ,
284+ header : * const raw:: pcap_pkthdr ,
285+ packet : * const libc:: c_uchar ,
286+ ) {
287+ unsafe {
288+ let packet = Packet :: new (
289+ & * ( header as * const PacketHeader ) ,
290+ slice:: from_raw_parts ( packet, ( * header) . caplen as _ ) ,
291+ ) ;
292+
293+ let slf = slf as * mut Self ;
294+ let func = & mut ( * slf) . func ;
295+ let mut func = AssertUnwindSafe ( func) ;
296+ // If our handler function panics, we need to prevent it from unwinding across the
297+ // FFI boundary. If the handler panics we catch the unwind here, break out of
298+ // pcap_loop, and resume the unwind outside.
299+ if let Err ( e) = catch_unwind ( move || func ( packet) ) {
300+ ( * slf) . panic_payload = Some ( e) ;
301+ raw:: pcap_breakloop ( ( * slf) . handle . as_ptr ( ) ) ;
302+ }
303+ }
304+ }
305+ }
306+
244307impl < T : Activated > From < Capture < T > > for Capture < dyn Activated > {
245308 fn from ( cap : Capture < T > ) -> Capture < dyn Activated > {
246309 unsafe { mem:: transmute ( cap) }
0 commit comments