1use std::{
2 ffi::{c_int, c_uchar},
3 ptr,
4 sync::atomic::{AtomicBool, Ordering},
5};
6
7#[cfg(unix)]
8#[path = "unix.rs"]
9mod imp;
10
11#[cfg(windows)]
12#[path = "windows.rs"]
13mod imp;
14
15pub(crate) use imp::{PAYLOAD_ALIGN, RecvBuf, SendBuf};
16
17pub(crate) struct Encoder<'a, M: MsgHdr> {
23 hdr: &'a mut M,
24 cmsg: Option<&'a mut M::ControlMessage>,
25 len: usize,
26}
27
28impl<'a, M: MsgHdr> Encoder<'a, M> {
29 pub(crate) unsafe fn new(hdr: &'a mut M) -> Self {
34 Self {
35 cmsg: unsafe { hdr.cmsg_first_hdr().as_mut() },
36 hdr,
37 len: 0,
38 }
39 }
40
41 fn push<T: Copy>(&mut self, level: c_int, ty: c_int, value: T) {
48 const {
49 assert!(
50 align_of::<T>() <= PAYLOAD_ALIGN,
51 "control message payload is more aligned than a control message buffer can be",
52 );
53 }
54 let space = M::ControlMessage::cmsg_space(size_of_val(&value));
55 assert!(
56 self.hdr.control_len() >= self.len + space,
57 "control message buffer too small. Required: {}, Available: {}",
58 self.len + space,
59 self.hdr.control_len()
60 );
61 let cmsg = self.cmsg.take().expect("no control buffer space remaining");
62 cmsg.set(level, ty, M::ControlMessage::cmsg_len(size_of_val(&value)));
63 unsafe {
64 ptr::write(cmsg.cmsg_data() as *const T as *mut T, value);
65 }
66 self.len += space;
67 self.cmsg = unsafe { self.hdr.cmsg_nxt_hdr(cmsg).as_mut() };
68 }
69
70 pub(crate) fn finish(self) {
72 }
74}
75
76impl<M: MsgHdr> Drop for Encoder<'_, M> {
79 fn drop(&mut self) {
80 self.hdr.set_control_len(self.len as _);
81 }
82}
83
84pub(crate) fn warn_if_control_truncated(hdr: &impl MsgHdr) {
90 static WARNED: AtomicBool = AtomicBool::new(false);
91
92 if hdr.recv_flags() & imp::MSG_CTRUNC != 0 && !WARNED.swap(true, Ordering::Relaxed) {
93 crate::log::warn!(
94 "control messages truncated on receive, some datagram metadata was dropped"
95 );
96 }
97}
98
99pub(crate) unsafe fn decode<T: Copy, C: CMsgHdr>(cmsg: &impl CMsgHdr) -> T {
103 const {
104 assert!(
105 align_of::<T>() <= PAYLOAD_ALIGN,
106 "control message payload is more aligned than a control message buffer can be",
107 );
108 }
109 debug_assert_eq!(cmsg.len(), C::cmsg_len(size_of::<T>()));
110 unsafe { ptr::read(cmsg.cmsg_data() as *const T) }
111}
112
113pub(crate) struct Iter<'a, M: MsgHdr> {
114 hdr: &'a M,
115 cmsg: Option<&'a M::ControlMessage>,
116}
117
118impl<'a, M: MsgHdr> Iter<'a, M> {
119 pub(crate) unsafe fn new(hdr: &'a M) -> Self {
125 Self {
126 hdr,
127 cmsg: unsafe { hdr.cmsg_first_hdr().as_ref() },
128 }
129 }
130}
131
132impl<'a, M: MsgHdr> Iterator for Iter<'a, M> {
133 type Item = &'a M::ControlMessage;
134
135 fn next(&mut self) -> Option<Self::Item> {
136 let current = self.cmsg.take()?;
137 self.cmsg = unsafe { self.hdr.cmsg_nxt_hdr(current).as_ref() };
138
139 #[cfg(apple_fast)]
140 {
141 if current.len() < size_of::<M::ControlMessage>() {
145 return None;
146 }
147 }
148
149 Some(current)
150 }
151}
152
153pub(crate) trait MsgHdr {
155 type ControlMessage: CMsgHdr;
156
157 fn cmsg_first_hdr(&self) -> *mut Self::ControlMessage;
158
159 fn cmsg_nxt_hdr(&self, cmsg: &Self::ControlMessage) -> *mut Self::ControlMessage;
160
161 fn set_control_len(&mut self, len: usize);
166
167 fn control_len(&self) -> usize;
168
169 fn recv_flags(&self) -> c_int;
171}
172
173pub(crate) trait CMsgHdr {
174 fn cmsg_len(length: usize) -> usize;
175
176 fn cmsg_space(length: usize) -> usize;
177
178 fn cmsg_data(&self) -> *mut c_uchar;
179
180 fn set(&mut self, level: c_int, ty: c_int, len: usize);
181
182 fn len(&self) -> usize;
183}