1
use std::borrow::Borrow;
2

            
3
#[cfg(not(windows))]
4
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
5

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

            
11
impl Capture<Active> {
12
    /// Sends a packet over this capture handle's interface.
13
4
    pub fn sendpacket<B: Borrow<[u8]>>(&mut self, buf: B) -> Result<(), Error> {
14
4
        let buf = buf.borrow();
15
4
        self.check_err(unsafe {
16
4
            raw::pcap_sendpacket(self.handle.as_ptr(), buf.as_ptr() as _, buf.len() as _) == 0
17
4
        })
18
4
    }
19

            
20
    /// Set the capture to be non-blocking. When this is set, [`Self::next_packet()`] may return an
21
    /// error indicating that there is no packet available to be read.
22
4
    pub fn setnonblock(mut self) -> Result<Capture<Active>, Error> {
23
6
        Error::with_errbuf(|err| unsafe {
24
4
            if raw::pcap_setnonblock(self.handle.as_ptr(), 1, err) != 0 {
25
2
                return Err(Error::new(err));
26
2
            }
27
2
            self.nonblock = true;
28
2
            Ok(self)
29
6
        })
30
4
    }
31
}
32

            
33
#[cfg(not(windows))]
34
impl AsRawFd for Capture<Active> {
35
    /// Returns the file descriptor for a live capture.
36
2
    fn as_raw_fd(&self) -> RawFd {
37
2
        let fd = unsafe { raw::pcap_fileno(self.handle.as_ptr()) };
38
2
        assert!(fd != -1, "Unable to get file descriptor for live capture");
39
2
        fd
40
2
    }
41
}
42

            
43
#[cfg(not(windows))]
44
impl AsFd for Capture<Active> {
45
    /// Returns the file descriptor for a live capture.
46
2
    fn as_fd(&self) -> BorrowedFd {
47
2
        // SAFETY: pcap_fileno always succeeds on a live capture,
48
2
        // and we know this capture is live due to its State.
49
2
        let fd = unsafe { raw::pcap_fileno(self.handle.as_ptr()) };
50
2
        assert!(fd != -1, "Unable to get file descriptor for live capture");
51
        // SAFETY: The lifetime is bound to self, which is correct.
52
        // We have checked that fd != -1.
53
2
        unsafe { BorrowedFd::borrow_raw(fd) }
54
2
    }
55
}
56

            
57
#[cfg(test)]
58
mod tests {
59
    use crate::{
60
        capture::testmod::test_capture,
61
        raw::{
62
            mock_ffi::*,
63
            testmod::{as_pcap_t, geterr_expect, RAWMTX},
64
        },
65
    };
66

            
67
    use super::*;
68

            
69
    #[test]
70
    fn test_sendpacket() {
71
        let _m = RAWMTX.lock();
72

            
73
        let mut dummy: isize = 777;
74
        let pcap = as_pcap_t(&mut dummy);
75

            
76
        let buffer: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
77

            
78
        let test_capture = test_capture::<Active>(pcap);
79
        let mut capture = test_capture.capture;
80

            
81
        let ctx = pcap_sendpacket_context();
82
        ctx.expect()
83
            .withf_st(move |arg1, _, _| *arg1 == pcap)
84
            .return_once(|_, _, _| 0);
85

            
86
        let result = capture.sendpacket(buffer);
87
        assert!(result.is_ok());
88

            
89
        let ctx = pcap_sendpacket_context();
90
        ctx.checkpoint();
91
        ctx.expect()
92
            .withf_st(move |arg1, _, _| *arg1 == pcap)
93
            .return_once(|_, _, _| -1);
94

            
95
        let _err = geterr_expect(pcap);
96

            
97
        let result = capture.sendpacket(buffer);
98
        assert!(result.is_err());
99
    }
100

            
101
    #[test]
102
    fn test_setnonblock() {
103
        let _m = RAWMTX.lock();
104

            
105
        let mut dummy: isize = 777;
106
        let pcap = as_pcap_t(&mut dummy);
107

            
108
        let test_capture = test_capture::<Active>(pcap);
109
        let capture = test_capture.capture;
110
        assert!(!capture.is_nonblock());
111

            
112
        let ctx = pcap_setnonblock_context();
113
        ctx.expect()
114
            .withf_st(move |arg1, arg2, _| (*arg1 == pcap) && (*arg2 == 1))
115
            .return_once(|_, _, _| 0);
116

            
117
        let capture = capture.setnonblock().unwrap();
118
        assert!(capture.is_nonblock());
119
    }
120

            
121
    #[test]
122
    fn test_setnonblock_error() {
123
        let _m = RAWMTX.lock();
124

            
125
        let mut dummy: isize = 777;
126
        let pcap = as_pcap_t(&mut dummy);
127

            
128
        let test_capture = test_capture::<Active>(pcap);
129
        let capture = test_capture.capture;
130
        assert!(!capture.nonblock);
131

            
132
        let ctx = pcap_setnonblock_context();
133
        ctx.expect()
134
            .withf_st(move |arg1, arg2, _| (*arg1 == pcap) && (*arg2 == 1))
135
            .return_once(|_, _, _| -1);
136

            
137
        let result = capture.setnonblock();
138
        assert!(result.is_err());
139
    }
140

            
141
    #[test]
142
    #[cfg(not(windows))]
143
    fn test_as_raw_fd() {
144
        let _m = RAWMTX.lock();
145

            
146
        let mut dummy: isize = 777;
147
        let pcap = as_pcap_t(&mut dummy);
148

            
149
        let test_capture = test_capture::<Active>(pcap);
150
        let capture = test_capture.capture;
151

            
152
        let ctx = pcap_fileno_context();
153
        ctx.expect()
154
            .withf_st(move |arg1| *arg1 == pcap)
155
            .return_once(|_| 7);
156

            
157
        assert_eq!(capture.as_raw_fd(), 7);
158
    }
159

            
160
    #[test]
161
    #[cfg(not(windows))]
162
    fn test_as_fd() {
163
        let _m = RAWMTX.lock();
164

            
165
        let mut dummy: isize = 777;
166
        let pcap = as_pcap_t(&mut dummy);
167

            
168
        let test_capture = test_capture::<Active>(pcap);
169
        let capture = test_capture.capture;
170

            
171
        let ctx = pcap_fileno_context();
172
        ctx.expect()
173
            .withf_st(move |arg1| *arg1 == pcap)
174
            .return_once(|_| 7);
175

            
176
        assert_eq!(capture.as_fd().as_raw_fd(), 7);
177
    }
178
}