1 | //! [`recvmsg`], [`sendmsg`], and related functions. |
2 | |
3 | #![allow (unsafe_code)] |
4 | |
5 | use crate::backend::{self, c}; |
6 | use crate::fd::{AsFd, BorrowedFd, OwnedFd}; |
7 | use crate::io::{self, IoSlice, IoSliceMut}; |
8 | #[cfg (linux_kernel)] |
9 | use crate::net::UCred; |
10 | |
11 | use core::iter::FusedIterator; |
12 | use core::marker::PhantomData; |
13 | use core::mem::{align_of, size_of, size_of_val, take}; |
14 | #[cfg (linux_kernel)] |
15 | use core::ptr::addr_of; |
16 | use core::{ptr, slice}; |
17 | |
18 | use super::{RecvFlags, SendFlags, SocketAddrAny, SocketAddrV4, SocketAddrV6}; |
19 | |
20 | /// Macro for defining the amount of space to allocate in a buffer for use with |
21 | /// [`RecvAncillaryBuffer::new`] and [`SendAncillaryBuffer::new`]. |
22 | /// |
23 | /// # Examples |
24 | /// |
25 | /// Allocate a buffer for a single file descriptor: |
26 | /// ``` |
27 | /// # use rustix::cmsg_space; |
28 | /// let mut space = [0; rustix::cmsg_space!(ScmRights(1))]; |
29 | /// ``` |
30 | /// |
31 | /// Allocate a buffer for credentials: |
32 | /// ``` |
33 | /// # #[cfg (linux_kernel)] |
34 | /// # { |
35 | /// # use rustix::cmsg_space; |
36 | /// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))]; |
37 | /// # } |
38 | /// ``` |
39 | /// |
40 | /// Allocate a buffer for two file descriptors and credentials: |
41 | /// ``` |
42 | /// # #[cfg (linux_kernel)] |
43 | /// # { |
44 | /// # use rustix::cmsg_space; |
45 | /// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))]; |
46 | /// # } |
47 | /// ``` |
48 | #[macro_export ] |
49 | macro_rules! cmsg_space { |
50 | // Base Rules |
51 | (ScmRights($len:expr)) => { |
52 | $crate::net::__cmsg_space( |
53 | $len * ::core::mem::size_of::<$crate::fd::BorrowedFd<'static>>(), |
54 | ) |
55 | }; |
56 | (ScmCredentials($len:expr)) => { |
57 | $crate::net::__cmsg_space( |
58 | $len * ::core::mem::size_of::<$crate::net::UCred>(), |
59 | ) |
60 | }; |
61 | |
62 | // Combo Rules |
63 | ($firstid:ident($firstex:expr), $($restid:ident($restex:expr)),*) => {{ |
64 | // We only have to add `cmsghdr` alignment once; all other times we can |
65 | // use `cmsg_aligned_space`. |
66 | let sum = $crate::cmsg_space!($firstid($firstex)); |
67 | $( |
68 | let sum = sum + $crate::cmsg_aligned_space!($restid($restex)); |
69 | )* |
70 | sum |
71 | }}; |
72 | } |
73 | |
74 | /// Like `cmsg_space`, but doesn't add padding for `cmsghdr` alignment. |
75 | #[doc (hidden)] |
76 | #[macro_export ] |
77 | macro_rules! cmsg_aligned_space { |
78 | // Base Rules |
79 | (ScmRights($len:expr)) => { |
80 | $crate::net::__cmsg_aligned_space( |
81 | $len * ::core::mem::size_of::<$crate::fd::BorrowedFd<'static>>(), |
82 | ) |
83 | }; |
84 | (ScmCredentials($len:expr)) => { |
85 | $crate::net::__cmsg_aligned_space( |
86 | $len * ::core::mem::size_of::<$crate::net::UCred>(), |
87 | ) |
88 | }; |
89 | |
90 | // Combo Rules |
91 | ($firstid:ident($firstex:expr), $($restid:ident($restex:expr)),*) => {{ |
92 | let sum = cmsg_aligned_space!($firstid($firstex)); |
93 | $( |
94 | let sum = sum + cmsg_aligned_space!($restid($restex)); |
95 | )* |
96 | sum |
97 | }}; |
98 | } |
99 | |
100 | /// Helper function for [`cmsg_space`]. |
101 | #[doc (hidden)] |
102 | pub const fn __cmsg_space(len: usize) -> usize { |
103 | // Add `align_of::<c::cmsghdr>()` so that we can align the user-provided |
104 | // `&[u8]` to the required alignment boundary. |
105 | let len: usize = len + align_of::<c::cmsghdr>(); |
106 | |
107 | __cmsg_aligned_space(len) |
108 | } |
109 | |
110 | /// Helper function for [`cmsg_aligned_space`]. |
111 | #[doc (hidden)] |
112 | pub const fn __cmsg_aligned_space(len: usize) -> usize { |
113 | // Convert `len` to `u32` for `CMSG_SPACE`. This would be `try_into()` if |
114 | // we could call that in a `const fn`. |
115 | let converted_len: u32 = len as u32; |
116 | if converted_len as usize != len { |
117 | unreachable!(); // `CMSG_SPACE` size overflow |
118 | } |
119 | |
120 | unsafe { c::CMSG_SPACE(converted_len) as usize } |
121 | } |
122 | |
123 | /// Ancillary message for [`sendmsg`], [`sendmsg_v4`], [`sendmsg_v6`], |
124 | /// [`sendmsg_unix`], and [`sendmsg_any`]. |
125 | #[non_exhaustive ] |
126 | pub enum SendAncillaryMessage<'slice, 'fd> { |
127 | /// Send file descriptors. |
128 | #[doc (alias = "SCM_RIGHTS" )] |
129 | ScmRights(&'slice [BorrowedFd<'fd>]), |
130 | /// Send process credentials. |
131 | #[cfg (linux_kernel)] |
132 | #[doc (alias = "SCM_CREDENTIAL" )] |
133 | ScmCredentials(UCred), |
134 | } |
135 | |
136 | impl SendAncillaryMessage<'_, '_> { |
137 | /// Get the maximum size of an ancillary message. |
138 | /// |
139 | /// This can be helpful in determining the size of the buffer you allocate. |
140 | pub const fn size(&self) -> usize { |
141 | match self { |
142 | Self::ScmRights(slice: &&[BorrowedFd<'_>]) => cmsg_space!(ScmRights(slice.len())), |
143 | #[cfg (linux_kernel)] |
144 | Self::ScmCredentials(_) => cmsg_space!(ScmCredentials(1)), |
145 | } |
146 | } |
147 | } |
148 | |
149 | /// Ancillary message for [`recvmsg`]. |
150 | #[non_exhaustive ] |
151 | pub enum RecvAncillaryMessage<'a> { |
152 | /// Received file descriptors. |
153 | #[doc (alias = "SCM_RIGHTS" )] |
154 | ScmRights(AncillaryIter<'a, OwnedFd>), |
155 | /// Received process credentials. |
156 | #[cfg (linux_kernel)] |
157 | #[doc (alias = "SCM_CREDENTIALS" )] |
158 | ScmCredentials(UCred), |
159 | } |
160 | |
161 | /// Buffer for sending ancillary messages with [`sendmsg`], [`sendmsg_v4`], |
162 | /// [`sendmsg_v6`], [`sendmsg_unix`], and [`sendmsg_any`]. |
163 | /// |
164 | /// Use the [`push`] function to add messages to send. |
165 | /// |
166 | /// [`push`]: SendAncillaryBuffer::push |
167 | pub struct SendAncillaryBuffer<'buf, 'slice, 'fd> { |
168 | /// Raw byte buffer for messages. |
169 | buffer: &'buf mut [u8], |
170 | |
171 | /// The amount of the buffer that is used. |
172 | length: usize, |
173 | |
174 | /// Phantom data for lifetime of `&'slice [BorrowedFd<'fd>]`. |
175 | _phantom: PhantomData<&'slice [BorrowedFd<'fd>]>, |
176 | } |
177 | |
178 | impl<'buf> From<&'buf mut [u8]> for SendAncillaryBuffer<'buf, '_, '_> { |
179 | fn from(buffer: &'buf mut [u8]) -> Self { |
180 | Self::new(buffer) |
181 | } |
182 | } |
183 | |
184 | impl Default for SendAncillaryBuffer<'_, '_, '_> { |
185 | fn default() -> Self { |
186 | Self { |
187 | buffer: &mut [], |
188 | length: 0, |
189 | _phantom: PhantomData, |
190 | } |
191 | } |
192 | } |
193 | |
194 | impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> { |
195 | /// Create a new, empty `SendAncillaryBuffer` from a raw byte buffer. |
196 | /// |
197 | /// The buffer size may be computed with [`cmsg_space`], or it may be |
198 | /// zero for an empty buffer, however in that case, consider `default()` |
199 | /// instead, or even using [`send`] instead of `sendmsg`. |
200 | /// |
201 | /// # Examples |
202 | /// |
203 | /// Allocate a buffer for a single file descriptor: |
204 | /// ``` |
205 | /// # use rustix::cmsg_space; |
206 | /// # use rustix::net::SendAncillaryBuffer; |
207 | /// let mut space = [0; rustix::cmsg_space!(ScmRights(1))]; |
208 | /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space); |
209 | /// ``` |
210 | /// |
211 | /// Allocate a buffer for credentials: |
212 | /// ``` |
213 | /// # #[cfg (linux_kernel)] |
214 | /// # { |
215 | /// # use rustix::cmsg_space; |
216 | /// # use rustix::net::SendAncillaryBuffer; |
217 | /// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))]; |
218 | /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space); |
219 | /// # } |
220 | /// ``` |
221 | /// |
222 | /// Allocate a buffer for two file descriptors and credentials: |
223 | /// ``` |
224 | /// # #[cfg (linux_kernel)] |
225 | /// # { |
226 | /// # use rustix::cmsg_space; |
227 | /// # use rustix::net::SendAncillaryBuffer; |
228 | /// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))]; |
229 | /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space); |
230 | /// # } |
231 | /// ``` |
232 | /// |
233 | /// [`send`]: crate::net::send |
234 | #[inline ] |
235 | pub fn new(buffer: &'buf mut [u8]) -> Self { |
236 | Self { |
237 | buffer: align_for_cmsghdr(buffer), |
238 | length: 0, |
239 | _phantom: PhantomData, |
240 | } |
241 | } |
242 | |
243 | /// Returns a pointer to the message data. |
244 | pub(crate) fn as_control_ptr(&mut self) -> *mut u8 { |
245 | // When the length is zero, we may be using a `&[]` address, which may |
246 | // be an invalid but non-null pointer, and on some platforms, that |
247 | // causes `sendmsg` to fail with `EFAULT` or `EINVAL` |
248 | #[cfg (not(linux_kernel))] |
249 | if self.length == 0 { |
250 | return core::ptr::null_mut(); |
251 | } |
252 | |
253 | self.buffer.as_mut_ptr() |
254 | } |
255 | |
256 | /// Returns the length of the message data. |
257 | pub(crate) fn control_len(&self) -> usize { |
258 | self.length |
259 | } |
260 | |
261 | /// Delete all messages from the buffer. |
262 | pub fn clear(&mut self) { |
263 | self.length = 0; |
264 | } |
265 | |
266 | /// Add an ancillary message to the buffer. |
267 | /// |
268 | /// Returns `true` if the message was added successfully. |
269 | pub fn push(&mut self, msg: SendAncillaryMessage<'slice, 'fd>) -> bool { |
270 | match msg { |
271 | SendAncillaryMessage::ScmRights(fds) => { |
272 | let fds_bytes = |
273 | unsafe { slice::from_raw_parts(fds.as_ptr().cast::<u8>(), size_of_val(fds)) }; |
274 | self.push_ancillary(fds_bytes, c::SOL_SOCKET as _, c::SCM_RIGHTS as _) |
275 | } |
276 | #[cfg (linux_kernel)] |
277 | SendAncillaryMessage::ScmCredentials(ucred) => { |
278 | let ucred_bytes = unsafe { |
279 | slice::from_raw_parts(addr_of!(ucred).cast::<u8>(), size_of_val(&ucred)) |
280 | }; |
281 | self.push_ancillary(ucred_bytes, c::SOL_SOCKET as _, c::SCM_CREDENTIALS as _) |
282 | } |
283 | } |
284 | } |
285 | |
286 | /// Pushes an ancillary message to the buffer. |
287 | fn push_ancillary(&mut self, source: &[u8], cmsg_level: c::c_int, cmsg_type: c::c_int) -> bool { |
288 | macro_rules! leap { |
289 | ($e:expr) => {{ |
290 | match ($e) { |
291 | Some(x) => x, |
292 | None => return false, |
293 | } |
294 | }}; |
295 | } |
296 | |
297 | // Calculate the length of the message. |
298 | let source_len = leap!(u32::try_from(source.len()).ok()); |
299 | |
300 | // Calculate the new length of the buffer. |
301 | let additional_space = unsafe { c::CMSG_SPACE(source_len) }; |
302 | let new_length = leap!(self.length.checked_add(additional_space as usize)); |
303 | let buffer = leap!(self.buffer.get_mut(..new_length)); |
304 | |
305 | // Fill the new part of the buffer with zeroes. |
306 | buffer[self.length..new_length].fill(0); |
307 | self.length = new_length; |
308 | |
309 | // Get the last header in the buffer. |
310 | let last_header = leap!(messages::Messages::new(buffer).last()); |
311 | |
312 | // Set the header fields. |
313 | last_header.cmsg_len = unsafe { c::CMSG_LEN(source_len) } as _; |
314 | last_header.cmsg_level = cmsg_level; |
315 | last_header.cmsg_type = cmsg_type; |
316 | |
317 | // Get the pointer to the payload and copy the data. |
318 | unsafe { |
319 | let payload = c::CMSG_DATA(last_header); |
320 | ptr::copy_nonoverlapping(source.as_ptr(), payload, source_len as _); |
321 | } |
322 | |
323 | true |
324 | } |
325 | } |
326 | |
327 | impl<'slice, 'fd> Extend<SendAncillaryMessage<'slice, 'fd>> |
328 | for SendAncillaryBuffer<'_, 'slice, 'fd> |
329 | { |
330 | fn extend<T: IntoIterator<Item = SendAncillaryMessage<'slice, 'fd>>>(&mut self, iter: T) { |
331 | // TODO: This could be optimized to add every message in one go. |
332 | iter.into_iter().all(|msg: SendAncillaryMessage<'slice, 'fd>| self.push(msg)); |
333 | } |
334 | } |
335 | |
336 | /// Buffer for receiving ancillary messages with [`recvmsg`]. |
337 | /// |
338 | /// Use the [`drain`] function to iterate over the received messages. |
339 | /// |
340 | /// [`drain`]: RecvAncillaryBuffer::drain |
341 | #[derive (Default)] |
342 | pub struct RecvAncillaryBuffer<'buf> { |
343 | /// Raw byte buffer for messages. |
344 | buffer: &'buf mut [u8], |
345 | |
346 | /// The portion of the buffer we've read from already. |
347 | read: usize, |
348 | |
349 | /// The amount of the buffer that is used. |
350 | length: usize, |
351 | } |
352 | |
353 | impl<'buf> From<&'buf mut [u8]> for RecvAncillaryBuffer<'buf> { |
354 | fn from(buffer: &'buf mut [u8]) -> Self { |
355 | Self::new(buffer) |
356 | } |
357 | } |
358 | |
359 | impl<'buf> RecvAncillaryBuffer<'buf> { |
360 | /// Create a new, empty `RecvAncillaryBuffer` from a raw byte buffer. |
361 | /// |
362 | /// The buffer size may be computed with [`cmsg_space`], or it may be |
363 | /// zero for an empty buffer, however in that case, consider `default()` |
364 | /// instead, or even using [`recv`] instead of `recvmsg`. |
365 | /// |
366 | /// # Examples |
367 | /// |
368 | /// Allocate a buffer for a single file descriptor: |
369 | /// ``` |
370 | /// # use rustix::cmsg_space; |
371 | /// # use rustix::net::RecvAncillaryBuffer; |
372 | /// let mut space = [0; rustix::cmsg_space!(ScmRights(1))]; |
373 | /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space); |
374 | /// ``` |
375 | /// |
376 | /// Allocate a buffer for credentials: |
377 | /// ``` |
378 | /// # #[cfg (linux_kernel)] |
379 | /// # { |
380 | /// # use rustix::cmsg_space; |
381 | /// # use rustix::net::RecvAncillaryBuffer; |
382 | /// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))]; |
383 | /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space); |
384 | /// # } |
385 | /// ``` |
386 | /// |
387 | /// Allocate a buffer for two file descriptors and credentials: |
388 | /// ``` |
389 | /// # #[cfg (linux_kernel)] |
390 | /// # { |
391 | /// # use rustix::cmsg_space; |
392 | /// # use rustix::net::RecvAncillaryBuffer; |
393 | /// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))]; |
394 | /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space); |
395 | /// # } |
396 | /// ``` |
397 | /// |
398 | /// [`recv`]: crate::net::recv |
399 | #[inline ] |
400 | pub fn new(buffer: &'buf mut [u8]) -> Self { |
401 | Self { |
402 | buffer: align_for_cmsghdr(buffer), |
403 | read: 0, |
404 | length: 0, |
405 | } |
406 | } |
407 | |
408 | /// Returns a pointer to the message data. |
409 | pub(crate) fn as_control_ptr(&mut self) -> *mut u8 { |
410 | // When the length is zero, we may be using a `&[]` address, which may |
411 | // be an invalid but non-null pointer, and on some platforms, that |
412 | // causes `sendmsg` to fail with `EFAULT` or `EINVAL` |
413 | #[cfg (not(linux_kernel))] |
414 | if self.buffer.is_empty() { |
415 | return core::ptr::null_mut(); |
416 | } |
417 | |
418 | self.buffer.as_mut_ptr() |
419 | } |
420 | |
421 | /// Returns the length of the message data. |
422 | pub(crate) fn control_len(&self) -> usize { |
423 | self.buffer.len() |
424 | } |
425 | |
426 | /// Set the length of the message data. |
427 | /// |
428 | /// # Safety |
429 | /// |
430 | /// The buffer must be filled with valid message data. |
431 | pub(crate) unsafe fn set_control_len(&mut self, len: usize) { |
432 | self.length = len; |
433 | self.read = 0; |
434 | } |
435 | |
436 | /// Delete all messages from the buffer. |
437 | pub(crate) fn clear(&mut self) { |
438 | self.drain().for_each(drop); |
439 | } |
440 | |
441 | /// Drain all messages from the buffer. |
442 | pub fn drain(&mut self) -> AncillaryDrain<'_> { |
443 | AncillaryDrain { |
444 | messages: messages::Messages::new(&mut self.buffer[self.read..][..self.length]), |
445 | read_and_length: Some((&mut self.read, &mut self.length)), |
446 | } |
447 | } |
448 | } |
449 | |
450 | impl Drop for RecvAncillaryBuffer<'_> { |
451 | fn drop(&mut self) { |
452 | self.clear(); |
453 | } |
454 | } |
455 | |
456 | /// Return a slice of `buffer` starting at the first `cmsghdr` alignment |
457 | /// boundary. |
458 | #[inline ] |
459 | fn align_for_cmsghdr(buffer: &mut [u8]) -> &mut [u8] { |
460 | // If the buffer is empty, we won't be writing anything into it, so it |
461 | // doesn't need to be aligned. |
462 | if buffer.is_empty() { |
463 | return buffer; |
464 | } |
465 | |
466 | let align: usize = align_of::<c::cmsghdr>(); |
467 | let addr: usize = buffer.as_ptr() as usize; |
468 | let adjusted: usize = (addr + (align - 1)) & align.wrapping_neg(); |
469 | &mut buffer[adjusted - addr..] |
470 | } |
471 | |
472 | /// An iterator that drains messages from a [`RecvAncillaryBuffer`]. |
473 | pub struct AncillaryDrain<'buf> { |
474 | /// Inner iterator over messages. |
475 | messages: messages::Messages<'buf>, |
476 | |
477 | /// Increment the number of messages we've read. |
478 | /// Decrement the total length. |
479 | read_and_length: Option<(&'buf mut usize, &'buf mut usize)>, |
480 | } |
481 | |
482 | impl<'buf> AncillaryDrain<'buf> { |
483 | /// Create an iterator for control messages that were received without |
484 | /// [`RecvAncillaryBuffer`]. |
485 | /// |
486 | /// # Safety |
487 | /// |
488 | /// The buffer must contain valid message data (or be empty). |
489 | pub unsafe fn parse(buffer: &'buf mut [u8]) -> Self { |
490 | Self { |
491 | messages: messages::Messages::new(buffer), |
492 | read_and_length: None, |
493 | } |
494 | } |
495 | |
496 | fn advance( |
497 | read_and_length: &mut Option<(&'buf mut usize, &'buf mut usize)>, |
498 | msg: &c::cmsghdr, |
499 | ) -> Option<RecvAncillaryMessage<'buf>> { |
500 | // Advance the `read` pointer. |
501 | if let Some((read, length)) = read_and_length { |
502 | let msg_len = msg.cmsg_len as usize; |
503 | **read += msg_len; |
504 | **length -= msg_len; |
505 | } |
506 | |
507 | Self::cvt_msg(msg) |
508 | } |
509 | |
510 | /// A closure that converts a message into a [`RecvAncillaryMessage`]. |
511 | fn cvt_msg(msg: &c::cmsghdr) -> Option<RecvAncillaryMessage<'buf>> { |
512 | unsafe { |
513 | // Get a pointer to the payload. |
514 | let payload = c::CMSG_DATA(msg); |
515 | let payload_len = msg.cmsg_len as usize - c::CMSG_LEN(0) as usize; |
516 | |
517 | // Get a mutable slice of the payload. |
518 | let payload: &'buf mut [u8] = slice::from_raw_parts_mut(payload, payload_len); |
519 | |
520 | // Determine what type it is. |
521 | let (level, msg_type) = (msg.cmsg_level, msg.cmsg_type); |
522 | match (level as _, msg_type as _) { |
523 | (c::SOL_SOCKET, c::SCM_RIGHTS) => { |
524 | // Create an iterator that reads out the file descriptors. |
525 | let fds = AncillaryIter::new(payload); |
526 | |
527 | Some(RecvAncillaryMessage::ScmRights(fds)) |
528 | } |
529 | #[cfg (linux_kernel)] |
530 | (c::SOL_SOCKET, c::SCM_CREDENTIALS) => { |
531 | if payload_len >= size_of::<UCred>() { |
532 | let ucred = payload.as_ptr().cast::<UCred>().read_unaligned(); |
533 | Some(RecvAncillaryMessage::ScmCredentials(ucred)) |
534 | } else { |
535 | None |
536 | } |
537 | } |
538 | _ => None, |
539 | } |
540 | } |
541 | } |
542 | } |
543 | |
544 | impl<'buf> Iterator for AncillaryDrain<'buf> { |
545 | type Item = RecvAncillaryMessage<'buf>; |
546 | |
547 | fn next(&mut self) -> Option<Self::Item> { |
548 | self.messages |
549 | .find_map(|ev| Self::advance(&mut self.read_and_length, ev)) |
550 | } |
551 | |
552 | fn size_hint(&self) -> (usize, Option<usize>) { |
553 | let (_, max) = self.messages.size_hint(); |
554 | (0, max) |
555 | } |
556 | |
557 | fn fold<B, F>(mut self, init: B, f: F) -> B |
558 | where |
559 | Self: Sized, |
560 | F: FnMut(B, Self::Item) -> B, |
561 | { |
562 | self.messages |
563 | .filter_map(|ev| Self::advance(&mut self.read_and_length, ev)) |
564 | .fold(init, f) |
565 | } |
566 | |
567 | fn count(mut self) -> usize { |
568 | self.messages |
569 | .filter_map(|ev| Self::advance(&mut self.read_and_length, ev)) |
570 | .count() |
571 | } |
572 | |
573 | fn last(mut self) -> Option<Self::Item> |
574 | where |
575 | Self: Sized, |
576 | { |
577 | self.messages |
578 | .filter_map(|ev| Self::advance(&mut self.read_and_length, ev)) |
579 | .last() |
580 | } |
581 | |
582 | fn collect<B: FromIterator<Self::Item>>(mut self) -> B |
583 | where |
584 | Self: Sized, |
585 | { |
586 | self.messages |
587 | .filter_map(|ev| Self::advance(&mut self.read_and_length, ev)) |
588 | .collect() |
589 | } |
590 | } |
591 | |
592 | impl FusedIterator for AncillaryDrain<'_> {} |
593 | |
594 | /// `sendmsg(msghdr)`—Sends a message on a socket. |
595 | /// |
596 | /// This function is for use on connected sockets, as it doesn't have |
597 | /// a way to specify an address. See the [`sendmsg_v4`], [`sendmsg_v6`] |
598 | /// [`sendmsg_unix`], [`sendmsg_xdp`], and [`sendmsg_any`] to send |
599 | /// messages on unconnected sockets. |
600 | /// |
601 | /// # References |
602 | /// - [POSIX] |
603 | /// - [Linux] |
604 | /// - [Apple] |
605 | /// - [FreeBSD] |
606 | /// - [NetBSD] |
607 | /// - [OpenBSD] |
608 | /// - [DragonFly BSD] |
609 | /// - [illumos] |
610 | /// |
611 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendmsg.html |
612 | /// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html |
613 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html |
614 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 |
615 | /// [NetBSD]: https://man.netbsd.org/sendmsg.2 |
616 | /// [OpenBSD]: https://man.openbsd.org/sendmsg.2 |
617 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 |
618 | /// [illumos]: https://illumos.org/man/3SOCKET/sendmsg |
619 | #[inline ] |
620 | pub fn sendmsg( |
621 | socket: impl AsFd, |
622 | iov: &[IoSlice<'_>], |
623 | control: &mut SendAncillaryBuffer<'_, '_, '_>, |
624 | flags: SendFlags, |
625 | ) -> io::Result<usize> { |
626 | backend::net::syscalls::sendmsg(sockfd:socket.as_fd(), iov, control, flags) |
627 | } |
628 | |
629 | /// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv4 address. |
630 | /// |
631 | /// # References |
632 | /// - [POSIX] |
633 | /// - [Linux] |
634 | /// - [Apple] |
635 | /// - [FreeBSD] |
636 | /// - [NetBSD] |
637 | /// - [OpenBSD] |
638 | /// - [DragonFly BSD] |
639 | /// - [illumos] |
640 | /// |
641 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendmsg.html |
642 | /// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html |
643 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html |
644 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 |
645 | /// [NetBSD]: https://man.netbsd.org/sendmsg.2 |
646 | /// [OpenBSD]: https://man.openbsd.org/sendmsg.2 |
647 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 |
648 | /// [illumos]: https://illumos.org/man/3SOCKET/sendmsg |
649 | #[inline ] |
650 | pub fn sendmsg_v4( |
651 | socket: impl AsFd, |
652 | addr: &SocketAddrV4, |
653 | iov: &[IoSlice<'_>], |
654 | control: &mut SendAncillaryBuffer<'_, '_, '_>, |
655 | flags: SendFlags, |
656 | ) -> io::Result<usize> { |
657 | backend::net::syscalls::sendmsg_v4(sockfd:socket.as_fd(), addr, iov, control, flags) |
658 | } |
659 | |
660 | /// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv6 address. |
661 | /// |
662 | /// # References |
663 | /// - [POSIX] |
664 | /// - [Linux] |
665 | /// - [Apple] |
666 | /// - [FreeBSD] |
667 | /// - [NetBSD] |
668 | /// - [OpenBSD] |
669 | /// - [DragonFly BSD] |
670 | /// - [illumos] |
671 | /// |
672 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendmsg.html |
673 | /// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html |
674 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html |
675 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 |
676 | /// [NetBSD]: https://man.netbsd.org/sendmsg.2 |
677 | /// [OpenBSD]: https://man.openbsd.org/sendmsg.2 |
678 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 |
679 | /// [illumos]: https://illumos.org/man/3SOCKET/sendmsg |
680 | #[inline ] |
681 | pub fn sendmsg_v6( |
682 | socket: impl AsFd, |
683 | addr: &SocketAddrV6, |
684 | iov: &[IoSlice<'_>], |
685 | control: &mut SendAncillaryBuffer<'_, '_, '_>, |
686 | flags: SendFlags, |
687 | ) -> io::Result<usize> { |
688 | backend::net::syscalls::sendmsg_v6(sockfd:socket.as_fd(), addr, iov, control, flags) |
689 | } |
690 | |
691 | /// `sendmsg(msghdr)`—Sends a message on a socket to a specific Unix-domain |
692 | /// address. |
693 | /// |
694 | /// # References |
695 | /// - [POSIX] |
696 | /// - [Linux] |
697 | /// - [Apple] |
698 | /// - [FreeBSD] |
699 | /// - [NetBSD] |
700 | /// - [OpenBSD] |
701 | /// - [DragonFly BSD] |
702 | /// - [illumos] |
703 | /// |
704 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendmsg.html |
705 | /// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html |
706 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html |
707 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 |
708 | /// [NetBSD]: https://man.netbsd.org/sendmsg.2 |
709 | /// [OpenBSD]: https://man.openbsd.org/sendmsg.2 |
710 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 |
711 | /// [illumos]: https://illumos.org/man/3SOCKET/sendmsg |
712 | #[inline ] |
713 | #[cfg (unix)] |
714 | pub fn sendmsg_unix( |
715 | socket: impl AsFd, |
716 | addr: &super::SocketAddrUnix, |
717 | iov: &[IoSlice<'_>], |
718 | control: &mut SendAncillaryBuffer<'_, '_, '_>, |
719 | flags: SendFlags, |
720 | ) -> io::Result<usize> { |
721 | backend::net::syscalls::sendmsg_unix(sockfd:socket.as_fd(), addr, iov, control, flags) |
722 | } |
723 | |
724 | /// `sendmsg(msghdr)`—Sends a message on a socket to a specific XDP address. |
725 | /// |
726 | /// # References |
727 | /// - [Linux] |
728 | /// |
729 | /// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html |
730 | #[inline ] |
731 | #[cfg (target_os = "linux" )] |
732 | pub fn sendmsg_xdp( |
733 | socket: impl AsFd, |
734 | addr: &super::SocketAddrXdp, |
735 | iov: &[IoSlice<'_>], |
736 | control: &mut SendAncillaryBuffer<'_, '_, '_>, |
737 | flags: SendFlags, |
738 | ) -> io::Result<usize> { |
739 | backend::net::syscalls::sendmsg_xdp(sockfd:socket.as_fd(), addr, iov, control, flags) |
740 | } |
741 | |
742 | /// `sendmsg(msghdr)`—Sends a message on a socket to a specific address. |
743 | /// |
744 | /// # References |
745 | /// - [POSIX] |
746 | /// - [Linux] |
747 | /// - [Apple] |
748 | /// - [FreeBSD] |
749 | /// - [NetBSD] |
750 | /// - [OpenBSD] |
751 | /// - [DragonFly BSD] |
752 | /// - [illumos] |
753 | /// |
754 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendmsg.html |
755 | /// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html |
756 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html |
757 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 |
758 | /// [NetBSD]: https://man.netbsd.org/sendmsg.2 |
759 | /// [OpenBSD]: https://man.openbsd.org/sendmsg.2 |
760 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 |
761 | /// [illumos]: https://illumos.org/man/3SOCKET/sendmsg |
762 | #[inline ] |
763 | pub fn sendmsg_any( |
764 | socket: impl AsFd, |
765 | addr: Option<&SocketAddrAny>, |
766 | iov: &[IoSlice<'_>], |
767 | control: &mut SendAncillaryBuffer<'_, '_, '_>, |
768 | flags: SendFlags, |
769 | ) -> io::Result<usize> { |
770 | match addr { |
771 | None => backend::net::syscalls::sendmsg(sockfd:socket.as_fd(), iov, control, flags), |
772 | Some(SocketAddrAny::V4(addr: &SocketAddrV4)) => { |
773 | backend::net::syscalls::sendmsg_v4(sockfd:socket.as_fd(), addr, iov, control, flags) |
774 | } |
775 | Some(SocketAddrAny::V6(addr: &SocketAddrV6)) => { |
776 | backend::net::syscalls::sendmsg_v6(sockfd:socket.as_fd(), addr, iov, control, flags) |
777 | } |
778 | #[cfg (unix)] |
779 | Some(SocketAddrAny::Unix(addr: &SocketAddrUnix)) => { |
780 | backend::net::syscalls::sendmsg_unix(sockfd:socket.as_fd(), addr, iov, control, flags) |
781 | } |
782 | #[cfg (target_os = "linux" )] |
783 | Some(SocketAddrAny::Xdp(addr: &SocketAddrXdp)) => { |
784 | backend::net::syscalls::sendmsg_xdp(sockfd:socket.as_fd(), addr, iov, control, flags) |
785 | } |
786 | } |
787 | } |
788 | |
789 | /// `recvmsg(msghdr)`—Receives a message from a socket. |
790 | /// |
791 | /// # References |
792 | /// - [POSIX] |
793 | /// - [Linux] |
794 | /// - [Apple] |
795 | /// - [FreeBSD] |
796 | /// - [NetBSD] |
797 | /// - [OpenBSD] |
798 | /// - [DragonFly BSD] |
799 | /// - [illumos] |
800 | /// |
801 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/recvmsg.html |
802 | /// [Linux]: https://man7.org/linux/man-pages/man2/recvmsg.2.html |
803 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recvmsg.2.html |
804 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recvmsg&sektion=2 |
805 | /// [NetBSD]: https://man.netbsd.org/recvmsg.2 |
806 | /// [OpenBSD]: https://man.openbsd.org/recvmsg.2 |
807 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recvmsg§ion=2 |
808 | /// [illumos]: https://illumos.org/man/3SOCKET/recvmsg |
809 | #[inline ] |
810 | pub fn recvmsg( |
811 | socket: impl AsFd, |
812 | iov: &mut [IoSliceMut<'_>], |
813 | control: &mut RecvAncillaryBuffer<'_>, |
814 | flags: RecvFlags, |
815 | ) -> io::Result<RecvMsgReturn> { |
816 | backend::net::syscalls::recvmsg(sockfd:socket.as_fd(), iov, control, flags) |
817 | } |
818 | |
819 | /// The result of a successful [`recvmsg`] call. |
820 | pub struct RecvMsgReturn { |
821 | /// The number of bytes received. |
822 | pub bytes: usize, |
823 | |
824 | /// The flags received. |
825 | pub flags: RecvFlags, |
826 | |
827 | /// The address of the socket we received from, if any. |
828 | pub address: Option<SocketAddrAny>, |
829 | } |
830 | |
831 | /// An iterator over data in an ancillary buffer. |
832 | pub struct AncillaryIter<'data, T> { |
833 | /// The data we're iterating over. |
834 | data: &'data mut [u8], |
835 | |
836 | /// The raw data we're removing. |
837 | _marker: PhantomData<T>, |
838 | } |
839 | |
840 | impl<'data, T> AncillaryIter<'data, T> { |
841 | /// Create a new iterator over data in an ancillary buffer. |
842 | /// |
843 | /// # Safety |
844 | /// |
845 | /// The buffer must contain valid ancillary data. |
846 | unsafe fn new(data: &'data mut [u8]) -> Self { |
847 | assert_eq!(data.len() % size_of::<T>(), 0); |
848 | |
849 | Self { |
850 | data, |
851 | _marker: PhantomData, |
852 | } |
853 | } |
854 | } |
855 | |
856 | impl<'data, T> Drop for AncillaryIter<'data, T> { |
857 | fn drop(&mut self) { |
858 | self.for_each(drop); |
859 | } |
860 | } |
861 | |
862 | impl<T> Iterator for AncillaryIter<'_, T> { |
863 | type Item = T; |
864 | |
865 | fn next(&mut self) -> Option<Self::Item> { |
866 | // See if there is a next item. |
867 | if self.data.len() < size_of::<T>() { |
868 | return None; |
869 | } |
870 | |
871 | // Get the next item. |
872 | let item = unsafe { self.data.as_ptr().cast::<T>().read_unaligned() }; |
873 | |
874 | // Move forward. |
875 | let data = take(&mut self.data); |
876 | self.data = &mut data[size_of::<T>()..]; |
877 | |
878 | Some(item) |
879 | } |
880 | |
881 | fn size_hint(&self) -> (usize, Option<usize>) { |
882 | let len = self.len(); |
883 | (len, Some(len)) |
884 | } |
885 | |
886 | fn count(self) -> usize { |
887 | self.len() |
888 | } |
889 | |
890 | fn last(mut self) -> Option<Self::Item> { |
891 | self.next_back() |
892 | } |
893 | } |
894 | |
895 | impl<T> FusedIterator for AncillaryIter<'_, T> {} |
896 | |
897 | impl<T> ExactSizeIterator for AncillaryIter<'_, T> { |
898 | fn len(&self) -> usize { |
899 | self.data.len() / size_of::<T>() |
900 | } |
901 | } |
902 | |
903 | impl<T> DoubleEndedIterator for AncillaryIter<'_, T> { |
904 | fn next_back(&mut self) -> Option<Self::Item> { |
905 | // See if there is a next item. |
906 | if self.data.len() < size_of::<T>() { |
907 | return None; |
908 | } |
909 | |
910 | // Get the next item. |
911 | let item: T = unsafe { |
912 | let ptr: *const u8 = self.data.as_ptr().add(self.data.len() - size_of::<T>()); |
913 | ptr.cast::<T>().read_unaligned() |
914 | }; |
915 | |
916 | // Move forward. |
917 | let len: usize = self.data.len(); |
918 | let data: &mut [u8] = take(&mut self.data); |
919 | self.data = &mut data[..len - size_of::<T>()]; |
920 | |
921 | Some(item) |
922 | } |
923 | } |
924 | |
925 | mod messages { |
926 | use crate::backend::c; |
927 | use crate::backend::net::msghdr; |
928 | use core::iter::FusedIterator; |
929 | use core::marker::PhantomData; |
930 | use core::ptr::NonNull; |
931 | |
932 | /// An iterator over the messages in an ancillary buffer. |
933 | pub(super) struct Messages<'buf> { |
934 | /// The message header we're using to iterate over the messages. |
935 | msghdr: c::msghdr, |
936 | |
937 | /// The current pointer to the next message header to return. |
938 | /// |
939 | /// This has a lifetime of `'buf`. |
940 | header: Option<NonNull<c::cmsghdr>>, |
941 | |
942 | /// Capture the original lifetime of the buffer. |
943 | _buffer: PhantomData<&'buf mut [u8]>, |
944 | } |
945 | |
946 | impl<'buf> Messages<'buf> { |
947 | /// Create a new iterator over messages from a byte buffer. |
948 | pub(super) fn new(buf: &'buf mut [u8]) -> Self { |
949 | let msghdr = { |
950 | let mut h = msghdr::zero_msghdr(); |
951 | h.msg_control = buf.as_mut_ptr().cast(); |
952 | h.msg_controllen = buf.len().try_into().unwrap(); |
953 | h |
954 | }; |
955 | |
956 | // Get the first header. |
957 | let header = NonNull::new(unsafe { c::CMSG_FIRSTHDR(&msghdr) }); |
958 | |
959 | Self { |
960 | msghdr, |
961 | header, |
962 | _buffer: PhantomData, |
963 | } |
964 | } |
965 | } |
966 | |
967 | impl<'a> Iterator for Messages<'a> { |
968 | type Item = &'a mut c::cmsghdr; |
969 | |
970 | #[inline ] |
971 | fn next(&mut self) -> Option<Self::Item> { |
972 | // Get the current header. |
973 | let header = self.header?; |
974 | |
975 | // Get the next header. |
976 | self.header = NonNull::new(unsafe { c::CMSG_NXTHDR(&self.msghdr, header.as_ptr()) }); |
977 | |
978 | // If the headers are equal, we're done. |
979 | if Some(header) == self.header { |
980 | self.header = None; |
981 | } |
982 | |
983 | // SAFETY: The lifetime of `header` is tied to this. |
984 | Some(unsafe { &mut *header.as_ptr() }) |
985 | } |
986 | |
987 | fn size_hint(&self) -> (usize, Option<usize>) { |
988 | if self.header.is_some() { |
989 | // The remaining buffer *could* be filled with zero-length |
990 | // messages. |
991 | let max_size = unsafe { c::CMSG_LEN(0) } as usize; |
992 | let remaining_count = self.msghdr.msg_controllen as usize / max_size; |
993 | (1, Some(remaining_count)) |
994 | } else { |
995 | (0, Some(0)) |
996 | } |
997 | } |
998 | } |
999 | |
1000 | impl FusedIterator for Messages<'_> {} |
1001 | } |
1002 | |