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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::*;
use std::{
convert::{TryFrom, TryInto},
mem,
};
#[cfg(any(target_os = "dragonfly", target_os = "macos", target_os = "ios"))]
const ALIGN: usize = 4 - 1;
#[cfg(any(
target_os = "linux",
all(
target_os = "freebsd",
any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc64",
target_arch = "x86",
target_arch = "x86_64"
)
),
all(
target_os = "openbsd",
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
),
))]
const ALIGN: usize = mem::size_of::<usize>() - 1;
const fn align(size: usize) -> usize {
(size + ALIGN) & !ALIGN
}
const HDR_SIZE: usize = mem::size_of::<c::cmsghdr>();
#[repr(C)]
union HdrBytes {
hdr: c::cmsghdr,
bytes: [u8; align(HDR_SIZE)],
}
pub const fn cmsg_space(data_len: usize) -> usize {
align(HDR_SIZE) + align(data_len)
}
pub fn cmsg_read<'a>(buf: &mut &'a [u8]) -> Result<(usize, c::cmsghdr, &'a [u8])> {
if buf.len() < align(HDR_SIZE) {
return einval();
}
let mut hdr_bytes = HdrBytes {
bytes: [0; align(HDR_SIZE)],
};
unsafe {
hdr_bytes.bytes.copy_from_slice(&buf[..align(HDR_SIZE)]);
}
let hdr = unsafe { hdr_bytes.hdr };
let cmsg_len = match usize::try_from(hdr.cmsg_len) {
Ok(l) => l,
_ => return einval(),
};
if cmsg_len < align(HDR_SIZE) {
return einval();
}
if usize::max_value() - cmsg_len < ALIGN {
return einval();
}
let cmsg_space = align(cmsg_len);
if buf.len() < cmsg_space {
return einval();
}
let data = &buf[align(HDR_SIZE)..cmsg_len];
*buf = &buf[cmsg_space..];
Ok((cmsg_space, hdr, data))
}
pub fn cmsg_write<T: ?Sized>(
buf: &mut &mut [u8],
mut hdr: c::cmsghdr,
data: &T,
) -> Result<usize> {
let data_size = mem::size_of_val(data);
let cmsg_space = cmsg_space(data_size);
if buf.len() < cmsg_space {
return einval();
}
hdr.cmsg_len = match (align(HDR_SIZE) + data_size).try_into() {
Ok(v) => v,
Err(_) => return einval(),
};
let ptr = buf.as_mut_ptr();
unsafe {
ptr.copy_from_nonoverlapping(&hdr as *const _ as *const _, HDR_SIZE);
ptr.add(align(HDR_SIZE))
.copy_from_nonoverlapping(data as *const _ as *const _, data_size);
black_box(ptr);
}
*buf = &mut mem::replace(buf, &mut [])[cmsg_space..];
Ok(cmsg_space)
}