1
use std::path::Path;
2

            
3
#[cfg(not(windows))]
4
use std::os::unix::io::RawFd;
5

            
6
use crate::{
7
    capture::{Capture, Offline},
8
    raw, Error,
9
};
10

            
11
#[cfg(libpcap_1_5_0)]
12
use crate::capture::Precision;
13

            
14
#[cfg(not(windows))]
15
use crate::capture::activated::open_raw_fd;
16

            
17
impl Capture<Offline> {
18
    /// Opens an offline capture handle from a pcap dump file, given a path.
19
24
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Capture<Offline>, Error> {
20
36
        Capture::new_raw(path.as_ref().to_str(), |path, err| unsafe {
21
24
            raw::pcap_open_offline(path, err)
22
36
        })
23
24
    }
24

            
25
    /// Opens an offline capture handle from a pcap dump file, given a path.
26
    /// Takes an additional precision argument specifying the time stamp precision desired.
27
    #[cfg(libpcap_1_5_0)]
28
2
    pub fn from_file_with_precision<P: AsRef<Path>>(
29
2
        path: P,
30
2
        precision: Precision,
31
2
    ) -> Result<Capture<Offline>, Error> {
32
3
        Capture::new_raw(path.as_ref().to_str(), |path, err| unsafe {
33
2
            raw::pcap_open_offline_with_tstamp_precision(path, precision as _, err)
34
3
        })
35
2
    }
36

            
37
    /// Opens an offline capture handle from a pcap dump file, given a file descriptor.
38
    ///
39
    /// # Safety
40
    ///
41
    /// Unsafe, because the returned Capture assumes it is the sole owner of the file descriptor.
42
    #[cfg(not(windows))]
43
6
    pub unsafe fn from_raw_fd(fd: RawFd) -> Result<Capture<Offline>, Error> {
44
6
        open_raw_fd(fd, b'r')
45
7
            .and_then(|file| Capture::new_raw(None, |_, err| raw::pcap_fopen_offline(file, err)))
46
6
    }
47

            
48
    /// Opens an offline capture handle from a pcap dump file, given a file descriptor. Takes an
49
    /// additional precision argument specifying the time stamp precision desired.
50
    ///
51
    /// # Safety
52
    ///
53
    /// Unsafe, because the returned Capture assumes it is the sole owner of the file descriptor.
54
    #[cfg(all(not(windows), libpcap_1_5_0))]
55
6
    pub unsafe fn from_raw_fd_with_precision(
56
6
        fd: RawFd,
57
6
        precision: Precision,
58
6
    ) -> Result<Capture<Offline>, Error> {
59
7
        open_raw_fd(fd, b'r').and_then(|file| {
60
3
            Capture::new_raw(None, |_, err| {
61
3
                raw::pcap_fopen_offline_with_tstamp_precision(file, precision as _, err)
62
3
            })
63
7
        })
64
6
    }
65

            
66
    /// Get the major version number of the pcap dump file format.
67
8
    pub fn major_version(&self) -> i32 {
68
8
        unsafe { raw::pcap_major_version(self.handle.as_ptr()) }
69
8
    }
70

            
71
    /// Get the minor version number of the pcap dump file format.
72
8
    pub fn minor_version(&self) -> i32 {
73
8
        unsafe { raw::pcap_minor_version(self.handle.as_ptr()) }
74
8
    }
75

            
76
    /// Get the (major, minor) version number of the pcap dump file format.
77
5
    pub fn version(&self) -> (i32, i32) {
78
5
        (self.major_version(), self.minor_version())
79
5
    }
80
}
81

            
82
#[cfg(test)]
83
mod tests {
84
    #[cfg(libpcap_1_5_0)]
85
    use mockall::predicate;
86

            
87
    use crate::{
88
        capture::testmod::test_capture,
89
        raw::testmod::{as_pcap_t, RAWMTX},
90
    };
91

            
92
    use super::*;
93

            
94
    #[test]
95
    fn test_from_file() {
96
        let _m = RAWMTX.lock();
97

            
98
        let mut dummy: isize = 777;
99
        let pcap = as_pcap_t(&mut dummy);
100

            
101
        let ctx = raw::pcap_open_offline_context();
102
        ctx.expect().return_once_st(move |_, _| pcap);
103

            
104
        let ctx = raw::pcap_close_context();
105
        ctx.expect()
106
            .withf_st(move |ptr| *ptr == pcap)
107
            .return_once(|_| {});
108

            
109
        let result = Capture::from_file("path/to/nowhere");
110
        assert!(result.is_ok());
111
    }
112

            
113
    #[test]
114
    #[cfg(libpcap_1_5_0)]
115
    fn test_from_file_with_precision() {
116
        let _m = RAWMTX.lock();
117

            
118
        let mut dummy: isize = 777;
119
        let pcap = as_pcap_t(&mut dummy);
120

            
121
        let ctx = raw::pcap_open_offline_with_tstamp_precision_context();
122
        ctx.expect()
123
            .with(predicate::always(), predicate::eq(1), predicate::always())
124
            .return_once_st(move |_, _, _| pcap);
125

            
126
        let ctx = raw::pcap_close_context();
127
        ctx.expect()
128
            .withf_st(move |ptr| *ptr == pcap)
129
            .return_once(|_| {});
130

            
131
        let result = Capture::from_file_with_precision("path/to/nowhere", Precision::Nano);
132
        assert!(result.is_ok());
133
    }
134

            
135
    #[test]
136
    fn test_version() {
137
        let _m = RAWMTX.lock();
138

            
139
        let mut dummy: isize = 777;
140
        let pcap = as_pcap_t(&mut dummy);
141

            
142
        let ctx = raw::pcap_major_version_context();
143
        ctx.expect()
144
            .withf_st(move |arg| *arg == pcap)
145
            .return_once(|_| 5);
146

            
147
        let ctx = raw::pcap_minor_version_context();
148
        ctx.expect()
149
            .withf_st(move |arg| *arg == pcap)
150
            .return_once(|_| 7);
151

            
152
        let test_capture = test_capture::<Offline>(pcap);
153
        let capture = test_capture.capture;
154

            
155
        assert_eq!(capture.version(), (5, 7));
156
    }
157
}