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
use crate::session;
use std::sync::Arc;
pub(crate) enum Kind {
SendPacketPending, //Send packet type, but not sent yet
SendPacketSent, //Send packet type - sent
ReceivePacket,
}
/// Represents a wintun packet
pub struct Packet {
pub(crate) kind: Kind,
/// This lifetime is not actually 'static, however before you get your pitchforks let me explain...
/// The bytes in this slice live for as long at the session that allocated them, or until
/// WintunReleaseReceivePacket, or WintunSendPacket is called on them (whichever happens first).
/// The wrapper functions that call into WintunReleaseReceivePacket, and WintunSendPacket
/// consume the packet, meaning the end of this packet's lifetime coincides with the end of byte's
/// lifetime. Because we never copy out of bytes, this pointer becomes inaccessible when the
/// packet is dropped.
///
/// This just leaves packets potentially outliving the session that allocated them posing a
/// problem.
/// Fortunately we have an Arc to the session that allocated this packet, meaning that the lifetime
/// of the session that created this packet is at least as long as the packet.
/// Because this is private (to external users) and we only write to this field when allocating
/// new packets, it is impossible for the memory that is pointed to by bytes to outlive the
/// underlying memory allocated by wintun.
///
/// So what I told you was true, from a certain point of view.
/// From the point of view of this packet, bytes' lifetime is 'static because we are always
/// dropped before the underlying memory is freed
///
/// Its also important to know that WintunAllocateSendPacket and WintunReceivePacket always
/// return sections of memory that never overlap, so we have exclusive access to the memory,
/// therefore mut is okay here.
pub(crate) bytes: &'static mut [u8],
/// Share ownership of session to prevent the session from being dropped before packets that
/// belong to it
pub(crate) session: Arc<session::Session>,
}
impl Packet {
/// Returns the bytes this packet holds as &mut.
/// The lifetime of the bytes is tied to the lifetime of this packet.
pub fn bytes_mut(&mut self) -> &mut [u8] {
self.bytes
}
/// Returns an immutable reference to the bytes this packet holds.
/// The lifetime of the bytes is tied to the lifetime of this packet.
pub fn bytes(&self) -> &[u8] {
self.bytes
}
}
impl Drop for Packet {
fn drop(&mut self) {
match self.kind {
Kind::ReceivePacket => {
unsafe {
//SAFETY:
//
// 1. We share ownership of the session therefore it hasn't been dropped yet
// 2. Bytes is valid because each packet holds exclusive access to a region of the
// ring buffer that the wintun session owns. We return that region of
// memory back to wintun here
self.session
.wintun
.WintunReleaseReceivePacket(self.session.session.0, self.bytes.as_ptr())
};
}
Kind::SendPacketPending => {
//If someone allocates a packet with session.allocate_send_packet() and then it is
//dropped without being sent, this will hold up the send queue because wintun expects
//that every allocated packet is sent
#[cfg(feature = "panic_on_unsent_packets")]
panic!("Packet was never sent!");
}
Kind::SendPacketSent => {
//Nop
}
}
}
}