netstack3_datagram/
sndbuf.rs1use core::borrow::Borrow;
8use core::mem::ManuallyDrop;
9
10use derivative::Derivative;
11use net_types::ip::{GenericOverIp, Ip, IpVersion};
12use netstack3_base::socket::{SendBufferFullError, SendBufferSpace};
13use netstack3_base::{PositiveIsize, WeakDeviceIdentifier};
14use packet::FragmentedBuffer;
15
16use crate::internal::datagram::{DatagramSocketSpec, IpExt};
17use crate::internal::settings::DatagramSettings;
18
19#[derive(Derivative)]
20#[derivative(Debug(bound = ""))]
21pub(crate) struct SendBufferTracking<S: DatagramSocketSpec>(
22 netstack3_base::socket::SendBufferTracking<S::SocketWritableListener>,
23);
24
25pub(crate) enum SendBufferError {
26 SendBufferFull,
27 InvalidLength,
28}
29
30impl From<SendBufferFullError> for SendBufferError {
31 fn from(SendBufferFullError: SendBufferFullError) -> Self {
32 Self::SendBufferFull
33 }
34}
35
36impl<S: DatagramSocketSpec> SendBufferTracking<S> {
37 pub(crate) fn new(listener: S::SocketWritableListener, settings: &DatagramSettings) -> Self {
38 Self(netstack3_base::socket::SendBufferTracking::new(
39 settings.send_buffer.default(),
40 listener,
41 ))
42 }
43
44 pub(crate) fn set_capacity(&self, capacity: usize, settings: &DatagramSettings) {
45 let Self(tracking) = self;
46 let capacity = PositiveIsize::new_unsigned(capacity.max(settings.send_buffer.min().into()))
47 .unwrap_or_else(|| settings.send_buffer.max())
48 .min(settings.send_buffer.max());
49 tracking.set_capacity(capacity);
50 }
51
52 pub(crate) fn capacity(&self) -> usize {
53 let Self(tracking) = self;
54 tracking.capacity().into()
55 }
56
57 #[cfg(any(test, feature = "testutils"))]
58 pub(crate) fn available(&self) -> usize {
59 let Self(tracking) = self;
60 tracking.available().map(Into::into).unwrap_or(0)
61 }
62
63 pub(crate) fn prepare_for_send<
64 WireI: Ip,
65 SocketI: IpExt,
66 D: WeakDeviceIdentifier,
67 B: FragmentedBuffer,
68 >(
69 &self,
70 id: &S::SocketId<SocketI, D>,
71 buffer: &B,
72 ) -> Result<TxMetadata<SocketI, D, S>, SendBufferError> {
73 let header_len = match WireI::VERSION {
75 IpVersion::V4 => packet_formats::ipv4::HDR_PREFIX_LEN,
76 IpVersion::V6 => packet_formats::ipv6::IPV6_FIXED_HDR_LEN,
77 } + S::FIXED_HEADER_SIZE;
78 self.prepare_for_send_inner(buffer.len() + header_len, id)
79 }
80
81 fn prepare_for_send_inner<I: IpExt, D: WeakDeviceIdentifier>(
82 &self,
83 size: usize,
84 id: &S::SocketId<I, D>,
85 ) -> Result<TxMetadata<I, D, S>, SendBufferError> {
86 let Self(tracking) = self;
87 let size = PositiveIsize::new_unsigned(size).ok_or(SendBufferError::InvalidLength)?;
89 let space = tracking.acquire(size)?;
90 Ok(TxMetadata { socket: S::downgrade_socket_id(id), space: ManuallyDrop::new(space) })
91 }
92}
93
94#[derive(Derivative, GenericOverIp)]
96#[generic_over_ip(I, Ip)]
97#[derivative(Debug(bound = ""))]
98pub struct TxMetadata<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
99 socket: S::WeakSocketId<I, D>,
100 space: ManuallyDrop<SendBufferSpace>,
101}
102
103impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> TxMetadata<I, D, S> {
104 pub fn socket(&self) -> &S::WeakSocketId<I, D> {
106 &self.socket
107 }
108}
109
110impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> Drop for TxMetadata<I, D, S> {
111 fn drop(&mut self) {
112 let Self { socket, space } = self;
113 let space = unsafe { ManuallyDrop::take(space) };
118 match S::upgrade_socket_id(socket) {
119 Some(socket) => {
120 let SendBufferTracking(tracking) = &socket.borrow().send_buffer;
121 tracking.release(space)
122 }
123 None => {
124 space.acknowledge_drop();
127 }
128 }
129 }
130}
131
132#[cfg(any(test, feature = "testutils"))]
133impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> PartialEq for TxMetadata<I, D, S> {
134 fn eq(&self, other: &Self) -> bool {
135 core::ptr::eq(self, other)
139 }
140}