5959//! ```
6060
6161use bitflags:: bitflags;
62+ use std:: any:: Any ;
6263use std:: borrow:: Borrow ;
6364use std:: convert:: TryFrom ;
6465use std:: ffi:: { self , CStr , CString } ;
@@ -69,6 +70,7 @@ use std::net::IpAddr;
6970use std:: ops:: Deref ;
7071#[ cfg( not( windows) ) ]
7172use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
73+ use std:: panic:: { catch_unwind, resume_unwind, RefUnwindSafe } ;
7274use std:: path:: Path ;
7375use std:: ptr:: { self , NonNull } ;
7476use 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.
842844struct Handler < F > {
843845 func : F ,
846+ panic_payload : Option < Box < dyn Any + Send > > ,
847+ handle : NonNull < raw:: pcap_t > ,
844848}
845849
846850impl < F > Handler < F >
847851where
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
867878impl < 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 >
0 commit comments