compio_net/cmsg/
unix.rs

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        // SAFETY: msg is initialized and valid
57        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}