wintun_bindings/
packet.rs

1use crate::session::Session;
2use std::sync::Arc;
3
4pub(crate) enum Kind {
5    SendPacketPending, //Send packet type, but not sent yet
6    SendPacketSent,    //Send packet type - sent
7    ReceivePacket,
8}
9
10/// Represents a wintun packet
11pub struct Packet {
12    pub(crate) kind: Kind,
13
14    /// This lifetime is not actually 'static, however before you get your pitchforks let me explain...
15    /// The bytes in this slice live for as long at the session that allocated them, or until
16    /// WintunReleaseReceivePacket, or WintunSendPacket is called on them (whichever happens first).
17    /// The wrapper functions that call into WintunReleaseReceivePacket, and WintunSendPacket
18    /// consume the packet, meaning the end of this packet's lifetime coincides with the end of byte's
19    /// lifetime. Because we never copy out of bytes, this pointer becomes inaccessible when the
20    /// packet is dropped.
21    ///
22    /// This just leaves packets potentially outliving the session that allocated them posing a
23    /// problem.
24    /// Fortunately we have an Arc to the session that allocated this packet, meaning that the lifetime
25    /// of the session that created this packet is at least as long as the packet.
26    /// Because this is private (to external users) and we only write to this field when allocating
27    /// new packets, it is impossible for the memory that is pointed to by bytes to outlive the
28    /// underlying memory allocated by wintun.
29    ///
30    /// So what I told you was true, from a certain point of view.
31    /// From the point of view of this packet, bytes' lifetime is 'static because we are always
32    /// dropped before the underlying memory is freed
33    ///
34    /// Its also important to know that WintunAllocateSendPacket and WintunReceivePacket always
35    /// return sections of memory that never overlap, so we have exclusive access to the memory,
36    /// therefore mut is okay here.
37    pub(crate) bytes: &'static mut [u8],
38
39    /// Share ownership of session to prevent the session from being dropped before packets that
40    /// belong to it
41    pub(crate) session: Arc<Session>,
42}
43
44impl Packet {
45    /// Returns the bytes this packet holds as &mut.
46    /// The lifetime of the bytes is tied to the lifetime of this packet.
47    pub fn bytes_mut(&mut self) -> &mut [u8] {
48        self.bytes
49    }
50
51    /// Returns an immutable reference to the bytes this packet holds.
52    /// The lifetime of the bytes is tied to the lifetime of this packet.
53    pub fn bytes(&self) -> &[u8] {
54        self.bytes
55    }
56}
57
58impl Drop for Packet {
59    fn drop(&mut self) {
60        match self.kind {
61            Kind::ReceivePacket => {
62                unsafe {
63                    //SAFETY:
64                    //
65                    //  1. We share ownership of the session therefore it hasn't been dropped yet
66                    //  2. Bytes is valid because each packet holds exclusive access to a region of the
67                    //     ring buffer that the wintun session owns. We return that region of
68                    //     memory back to wintun here
69                    self.session
70                        .get_wintun()
71                        .WintunReleaseReceivePacket(self.session.inner.0, self.bytes.as_ptr())
72                };
73            }
74            Kind::SendPacketPending => {
75                //If someone allocates a packet with session.allocate_send_packet() and then it is
76                //dropped without being sent, this will hold up the send queue because wintun expects
77                //that every allocated packet is sent
78
79                #[cfg(feature = "panic_on_unsent_packets")]
80                panic!("Packet was never sent!");
81            }
82            Kind::SendPacketSent => {
83                //Nop
84            }
85        }
86    }
87}