netlink_socket2/
multicast.rs1use std::{io, mem::MaybeUninit, os::fd::AsRawFd, sync::Arc};
2
3use netlink_bindings::utils;
4
5use super::{sock::NetlinkReplyInner, NetlinkSocket, Socket};
6#[allow(unused_imports)]
7use super::{Read, Write};
8use crate::{ReplyError, RECV_BUF_SIZE};
9
10#[derive(Debug, Clone)]
11pub struct MulticastRecv {
12 pub multicast_group: u32,
13 pub message_type: u16,
14}
15
16pub struct MulticastSocketRaw {
17 buf: Arc<[u8; RECV_BUF_SIZE]>,
18 sock: Socket,
19 reply: NetlinkReplyInner,
20 last_group: Option<u32>,
21}
22
23struct WrapSendUnsafe<T>(T);
24unsafe impl<T> Send for WrapSendUnsafe<T> {}
25
26type WrapMsghdr = WrapSendUnsafe<libc::msghdr>;
27
28impl MulticastSocketRaw {
29 pub fn new(protonum: u16) -> io::Result<Self> {
30 let sock = NetlinkSocket::get_socket_new(protonum)?;
31
32 let res = unsafe {
34 libc::setsockopt(
35 sock.as_raw_fd(),
36 libc::SOL_NETLINK,
37 libc::NETLINK_PKTINFO,
38 &1u32 as *const u32 as *const libc::c_void,
39 4,
40 )
41 };
42 if res < 0 {
43 return Err(io::Error::from_raw_os_error(-res));
44 }
45
46 let mut buf: libc::sockaddr_nl = unsafe { std::mem::zeroed() };
47 buf.nl_family = libc::AF_NETLINK as u16;
48 buf.nl_groups = 0;
49
50 let res = unsafe {
51 libc::bind(
52 sock.as_raw_fd(),
53 &buf as *const _ as *const libc::sockaddr,
54 std::mem::size_of_val(&buf) as libc::socklen_t,
55 )
56 };
57 if res < 0 {
58 return Err(io::Error::last_os_error());
59 }
60
61 Ok(Self {
62 buf: Arc::new([0u8; RECV_BUF_SIZE]),
63 sock,
64 reply: NetlinkReplyInner {
65 buf_offset: 0,
66 buf_read: 0,
67 },
68 last_group: None,
69 })
70 }
71
72 pub fn listen(&mut self, group_id: u32) -> io::Result<()> {
73 let res = unsafe {
74 libc::setsockopt(
75 self.sock.as_raw_fd(),
76 libc::SOL_NETLINK,
77 libc::NETLINK_ADD_MEMBERSHIP,
78 &group_id as *const u32 as *const libc::c_void,
79 4,
80 )
81 };
82 if res < 0 {
83 return Err(io::Error::last_os_error());
84 }
85
86 Ok(())
87 }
88
89 #[super::strip_async]
90 pub async fn recv(&mut self) -> Result<(MulticastRecv, &[u8]), ReplyError> {
91 let buf = Arc::make_mut(&mut self.buf);
92
93 loop {
94 if self.reply.buf_offset == self.reply.buf_read {
95 let read = Self::read_buf(&self.sock, buf, &mut self.last_group).await?;
96 self.reply.buf_read = read;
97 self.reply.buf_offset = 0;
98 }
99
100 match self.reply.parse_next(buf).await {
101 Err(io_err) => {
102 return Err(io_err.into());
103 }
104 Ok((_seq, message_type, res)) => {
105 let Some(multicast_group) = self.last_group else {
111 continue;
112 };
113
114 match res {
115 Ok((l, r)) => {
116 return Ok((
117 MulticastRecv {
118 multicast_group,
119 message_type,
120 },
121 &self.buf[l..r],
122 ));
123 }
124 Err(mut err) => {
125 if err.code.raw_os_error().unwrap() == 0 {
126 continue;
127 }
128
129 if err.has_context() {
130 err.reply_buf = Some(self.buf.clone());
132 }
133
134 return Err(err);
135 }
136 };
137 }
138 };
139 }
140 }
141
142 #[super::strip_async]
143 async fn read_buf(
144 sock: &Socket,
145 buf: &mut [u8],
146 last_group: &mut Option<u32>,
147 ) -> Result<usize, ReplyError> {
148 let mut iov = WrapSendUnsafe(libc::iovec {
149 iov_base: buf.as_mut_ptr() as *mut libc::c_void,
150 iov_len: buf.len(),
151 });
152
153 const CONTROL_BUF_LEN: usize = 128;
154 let mut control_buf = MaybeUninit::<[u8; CONTROL_BUF_LEN]>::uninit();
155
156 let mut msghdr: libc::msghdr = unsafe { std::mem::zeroed() };
159 msghdr.msg_name = std::ptr::null_mut();
160 msghdr.msg_namelen = 0;
161 msghdr.msg_iov = &raw mut iov.0;
162 msghdr.msg_iovlen = 1;
163 msghdr.msg_control = control_buf.as_mut_ptr() as *mut libc::c_void;
164 msghdr.msg_controllen = CONTROL_BUF_LEN as _;
166 msghdr.msg_flags = 0;
167
168 let mut msghdr = WrapSendUnsafe(msghdr);
169 let read = Self::recvmsg(&sock, &mut msghdr).await?;
170
171 *last_group = None;
172 unsafe {
173 let msghdr_ptr = &raw const msghdr.0;
174 let mut cmsg_ptr: *const libc::cmsghdr = libc::CMSG_FIRSTHDR(msghdr_ptr);
175 while !cmsg_ptr.is_null() {
176 let libc::cmsghdr {
177 cmsg_len,
178 cmsg_level,
179 cmsg_type,
180 .. } = *cmsg_ptr;
182
183 match (cmsg_level, cmsg_type) {
184 (libc::SOL_NETLINK, libc::NETLINK_PKTINFO) => {
185 let data = std::slice::from_raw_parts(
186 libc::CMSG_DATA(cmsg_ptr),
187 cmsg_len as usize - libc::CMSG_LEN(0) as usize,
188 );
189 *last_group = Some(utils::parse_u32(&data[..4]).unwrap());
190 }
191 _ => {}
192 }
193
194 cmsg_ptr = libc::CMSG_NXTHDR(msghdr_ptr, cmsg_ptr);
195 }
196 }
197
198 Ok(read)
199 }
200
201 fn recvmsg_sync(sock: &Socket, msghdr: &mut WrapMsghdr) -> io::Result<usize> {
202 unsafe {
203 let res = libc::recvmsg(sock.as_raw_fd(), &mut msghdr.0, 0);
204 if res < 0 {
205 return Err(io::Error::last_os_error());
206 }
207 Ok(res as usize)
208 }
209 }
210
211 #[super::only_sync]
212 fn recvmsg(sock: &Socket, msghdr: &mut WrapMsghdr) -> io::Result<usize> {
213 Self::recvmsg_sync(sock, msghdr)
214 }
215
216 #[super::only_async]
217 #[super::not_tokio]
218 async fn recvmsg(sock: &Socket, msghdr: &mut WrapMsghdr) -> io::Result<usize> {
219 loop {
220 match Self::recvmsg_sync(sock, msghdr) {
221 Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {
222 sock.readable().await?;
223 continue;
224 }
225 res => return res,
226 }
227 }
228 }
229
230 #[super::only_async]
231 #[super::only_tokio]
232 async fn recvmsg(sock: &Socket, msghdr: &mut WrapMsghdr) -> io::Result<usize> {
233 sock.async_io(tokio::io::Interest::READABLE, || {
235 Self::recvmsg_sync(sock, msghdr)
236 })
237 .await
238 }
239}