dope_uring/sockets/
source.rs1use std::{mem, net, ptr, slice};
2
3use dope_sys::io::socket::msg::source;
4
5use crate::{Uring, sockets::controls};
6
7const V4: usize = unsafe { libc::CMSG_SPACE(mem::size_of::<libc::in_pktinfo>() as u32) as usize };
9const V6: usize = unsafe { libc::CMSG_SPACE(mem::size_of::<libc::in6_pktinfo>() as u32) as usize };
10
11#[derive(Clone, Copy, Debug)]
13#[repr(C, align(8))]
14pub struct Control {
15 bytes: [u8; V6],
16}
17
18#[repr(transparent)]
20pub struct Combined(Kind);
21
22enum Kind {
23 Source(Control),
24 Segmented(Segmented),
25}
26
27#[repr(C)]
29struct Segmented {
30 gso: controls::Control,
31 source: Control,
32}
33
34impl source::Source for Uring {
35 type Control = Control;
36 type Combined = Combined;
37
38 fn control(source: source::Address) -> Self::Control {
39 let address = source.get();
40 let mut control = Control { bytes: [0; V6] };
41 let header = control.bytes.as_mut_ptr().cast::<libc::cmsghdr>();
42 unsafe {
45 let payload = libc::CMSG_DATA(header);
46 let length = match address {
47 net::SocketAddr::V4(address) => {
48 (*header).cmsg_level = libc::IPPROTO_IP;
49 (*header).cmsg_type = libc::IP_PKTINFO;
50 payload.cast::<libc::in_pktinfo>().write(libc::in_pktinfo {
51 ipi_ifindex: 0,
52 ipi_spec_dst: libc::in_addr {
53 s_addr: u32::from_ne_bytes(address.ip().octets()),
54 },
55 ipi_addr: libc::in_addr { s_addr: 0 },
56 });
57 mem::size_of::<libc::in_pktinfo>()
58 }
59 net::SocketAddr::V6(address) => {
60 (*header).cmsg_level = libc::IPPROTO_IPV6;
61 (*header).cmsg_type = libc::IPV6_PKTINFO;
62 payload
63 .cast::<libc::in6_pktinfo>()
64 .write(libc::in6_pktinfo {
65 ipi6_addr: libc::in6_addr {
66 s6_addr: address.ip().octets(),
67 },
68 ipi6_ifindex: address.scope_id(),
69 });
70 mem::size_of::<libc::in6_pktinfo>()
71 }
72 };
73 (*header).cmsg_len = libc::CMSG_LEN(length as u32) as _;
74 }
75 control
76 }
77
78 fn compose(source: Control, gso: Option<controls::Control>) -> Combined {
79 Combined(match gso {
80 Some(gso) => Kind::Segmented(Segmented { gso, source }),
81 None => Kind::Source(source),
82 })
83 }
84
85 fn release(control: Combined) -> (Control, Option<controls::Control>) {
86 match control.0 {
87 Kind::Source(source) => (source, None),
88 Kind::Segmented(control) => (control.source, Some(control.gso)),
89 }
90 }
91
92 fn bytes(control: &mut Combined) -> &[u8] {
93 match &control.0 {
94 Kind::Source(source) => source.as_ref(),
95 Kind::Segmented(control) => {
96 let length = mem::size_of::<controls::Control>() + control.source.as_ref().len();
97 unsafe { slice::from_raw_parts(ptr::from_ref(control).cast(), length) }
101 }
102 }
103 }
104}
105
106impl AsRef<[u8]> for Control {
107 fn as_ref(&self) -> &[u8] {
108 unsafe {
112 let length = (*self.bytes.as_ptr().cast::<libc::cmsghdr>()).cmsg_len;
113 slice::from_raw_parts(self.bytes.as_ptr(), length)
114 }
115 }
116}
117
118const _: () = {
119 assert!(V4 <= V6);
120 assert!(mem::size_of::<libc::in_pktinfo>() == 12);
121 assert!(mem::size_of::<libc::in6_pktinfo>() == 20);
122 assert!(mem::align_of::<Control>() >= mem::align_of::<libc::cmsghdr>());
123 assert!(mem::align_of::<Control>() >= mem::align_of::<libc::in_pktinfo>());
124 assert!(mem::align_of::<Control>() >= mem::align_of::<libc::in6_pktinfo>());
125 assert!(mem::size_of::<Control>() == 40);
126 assert!(mem::offset_of!(Segmented, gso) == 0);
127 assert!(mem::offset_of!(Segmented, source) == mem::size_of::<controls::Control>());
128 assert!(
129 mem::size_of::<Segmented>()
130 == mem::size_of::<controls::Control>() + mem::size_of::<Control>()
131 );
132 assert!(mem::align_of::<Segmented>() == mem::align_of::<Control>());
133};