1
use std::ptr::NonNull;
2

            
3
use crate::{
4
    Error,
5
    capture::{Capture, Dead},
6
    linktype::Linktype,
7
    raw,
8
};
9

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

            
13
impl Capture<Dead> {
14
    /// Creates a "fake" capture handle for the given link type.
15
52
    pub fn dead(linktype: Linktype) -> Result<Capture<Dead>, Error> {
16
52
        let library = raw::require_library()?;
17

            
18
52
        let handle = unsafe { raw::pcap_open_dead(&library, linktype.0, 65535) };
19
52
        Ok(Capture::from_handle(
20
52
            NonNull::<raw::pcap_t>::new(handle).ok_or(Error::InsufficientMemory)?,
21
        ))
22
52
    }
23

            
24
    /// Creates a "fake" capture handle for the given link type and timestamp precision.
25
    #[cfg(libpcap_1_5_0)]
26
1
    pub fn dead_with_precision(
27
1
        linktype: Linktype,
28
1
        precision: Precision,
29
1
    ) -> Result<Capture<Dead>, Error> {
30
1
        let library = raw::require_library()?;
31

            
32
        #[cfg(windows)]
33
        if !raw::has_dead_precision() {
34
            return Err(Error::EntrypointNotFound(
35
                "pcap_open_dead_with_tstamp_precision",
36
            ));
37
        }
38

            
39
1
        let handle = unsafe {
40
1
            raw::pcap_open_dead_with_tstamp_precision(&library, linktype.0, 65535, precision as u32)
41
        };
42
1
        Ok(Capture::from_handle(
43
1
            NonNull::<raw::pcap_t>::new(handle).ok_or(Error::InsufficientMemory)?,
44
        ))
45
1
    }
46
}
47

            
48
#[cfg(test)]
49
mod tests {
50
    #[cfg(libpcap_1_5_0)]
51
    use mockall::predicate;
52

            
53
    use crate::raw::testmod::{RAWMTX, as_pcap_t};
54

            
55
    use super::*;
56

            
57
    #[test]
58
    fn test_dead() {
59
        let _m = RAWMTX.lock();
60

            
61
        let mut dummy: isize = 777;
62
        let pcap = as_pcap_t(&mut dummy);
63

            
64
        let ctx = raw::pcap_open_dead_context();
65
        ctx.expect().return_once_st(move |_, _, _| pcap);
66

            
67
        let ctx = raw::pcap_close_context();
68
        ctx.expect()
69
            .withf_st(move |ptr| *ptr == pcap)
70
            .return_once(|_| {});
71

            
72
        let result = Capture::dead(Linktype::ETHERNET);
73
        assert!(result.is_ok());
74
    }
75

            
76
    #[test]
77
    #[cfg(libpcap_1_5_0)]
78
    fn test_dead_with_precision() {
79
        let _m = RAWMTX.lock();
80

            
81
        let mut dummy: isize = 777;
82
        let pcap = as_pcap_t(&mut dummy);
83

            
84
        #[cfg(windows)]
85
        let ctx = raw::has_dead_precision_context();
86
        #[cfg(windows)]
87
        ctx.expect().return_once(|| true);
88

            
89
        let ctx = raw::pcap_open_dead_with_tstamp_precision_context();
90
        ctx.expect()
91
            .with(
92
                predicate::always(),
93
                predicate::always(),
94
                predicate::always(),
95
                predicate::eq(1),
96
            )
97
            .return_once_st(move |_, _, _, _| pcap);
98

            
99
        let ctx = raw::pcap_close_context();
100
        ctx.expect()
101
            .withf_st(move |ptr| *ptr == pcap)
102
            .return_once(|_| {});
103

            
104
        let result = Capture::dead_with_precision(Linktype::ETHERNET, Precision::Nano);
105
        assert!(result.is_ok());
106
    }
107

            
108
    #[test]
109
    #[cfg(all(windows, libpcap_1_5_0))]
110
    fn test_dead_precision_missing() {
111
        let _m = RAWMTX.lock();
112

            
113
        let ctx = raw::has_dead_precision_context();
114
        ctx.expect().return_once(|| false);
115

            
116
        let result = Capture::dead_with_precision(Linktype::ETHERNET, Precision::Nano);
117
        assert!(matches!(result, Err(Error::EntrypointNotFound(_))));
118
    }
119
}