1use libc::{CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, CMSG_SPACE, c_int, cmsghdr, msghdr};
2
3pub(crate) struct CMsgRef<'a>(&'a cmsghdr);
4
5impl CMsgRef<'_> {
6 pub(crate) fn level(&self) -> c_int {
7 self.0.cmsg_level
8 }
9
10 pub(crate) fn ty(&self) -> c_int {
11 self.0.cmsg_type
12 }
13
14 pub(crate) fn len(&self) -> usize {
15 self.0.cmsg_len as _
16 }
17
18 pub(crate) unsafe fn data<T>(&self) -> &T {
19 let data_ptr = CMSG_DATA(self.0);
20 data_ptr.cast::<T>().as_ref().unwrap()
21 }
22}
23
24pub(crate) struct CMsgMut<'a>(&'a mut cmsghdr);
25
26impl CMsgMut<'_> {
27 pub(crate) fn set_level(&mut self, level: c_int) {
28 self.0.cmsg_level = level;
29 }
30
31 pub(crate) fn set_ty(&mut self, ty: c_int) {
32 self.0.cmsg_type = ty;
33 }
34
35 pub(crate) unsafe fn set_data<T>(&mut self, data: T) -> usize {
36 self.0.cmsg_len = CMSG_LEN(std::mem::size_of::<T>() as _) as _;
37 let data_ptr = CMSG_DATA(self.0);
38 std::ptr::write(data_ptr.cast::<T>(), data);
39 CMSG_SPACE(std::mem::size_of::<T>() as _) as _
40 }
41}
42
43pub(crate) struct CMsgIter {
44 msg: msghdr,
45 cmsg: *mut cmsghdr,
46}
47
48impl CMsgIter {
49 pub(crate) fn new(ptr: *const u8, len: usize) -> Self {
50 assert!(len >= unsafe { CMSG_SPACE(0) as _ }, "buffer too short");
51 assert!(ptr.cast::<cmsghdr>().is_aligned(), "misaligned buffer");
52
53 let mut msg: msghdr = unsafe { std::mem::zeroed() };
54 msg.msg_control = ptr as _;
55 msg.msg_controllen = len as _;
56 let cmsg = unsafe { CMSG_FIRSTHDR(&msg) };
58 Self { msg, cmsg }
59 }
60
61 pub(crate) unsafe fn current<'a>(&self) -> Option<CMsgRef<'a>> {
62 self.cmsg.as_ref().map(CMsgRef)
63 }
64
65 pub(crate) unsafe fn next(&mut self) {
66 if !self.cmsg.is_null() {
67 self.cmsg = CMSG_NXTHDR(&self.msg, self.cmsg);
68 }
69 }
70
71 pub(crate) unsafe fn current_mut<'a>(&self) -> Option<CMsgMut<'a>> {
72 self.cmsg.as_mut().map(CMsgMut)
73 }
74
75 pub(crate) fn is_aligned<T>(&self) -> bool {
76 self.msg.msg_control.cast::<T>().is_aligned()
77 }
78
79 pub(crate) fn is_space_enough<T>(&self) -> bool {
80 if !self.cmsg.is_null() {
81 let space = unsafe { CMSG_SPACE(std::mem::size_of::<T>() as _) as usize };
82 #[allow(clippy::unnecessary_cast)]
83 let max = self.msg.msg_control as usize + self.msg.msg_controllen as usize;
84 self.cmsg as usize + space <= max
85 } else {
86 false
87 }
88 }
89}