@@ -12,6 +12,7 @@ use std::{
1212 path:: Path ,
1313 ptr:: { self , NonNull } ,
1414 slice,
15+ sync:: { Arc , RwLock } ,
1516} ;
1617
1718#[ cfg( not( windows) ) ]
@@ -235,6 +236,39 @@ impl<T: Activated + ?Sized> Capture<T> {
235236 self . check_err ( return_code == 0 )
236237 }
237238
239+ /// Returns a thread-safe `BreakLoop` handle for calling pcap_breakloop() on an active capture.
240+ ///
241+ /// # Example
242+ ///
243+ /// ```no_run
244+ /// // Using an active capture
245+ /// use pcap::Device;
246+ ///
247+ /// let mut cap = Device::lookup().unwrap().unwrap().open().unwrap();
248+ ///
249+ /// let break_handle = cap.breakloop_handle();
250+ ///
251+ /// let capture_thread = std::thread::spawn(move || {
252+ /// while let Ok(packet) = cap.next_packet() {
253+ /// println!("received packet! {:?}", packet);
254+ /// }
255+ /// });
256+ ///
257+ /// // Send break_handle to a seperate thread (i.e. could be signal handler)
258+ /// std::thread::spawn(move || {
259+ /// std::thread::sleep(std::time::Duration::from_secs(1));
260+ /// break_handle.breakloop();
261+ /// });
262+ ///
263+ /// capture_thread.join().unwrap();
264+ /// ```
265+ pub fn breakloop_handle ( & mut self ) -> BreakLoop {
266+ BreakLoop {
267+ handle : self . handle ,
268+ handle_valid : Arc :: clone ( & self . handle_valid ) ,
269+ }
270+ }
271+
238272 /// Compiles the string into a filter program using `pcap_compile`.
239273 pub fn compile ( & self , program : & str , optimize : bool ) -> Result < BpfProgram , Error > {
240274 let program = CString :: new ( program) ?;
@@ -321,6 +355,39 @@ impl<T: Activated> From<Capture<T>> for Capture<dyn Activated> {
321355 unsafe { mem:: transmute ( cap) }
322356 }
323357}
358+ /// Breakloop can safely be sent to other threads such as signal handlers to abort
359+ /// blocking capture loops such as `Capture::next_packet` and `Capture::for_each`.
360+ ///
361+ /// See <https://www.tcpdump.org/manpages/pcap_breakloop.3pcap.html> for per-platform caveats about
362+ /// how breakloop can wake up blocked threads.
363+ pub struct BreakLoop {
364+ handle : NonNull < raw:: pcap_t > ,
365+ handle_valid : Arc < RwLock < bool > > ,
366+ }
367+
368+ // The `handle_valid` ensures that a valid handle is always referenced
369+ unsafe impl Send for BreakLoop { }
370+ // `pcap_breakloop()` is thread-safe
371+ unsafe impl Sync for BreakLoop { }
372+
373+ impl BreakLoop {
374+ /// Calls `pcap_breakloop` to make the blocking loop of a pcap capture return.
375+ /// The call is a no-op if the handle is invalid.
376+ pub fn breakloop ( & self ) {
377+ if let Ok ( handle_valid) = self . handle_valid . try_read ( ) {
378+ if * handle_valid {
379+ //
380+ // # Safety
381+ //
382+ // `handle_valid` is true, so the handle is valid before `pcap_breakloop`
383+ // `handle_valid` lock is held for the duration of `pcap_breakloop` so the handle
384+ // can't be deallocated while `pcap_breakloop` is running
385+ unsafe { raw:: pcap_breakloop ( self . handle . as_ptr ( ) ) } ;
386+ }
387+ }
388+ }
389+ }
390+
324391
325392/// Abstraction for writing pcap savefiles, which can be read afterwards via `Capture::from_file()`.
326393pub struct Savefile {
0 commit comments