How to Pause and Resume Packet Monitoring Using Sniffnet's Freeze Feature
Sniffnet's freeze feature temporarily suspends the live packet-parsing thread via a tokio::sync::broadcast channel, allowing you to pause and resume monitoring without terminating the underlying capture session.
Sniffnet, the open-source network traffic analyzer maintained by GyulyVGC/sniffnet, implements a sophisticated freeze mechanism that decouples the GUI from background packet processing. This feature enables users to halt packet parsing on demand through a toolbar toggle button while keeping the capture session alive. The implementation relies on asynchronous message passing between the main application state and the parsing thread, ensuring smooth state transitions without data loss.
Architecture of the Freeze Mechanism
Sniffnet coordinates the pause and resume functionality through four key components that communicate via broadcast channels. When you click the freeze button, the system toggles a boolean flag and signals the background thread to block until further notice.
The flow works as follows:
- The user clicks the Pause/Resume button in the header toolbar, dispatching
Message::Freezeto the event loop - The
Snifferstate machine flips itsfrozenboolean and broadcasts a signal throughfreeze_tx - The packet-parsing thread detects the signal via
freeze_rx.try_recv()and enters a blocking state usingfreeze_rx.blocking_recv() - A subsequent click sends a second broadcast, unblocking the receiver and resuming normal packet processing
Implementation Details
UI Button and Message Dispatch (src/gui/components/header.rs)
The freeze control resides in the header toolbar, implemented in src/gui/components/header.rs (lines 173-204). The get_button_freeze function constructs a button that dynamically switches between pause and resume icons based on the current frozen state:
pub fn get_button_freeze<'a>(
language: Language,
frozen: bool,
thumbnail: bool,
) -> Tooltip<'a, Message, StyleType> {
let icon = if frozen { Icon::Resume } else { Icon::Pause };
let tooltip = if frozen {
resume_translation(language) // “Resume monitoring”
} else {
pause_translation(language) // “Pause monitoring”
};
Tooltip::new(
button(icon.to_text())
.height(button_size)
.width(button_size)
.on_press(Message::Freeze), // <‑‑ dispatch Freeze message
Text::new(tooltip),
Position::FollowCursor,
)
}
This component triggers the Message::Freeze variant defined in src/gui/types/message.rs (lines 155-162), which carries no payload but serves as the toggle command:
enum Message {
// … other UI messages …
Freeze, // toggles pause/resume
}
State Management and Channel Setup (src/gui/sniffer.rs)
The core state logic lives in src/gui/sniffer.rs. The Sniffer struct maintains a frozen boolean and an optional broadcast sender freeze_tx: Option<broadcast::Sender<()>>.
When initializing a capture session (around lines 989-991), Sniffnet creates the broadcast channel with a capacity of 1,048,575 messages and prepares two receivers for the parsing thread:
let (freeze_tx, freeze_rx) = tokio::sync::broadcast::channel(1_048_575);
let freeze_rx2 = freeze_tx.subscribe(); // second receiver for the parser
self.freeze_tx = Some(freeze_tx);
...
parse_packets(..., (freeze_rx, freeze_rx2));
The freeze() method (lines 59-64) handles the toggle logic by flipping the state flag and broadcasting a unit value:
fn freeze(&mut self) {
self.frozen = !self.frozen; // flip the UI flag
if let Some(tx) = &self.freeze_tx {
let _ = tx.send(()); // broadcast pause or resume request
}
}
Parser Thread Coordination (src/networking/parse_packets.rs)
The background thread executing parse_packets in src/networking/parse_packets.rs (lines 81-88) implements non-blocking checks for freeze signals. When a signal arrives, the thread blocks on the receiver until the next broadcast arrives:
loop {
// Pause detection
if freeze_rx.try_recv().is_ok() {
// Block until a resume signal arrives
let _ = freeze_rx.blocking_recv();
// Reset timing for live captures
first_packet_ticks = Some(Instant::now());
}
// … normal packet processing …
}
This design ensures that packets continue to be captured at the OS level (by the underlying pcap library) but are not processed or displayed until the thread resumes. The blocking_recv() call efficiently parks the thread without consuming CPU cycles during the pause state.
Summary
- Sniffnet's freeze feature uses a
tokio::sync::broadcastchannel to coordinate between the GUI and the packet-parsing thread - The UI button in
src/gui/components/header.rsdispatchesMessage::Freezeto toggle states between pause and resume icons - State management in
src/gui/sniffer.rsflips a boolean flag and broadcasts signals viafreeze_tx.send(()) - The parsing thread in
src/networking/parse_packets.rsdetects freeze signals withtry_recv()and blocks withblocking_recv()until resumed - This architecture maintains the capture session while halting processing, allowing inspection of current traffic data without terminating the underlying capture
Frequently Asked Questions
Does freezing stop the network capture entirely?
No, freezing only pauses the packet-parsing thread. The underlying pcap capture session continues running in the background, but incoming packets are not processed or displayed in the GUI until you resume. This distinction ensures you don't lose network events or drop the capture handle during the pause.
What happens to packets received while Sniffnet is frozen?
Packets captured during the freeze state remain in the OS buffer or pcap buffer but are not parsed by the application. When you resume, the parser continues from where it left off, processing new packets as they arrive. The first_packet_ticks reset in the resume logic ensures timing calculations remain accurate for live captures.
Why does Sniffnet use a broadcast channel instead of a simple boolean flag?
The tokio::sync::broadcast channel provides thread-safe communication without requiring shared mutable state between the GUI and the background thread. The blocking receive mechanism (blocking_recv()) allows the parsing thread to sleep efficiently without polling, reducing CPU usage to zero while frozen. A simple boolean would require the thread to poll continuously or use additional synchronization primitives.
Can the freeze feature be triggered programmatically?
Yes, since Message::Freeze is a standard variant of the Message enum, any code that can dispatch messages to the Sniffnet update loop can trigger the freeze. This includes custom UI components, keyboard shortcuts, or automated scripts that interface with the Sniffer's message handling system defined in src/gui/types/message.rs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →