Skip to content

Commit 6b5c9b1

Browse files
committed
Take timestamp at capture level, refactor code
1 parent c6d72aa commit 6b5c9b1

File tree

5 files changed

+79
-68
lines changed

5 files changed

+79
-68
lines changed

src/app.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::{
1414
};
1515
use tokio::time;
1616

17-
use crate::types::{ClockIdentity, ProcessedPacket};
17+
use crate::types::{ClockIdentity, ParsedPacket};
1818

1919
use crate::{
2020
ptp::{PtpHost, PtpHostState, PtpTracker},
@@ -123,7 +123,7 @@ pub struct App {
123123
pub auto_scroll_packets: bool,
124124
pub visible_packet_height: usize,
125125
pub show_packet_modal: bool,
126-
pub modal_packet: Option<ProcessedPacket>,
126+
pub modal_packet: Option<ParsedPacket>,
127127
pub modal_scroll_offset: usize,
128128
pub modal_visible_height: usize,
129129
pub force_redraw: bool,
@@ -984,7 +984,7 @@ impl App {
984984
self.sort_ascending
985985
}
986986

987-
pub fn get_packet_history(&self) -> Vec<ProcessedPacket> {
987+
pub fn get_packet_history(&self) -> Vec<ParsedPacket> {
988988
// Return packets from the currently selected host
989989
if let Some(ref selected_host_id) = self.selected_host_id {
990990
if let Some(history) = self.ptp_tracker.get_host_packet_history(*selected_host_id) {
@@ -1174,7 +1174,7 @@ impl App {
11741174
self.visible_packet_height = height;
11751175
}
11761176

1177-
pub fn get_selected_packet(&self) -> Option<ProcessedPacket> {
1177+
pub fn get_selected_packet(&self) -> Option<ParsedPacket> {
11781178
let packets = self.get_packet_history();
11791179
if self.selected_packet_index < packets.len() {
11801180
Some(packets[self.selected_packet_index].clone())
@@ -1183,7 +1183,7 @@ impl App {
11831183
}
11841184
}
11851185

1186-
pub fn get_modal_packet(&self) -> Option<&ProcessedPacket> {
1186+
pub fn get_modal_packet(&self) -> Option<&ParsedPacket> {
11871187
self.modal_packet.as_ref()
11881188
}
11891189

src/ptp.rs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
bounded_vec::BoundedVec,
1010
types::{
1111
AnnounceMessage, ClockIdentity, DelayRespMessage, FollowUpMessage,
12-
PDelayRespFollowUpMessage, PDelayRespMessage, ProcessedPacket, PtpClockAccuracy,
12+
PDelayRespFollowUpMessage, PDelayRespMessage, ParsedPacket, PtpClockAccuracy,
1313
PtpClockClass, PtpCorrectionField, PtpHeader, PtpMessage, PtpTimestamp, PtpUtcOffset,
1414
PtpVersion, SyncMessage,
1515
},
@@ -395,7 +395,7 @@ pub struct PtpHost {
395395

396396
pub state: PtpHostState,
397397
pub last_correction_field: Option<PtpCorrectionField>,
398-
pub packet_history: BoundedVec<Rc<ProcessedPacket>>,
398+
pub packet_history: BoundedVec<Rc<ParsedPacket>>,
399399
}
400400

401401
impl PtpHost {
@@ -475,7 +475,7 @@ impl PtpHost {
475475
self.ip_addresses.keys().any(|ip| local_ips.contains(ip))
476476
}
477477

478-
pub fn add_packet(&mut self, packet: Rc<ProcessedPacket>) {
478+
pub fn add_packet(&mut self, packet: Rc<ParsedPacket>) {
479479
self.packet_history.push(packet);
480480
}
481481

@@ -487,7 +487,7 @@ impl PtpHost {
487487
}
488488
}
489489

490-
pub fn get_packet_history(&self) -> Vec<ProcessedPacket> {
490+
pub fn get_packet_history(&self) -> Vec<ParsedPacket> {
491491
self.packet_history
492492
.items
493493
.iter()
@@ -573,7 +573,8 @@ impl PtpTracker {
573573
// Limit iterations to prevent blocking too long
574574
match self.raw_socket_receiver.try_recv() {
575575
Some(raw_packet) => {
576-
self.handle_raw_packet(&raw_packet).await;
576+
let raw_packet_arc = std::sync::Arc::new(raw_packet);
577+
self.handle_raw_packet(raw_packet_arc).await;
577578
self.last_packet = Instant::now();
578579
}
579580
None => {
@@ -584,23 +585,16 @@ impl PtpTracker {
584585
}
585586
}
586587

587-
async fn handle_raw_packet(&mut self, raw_packet: &crate::socket::RawPacket) {
588+
async fn handle_raw_packet(&mut self, raw_packet: std::sync::Arc<crate::socket::RawPacket>) {
588589
let msg = match PtpMessage::try_from(raw_packet.ptp_payload.as_slice()) {
589590
Ok(m) => m,
590591
Err(_) => return, // Invalid message
591592
};
592593

593594
// Create packet info for recording
594-
let packet = Rc::new(ProcessedPacket {
595-
ptp_message: msg,
596-
timestamp: std::time::Instant::now(),
597-
vlan_id: raw_packet.vlan_id,
598-
source_addr: raw_packet.source_addr,
599-
source_mac: raw_packet.source_mac,
600-
dest_addr: raw_packet.dest_addr,
601-
dest_mac: raw_packet.dest_mac,
602-
interface: raw_packet.interface_name.clone(),
603-
raw_packet_data: raw_packet.data.clone(),
595+
let packet = Rc::new(ParsedPacket {
596+
ptp: msg,
597+
raw: raw_packet.clone(),
604598
});
605599

606600
let sending_host = self
@@ -609,7 +603,10 @@ impl PtpTracker {
609603
.or_insert_with(|| PtpHost::new(msg.header().source_port_identity.clock_identity));
610604

611605
// Add this IP address if it's not already known for this host
612-
sending_host.add_ip_address(raw_packet.source_addr.ip(), packet.interface.clone());
606+
sending_host.add_ip_address(
607+
raw_packet.source_addr.ip(),
608+
packet.raw.interface_name.clone(),
609+
);
613610

614611
sending_host.total_messages_sent_count += 1;
615612
sending_host.update_from_ptp_header(msg.header());
@@ -792,7 +789,7 @@ impl PtpTracker {
792789
pub fn get_host_packet_history(
793790
&self,
794791
clock_identity: ClockIdentity,
795-
) -> Option<Vec<ProcessedPacket>> {
792+
) -> Option<Vec<ParsedPacket>> {
796793
self.hosts
797794
.get(&clock_identity)
798795
.map(|host| host.get_packet_history())

src/socket.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
//! promiscuous mode support. Works on Linux, macOS, and Windows.
55
66
use anyhow::Result;
7-
use pcap::{Capture, Device, Linktype};
7+
use libc::timeval;
8+
use pcap::{Capture, Device, Linktype, Packet};
89
use socket2::{Domain, Protocol, Socket, Type};
910
use std::io;
1011
use std::net::{IpAddr, Ipv4Addr};
12+
use std::time::{SystemTime, UNIX_EPOCH};
1113
use tokio::sync::mpsc;
1214
use tokio::time::Duration;
1315

@@ -17,6 +19,7 @@ const PTP_MULTICAST_ADDR: &str = "224.0.1.129";
1719

1820
#[derive(Debug, Clone)]
1921
pub struct RawPacket {
22+
pub timestamp: std::time::SystemTime,
2023
pub data: Vec<u8>,
2124
pub source_addr: std::net::SocketAddr,
2225
pub source_mac: [u8; 6],
@@ -155,7 +158,15 @@ fn join_multicast_group(interface_name: &str, interface_addr: Ipv4Addr) -> Resul
155158
Ok(socket)
156159
}
157160

158-
fn process_ethernet_packet(packet_data: &[u8], interface_name: &str) -> Option<RawPacket> {
161+
fn timeval_to_systemtime(tv: timeval) -> SystemTime {
162+
// tv_sec is seconds since epoch, tv_usec is microseconds
163+
let dur = Duration::new(tv.tv_sec as u64, (tv.tv_usec as u32) * 1000);
164+
UNIX_EPOCH + dur
165+
}
166+
167+
fn process_ethernet_packet(packet: &Packet, interface_name: &str) -> Option<RawPacket> {
168+
let packet_data = packet.data;
169+
159170
// Minimum Ethernet frame size check
160171
if packet_data.len() < 14 {
161172
return None;
@@ -251,6 +262,7 @@ fn process_ethernet_packet(packet_data: &[u8], interface_name: &str) -> Option<R
251262
let dest_addr = std::net::SocketAddr::V4(std::net::SocketAddrV4::new(dest_ip, dest_port));
252263

253264
Some(RawPacket {
265+
timestamp: timeval_to_systemtime(packet.header.ts),
254266
data: packet_data.to_vec(),
255267
source_addr,
256268
source_mac,
@@ -315,7 +327,7 @@ async fn capture_on_interface(
315327
loop {
316328
match cap.next_packet() {
317329
Ok(packet) => {
318-
if let Some(raw_packet) = process_ethernet_packet(packet.data, &interface_name) {
330+
if let Some(raw_packet) = process_ethernet_packet(&packet, &interface_name) {
319331
if sender.send(raw_packet).is_err() {
320332
// Receiver has been dropped, exit the loop
321333
break;

src/types.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,16 +1068,9 @@ impl Display for PtpMessage {
10681068
}
10691069

10701070
#[derive(Debug, Clone)]
1071-
pub struct ProcessedPacket {
1072-
pub ptp_message: PtpMessage,
1073-
pub timestamp: std::time::Instant,
1074-
pub source_addr: std::net::SocketAddr,
1075-
pub source_mac: [u8; 6],
1076-
pub dest_addr: std::net::SocketAddr,
1077-
pub dest_mac: [u8; 6],
1078-
pub vlan_id: Option<u16>,
1079-
pub interface: String,
1080-
pub raw_packet_data: Vec<u8>,
1071+
pub struct ParsedPacket {
1072+
pub ptp: PtpMessage,
1073+
pub raw: std::sync::Arc<crate::socket::RawPacket>,
10811074
}
10821075

10831076
#[test]

src/ui.rs

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use ratatui::{
99
use crate::{
1010
app::{ActiveView, App, SortColumn, TreeNode},
1111
ptp::{PtpHost, PtpHostState},
12-
types::{format_timestamp, ProcessedPacket, PtpClockAccuracy, PtpClockClass},
12+
types::{format_timestamp, ParsedPacket, PtpClockAccuracy, PtpClockClass},
1313
version,
1414
};
1515

@@ -1027,8 +1027,9 @@ fn render_scrollbar(
10271027
}
10281028
}
10291029

1030-
fn format_instant(instant: std::time::Instant) -> String {
1031-
let elapsed = instant.elapsed();
1030+
fn format_instant(system_time: std::time::SystemTime) -> String {
1031+
let now = std::time::SystemTime::now();
1032+
let elapsed = now.duration_since(system_time).unwrap_or_default();
10321033

10331034
let elapsed_str = if elapsed.as_secs() < 1 {
10341035
format!("{}ms", elapsed.as_millis())
@@ -1180,8 +1181,8 @@ fn render_packet_history(f: &mut Frame, area: Rect, app: &mut App) {
11801181
.iter()
11811182
.enumerate()
11821183
.map(|(i, packet)| {
1183-
let time_str = format_instant(packet.timestamp);
1184-
let header = packet.ptp_message.header();
1184+
let time_str = format_instant(packet.raw.timestamp);
1185+
let header = packet.ptp.header();
11851186

11861187
let row_style =
11871188
if matches!(app.active_view, ActiveView::PacketHistory) && i == selected_in_view {
@@ -1194,19 +1195,19 @@ fn render_packet_history(f: &mut Frame, area: Rect, app: &mut App) {
11941195

11951196
Row::new(vec![
11961197
Cell::from(time_str),
1197-
Cell::from(match packet.vlan_id {
1198+
Cell::from(match packet.raw.vlan_id {
11981199
Some(id) => id.to_string(),
11991200
None => "-".to_string(),
12001201
}),
1201-
Cell::from(match packet.source_addr {
1202+
Cell::from(match packet.raw.source_addr {
12021203
std::net::SocketAddr::V4(a) => a.ip().to_string(),
12031204
_ => "-".to_string(),
12041205
}),
1205-
Cell::from(match packet.source_addr {
1206+
Cell::from(match packet.raw.source_addr {
12061207
std::net::SocketAddr::V4(a) => a.port().to_string(),
12071208
_ => "-".to_string(),
12081209
}),
1209-
Cell::from(packet.interface.clone()),
1210+
Cell::from(packet.raw.interface_name.clone()),
12101211
Cell::from(header.version.to_string()),
12111212
Cell::from(Span::styled(
12121213
header.message_type.to_string(),
@@ -1218,7 +1219,7 @@ fn render_packet_history(f: &mut Frame, area: Rect, app: &mut App) {
12181219
Cell::from(header.flags.short()),
12191220
Cell::from(header.correction_field.to_string()),
12201221
Cell::from(header.log_message_interval.to_string()),
1221-
Cell::from(packet.ptp_message.to_string()),
1222+
Cell::from(packet.ptp.to_string()),
12221223
])
12231224
.style(row_style)
12241225
})
@@ -1290,7 +1291,7 @@ fn render_packet_modal(f: &mut Frame, area: Rect, app: &mut App) {
12901291
// Modal title
12911292
let title = format!(
12921293
"Packet Details - Seq {} (ESC to close)",
1293-
packet.ptp_message.header().sequence_id
1294+
packet.ptp.header().sequence_id
12941295
);
12951296

12961297
// Get theme reference before mutable operations
@@ -1314,12 +1315,12 @@ fn render_packet_modal(f: &mut Frame, area: Rect, app: &mut App) {
13141315
fn render_packet_details_with_hexdump(
13151316
f: &mut Frame,
13161317
area: Rect,
1317-
packet: &ProcessedPacket,
1318+
packet: &ParsedPacket,
13181319
theme: &crate::themes::Theme,
13191320
app: &mut App,
13201321
) {
1321-
let header = packet.ptp_message.header();
1322-
let time_str = format_instant(packet.timestamp);
1322+
let header = packet.ptp.header();
1323+
let time_str = format_instant(packet.raw.timestamp);
13231324

13241325
// Define the width for label alignment (same as host details)
13251326
const LABEL_WIDTH: usize = 30;
@@ -1336,48 +1337,56 @@ fn render_packet_details_with_hexdump(
13361337
)]),
13371338
create_aligned_field(
13381339
"Source Address:",
1339-
packet.source_addr.to_string(),
1340+
packet.raw.source_addr.to_string(),
13401341
LABEL_WIDTH,
13411342
theme,
13421343
),
13431344
create_aligned_field(
13441345
"Source MAC:",
13451346
format!(
13461347
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
1347-
packet.source_mac[0],
1348-
packet.source_mac[1],
1349-
packet.source_mac[2],
1350-
packet.source_mac[3],
1351-
packet.source_mac[4],
1352-
packet.source_mac[5]
1348+
packet.raw.source_mac[0],
1349+
packet.raw.source_mac[1],
1350+
packet.raw.source_mac[2],
1351+
packet.raw.source_mac[3],
1352+
packet.raw.source_mac[4],
1353+
packet.raw.source_mac[5]
13531354
),
13541355
LABEL_WIDTH,
13551356
theme,
13561357
),
13571358
create_aligned_field(
13581359
"Dest Address:",
1359-
packet.dest_addr.to_string(),
1360+
packet.raw.dest_addr.to_string(),
13601361
LABEL_WIDTH,
13611362
theme,
13621363
),
13631364
create_aligned_field(
13641365
"Dest MAC:",
13651366
format!(
13661367
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
1367-
packet.dest_mac[0],
1368-
packet.dest_mac[1],
1369-
packet.dest_mac[2],
1370-
packet.dest_mac[3],
1371-
packet.dest_mac[4],
1372-
packet.dest_mac[5]
1368+
packet.raw.dest_mac[0],
1369+
packet.raw.dest_mac[1],
1370+
packet.raw.dest_mac[2],
1371+
packet.raw.dest_mac[3],
1372+
packet.raw.dest_mac[4],
1373+
packet.raw.dest_mac[5]
13731374
),
13741375
LABEL_WIDTH,
13751376
theme,
13761377
),
1377-
create_aligned_field("Interface:", packet.interface.clone(), LABEL_WIDTH, theme),
1378+
create_aligned_field(
1379+
"Interface:",
1380+
packet.raw.interface_name.clone(),
1381+
LABEL_WIDTH,
1382+
theme,
1383+
),
13781384
create_aligned_field(
13791385
"VLAN ID:",
1380-
packet.vlan_id.map_or("-".to_string(), |id| id.to_string()),
1386+
packet
1387+
.raw
1388+
.vlan_id
1389+
.map_or("-".to_string(), |id| id.to_string()),
13811390
LABEL_WIDTH,
13821391
theme,
13831392
),
@@ -1443,7 +1452,7 @@ fn render_packet_details_with_hexdump(
14431452
];
14441453

14451454
// Add detailed message fields
1446-
let message_details = packet.ptp_message.details();
1455+
let message_details = packet.ptp.details();
14471456
if !message_details.is_empty() {
14481457
for (field_name, field_value) in message_details.iter() {
14491458
all_lines.push(Line::from(vec![
@@ -1485,7 +1494,7 @@ fn render_packet_details_with_hexdump(
14851494
}
14861495

14871496
// Add hexdump section at the end
1488-
let raw_data = &packet.raw_packet_data;
1497+
let raw_data = &packet.raw.data;
14891498
all_lines.extend(vec![
14901499
Line::from(""),
14911500
Line::from(vec![

0 commit comments

Comments
 (0)