1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//! reads from a underlying reader like a file or a buffer.
use crate::format::{
PacketHeader, SnoopHeader, SnoopPacket, SnoopPacketRef, MAX_CAPTURE_LEN, MAX_CAPTURE_PADS,
SNOOP_HEADER_SIZE, SNOOP_PACKET_HEADER_SIZE,
};
use crate::parse::Parser;
use crate::Error;
use std::io::Read;
use std::{thread, time};
/// reader to read snoop packet data from a file or buffer into a internal buffer.
#[derive(Debug)]
pub struct Reader<R> {
r: R,
header: SnoopHeader,
ph: PacketHeader,
buf: Vec<u8>,
}
impl<R> Reader<R>
where
R: Read,
{
/// create a new reader with internal buffer for the snoop header, packet header and packet data.
/// read and parse the snoop file header on creation.
/// # Errors
/// will return [`Error::UnknownMagic`] if no magic bytes are present at the beginning
pub fn new(r: R) -> Result<Self, Error> {
let mut r = Self {
r,
header: SnoopHeader {
..Default::default()
},
ph: PacketHeader {
..Default::default()
},
buf: vec![0u8; (MAX_CAPTURE_LEN + MAX_CAPTURE_PADS) as usize],
};
r.read_header()?;
Ok(r)
}
/// get a reference to the snoop file format header
pub fn header(&self) -> &SnoopHeader {
&self.header
}
/// read and parse snoop file format header from the underlying reader
fn read_header(&mut self) -> Result<(), Error> {
self.read_exact(0, SNOOP_HEADER_SIZE)?;
self.header = Parser::parse_header(&self.buf[0..SNOOP_HEADER_SIZE].try_into().unwrap())?;
Ok(())
}
/// read a exact number of bytes from a underlying reader and returns how many bytes are read if a unexpected eof error occurs.
fn read_exact(&mut self, start: usize, end: usize) -> Result<(), Error> {
let mut buf = &mut self.buf[start..end];
let mut bytes: usize = 0;
while !buf.is_empty() {
match self.r.read(buf) {
Ok(0) => break, // maybe eof, tcp close or stream end
Ok(n) => {
bytes += n;
buf = &mut buf[n..]; // shrink buffer until its empty
}
Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {}
Err(e) => return Err(Error::Io(e)),
}
}
if !buf.is_empty() {
if bytes == 0 {
return Err(Error::Eof);
}
return Err(Error::UnexpectedEof(bytes));
}
Ok(())
}
/// read from a reader which is not finished yet. this function blocks until a valid EOF appeared.
/// can be used if the reader is a socket or the file is not fully written.
fn read_until(&mut self, size: usize, time: time::Duration) -> Result<(), Error> {
let mut bytes: usize = 0;
loop {
match self.read_exact(bytes, size) {
Ok(()) => break,
Err(e) => match e {
Error::Eof => {
thread::sleep(time);
}
Error::UnexpectedEof(n) => {
bytes += n;
thread::sleep(time);
}
_ => return Err(e),
},
};
}
Ok(())
}
/// read a packet with snoop header and snoop data from the underlying reader and return a reference to internal buf.
/// when this function is called again the data will be overwritten internaly.
/// # Errors
/// will return [`Error`] if something unexpected happen.
#[allow(clippy::missing_panics_doc)]
pub fn read_ref(&mut self) -> Result<SnoopPacketRef, Error> {
self.read_exact(0, SNOOP_PACKET_HEADER_SIZE)?;
Parser::parse_packet_header(
&self.buf[..SNOOP_PACKET_HEADER_SIZE].try_into().unwrap(),
&mut self.ph,
)?;
self.read_exact(0, Parser::data_len(&self.ph))?;
Ok(SnoopPacketRef {
header: &self.ph,
data: &self.buf[..usize::try_from(self.ph.included_length).unwrap()],
})
}
/// read a packet with snoop header and snoop data from the underlying reader and return a copy of the data.
/// # Errors
/// will return [`Error`] if something unexpected happen.
pub fn read(&mut self) -> Result<SnoopPacket, Error> {
let pr = self.read_ref()?;
Ok(SnoopPacket {
header: pr.header.clone(),
data: pr.data.to_vec(),
})
}
/// read a packet with snoop header and snoop data from the underlying reader and return a reference of the data.
/// read from a reader which is not finished yet. this function blocks until a valid EOF appeared.
/// can be used if the reader is a socket or the file is not fully written.
/// # Errors
/// will return [`Error`] if something unexpected happen.
#[allow(clippy::missing_panics_doc)]
pub fn read_stream(&mut self, time: time::Duration) -> Result<SnoopPacketRef, Error> {
self.read_until(SNOOP_PACKET_HEADER_SIZE, time)?;
Parser::parse_packet_header(
&self.buf[..SNOOP_PACKET_HEADER_SIZE].try_into().unwrap(),
&mut self.ph,
)?;
self.read_until(Parser::data_len(&self.ph), time)?;
Ok(SnoopPacketRef {
header: &self.ph,
data: &self.buf[..usize::try_from(self.ph.included_length).unwrap()],
})
}
/// iterate over packets inside a snoop file until a valid eof or error occurs and return the packet data as a reference to the underlying buffer.
pub fn iter_ref(&mut self) -> Option<Result<SnoopPacketRef, Error>> {
match self.read_ref() {
Ok(packet) => Some(Ok(packet)),
Err(Error::Eof) => None,
Err(e) => Some(Err(e)),
}
}
}
impl<R> Iterator for Reader<R>
where
R: Read,
{
type Item = Result<SnoopPacket, Error>;
/// iterate over packets inside a snoop file until a valid eof or error occurs and return the packet data as a copy.
fn next(&mut self) -> Option<Self::Item> {
match self.read() {
Ok(packet) => Some(Ok(packet)),
Err(Error::Eof) => None,
Err(e) => Some(Err(e)),
}
}
}