59
59
//! ```
60
60
61
61
use bitflags:: bitflags;
62
+ use std:: any:: Any ;
62
63
use std:: borrow:: Borrow ;
63
64
use std:: convert:: TryFrom ;
64
65
use std:: ffi:: { self , CStr , CString } ;
@@ -69,6 +70,7 @@ use std::net::IpAddr;
69
70
use std:: ops:: Deref ;
70
71
#[ cfg( not( windows) ) ]
71
72
use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
73
+ use std:: panic:: { catch_unwind, resume_unwind, RefUnwindSafe } ;
72
74
use std:: path:: Path ;
73
75
use std:: ptr:: { self , NonNull } ;
74
76
use std:: slice;
@@ -841,11 +843,13 @@ impl<T: State + ?Sized> From<NonNull<raw::pcap_t>> for Capture<T> {
841
843
// pointer and the right data pointer to pcap_loop.
842
844
struct Handler < F > {
843
845
func : F ,
846
+ panic_payload : Option < Box < dyn Any + Send > > ,
847
+ handle : NonNull < raw:: pcap_t > ,
844
848
}
845
849
846
850
impl < F > Handler < F >
847
851
where
848
- F : FnMut ( Packet ) ,
852
+ F : FnMut ( Packet ) + RefUnwindSafe ,
849
853
{
850
854
extern "C" fn callback (
851
855
slf : * mut libc:: c_uchar ,
@@ -859,25 +863,39 @@ where
859
863
) ;
860
864
861
865
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
+ }
863
874
}
864
875
}
865
876
}
866
877
867
878
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 )
869
880
where
870
- F : FnMut ( Packet ) ,
881
+ F : FnMut ( Packet ) + RefUnwindSafe ,
871
882
{
872
- let mut handler = Handler { func : handler } ;
883
+ let mut handler = Handler {
884
+ func : handler,
885
+ panic_payload : None ,
886
+ handle : self . handle ,
887
+ } ;
873
888
unsafe {
874
889
raw:: pcap_loop (
875
890
self . handle . as_ptr ( ) ,
876
- 0 ,
891
+ - 1 ,
877
892
Handler :: < F > :: callback,
878
893
ptr:: addr_of_mut!( handler) . cast ( ) ,
879
894
)
880
895
} ;
896
+ if let Some ( e) = handler. panic_payload {
897
+ resume_unwind ( e) ;
898
+ }
881
899
}
882
900
883
901
fn new_raw < F > ( path : Option < & str > , func : F ) -> Result < Capture < T > , Error >
0 commit comments