]> git.proxmox.com Git - rustc.git/blob - vendor/rustix/src/backend/linux_raw/net/syscalls.rs
New upstream version 1.73.0+dfsg1
[rustc.git] / vendor / rustix / src / backend / linux_raw / net / syscalls.rs
1 //! linux_raw syscalls supporting `rustix::net`.
2 //!
3 //! # Safety
4 //!
5 //! See the `rustix::backend` module documentation for details.
6 #![allow(unsafe_code)]
7 #![allow(clippy::undocumented_unsafe_blocks)]
8
9 use super::msghdr::{
10 with_noaddr_msghdr, with_recv_msghdr, with_unix_msghdr, with_v4_msghdr, with_v6_msghdr,
11 };
12 use super::read_sockaddr::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os};
13 use super::send_recv::{RecvFlags, SendFlags};
14 use super::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6};
15 use crate::backend::c;
16 use crate::backend::conv::{
17 by_mut, by_ref, c_int, c_uint, ret, ret_owned_fd, ret_usize, size_of, slice, slice_mut,
18 socklen_t, zero,
19 };
20 use crate::fd::{BorrowedFd, OwnedFd};
21 use crate::io::{self, IoSlice, IoSliceMut};
22 use crate::net::{
23 AddressFamily, Protocol, RecvAncillaryBuffer, RecvMsgReturn, SendAncillaryBuffer, Shutdown,
24 SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6, SocketFlags, SocketType,
25 };
26 use c::{sockaddr, sockaddr_in, sockaddr_in6, socklen_t};
27 use core::mem::MaybeUninit;
28 #[cfg(target_arch = "x86")]
29 use {
30 crate::backend::conv::{slice_just_addr, x86_sys},
31 crate::backend::reg::{ArgReg, SocketArg},
32 linux_raw_sys::net::{
33 SYS_ACCEPT, SYS_ACCEPT4, SYS_BIND, SYS_CONNECT, SYS_GETPEERNAME, SYS_GETSOCKNAME,
34 SYS_GETSOCKOPT, SYS_LISTEN, SYS_RECV, SYS_RECVFROM, SYS_RECVMSG, SYS_SEND, SYS_SENDMSG,
35 SYS_SENDTO, SYS_SETSOCKOPT, SYS_SHUTDOWN, SYS_SOCKET, SYS_SOCKETPAIR,
36 },
37 };
38
39 #[inline]
40 pub(crate) fn socket(
41 family: AddressFamily,
42 type_: SocketType,
43 protocol: Option<Protocol>,
44 ) -> io::Result<OwnedFd> {
45 #[cfg(not(target_arch = "x86"))]
46 unsafe {
47 ret_owned_fd(syscall_readonly!(__NR_socket, family, type_, protocol))
48 }
49 #[cfg(target_arch = "x86")]
50 unsafe {
51 ret_owned_fd(syscall_readonly!(
52 __NR_socketcall,
53 x86_sys(SYS_SOCKET),
54 slice_just_addr::<ArgReg<SocketArg>, _>(&[
55 family.into(),
56 type_.into(),
57 protocol.into(),
58 ])
59 ))
60 }
61 }
62
63 #[inline]
64 pub(crate) fn socket_with(
65 family: AddressFamily,
66 type_: SocketType,
67 flags: SocketFlags,
68 protocol: Option<Protocol>,
69 ) -> io::Result<OwnedFd> {
70 #[cfg(not(target_arch = "x86"))]
71 unsafe {
72 ret_owned_fd(syscall_readonly!(
73 __NR_socket,
74 family,
75 (type_, flags),
76 protocol
77 ))
78 }
79 #[cfg(target_arch = "x86")]
80 unsafe {
81 ret_owned_fd(syscall_readonly!(
82 __NR_socketcall,
83 x86_sys(SYS_SOCKET),
84 slice_just_addr::<ArgReg<SocketArg>, _>(&[
85 family.into(),
86 (type_, flags).into(),
87 protocol.into(),
88 ])
89 ))
90 }
91 }
92
93 #[inline]
94 pub(crate) fn socketpair(
95 family: AddressFamily,
96 type_: SocketType,
97 flags: SocketFlags,
98 protocol: Option<Protocol>,
99 ) -> io::Result<(OwnedFd, OwnedFd)> {
100 #[cfg(not(target_arch = "x86"))]
101 unsafe {
102 let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit();
103 ret(syscall!(
104 __NR_socketpair,
105 family,
106 (type_, flags),
107 protocol,
108 &mut result
109 ))?;
110 let [fd0, fd1] = result.assume_init();
111 Ok((fd0, fd1))
112 }
113 #[cfg(target_arch = "x86")]
114 unsafe {
115 let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit();
116 ret(syscall!(
117 __NR_socketcall,
118 x86_sys(SYS_SOCKETPAIR),
119 slice_just_addr::<ArgReg<SocketArg>, _>(&[
120 family.into(),
121 (type_, flags).into(),
122 protocol.into(),
123 (&mut result).into(),
124 ])
125 ))?;
126 let [fd0, fd1] = result.assume_init();
127 Ok((fd0, fd1))
128 }
129 }
130
131 #[inline]
132 pub(crate) fn accept(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> {
133 #[cfg(not(target_arch = "x86"))]
134 unsafe {
135 let fd = ret_owned_fd(syscall_readonly!(__NR_accept, fd, zero(), zero()))?;
136 Ok(fd)
137 }
138 #[cfg(target_arch = "x86")]
139 unsafe {
140 let fd = ret_owned_fd(syscall_readonly!(
141 __NR_socketcall,
142 x86_sys(SYS_ACCEPT),
143 slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), zero(), zero()])
144 ))?;
145 Ok(fd)
146 }
147 }
148
149 #[inline]
150 pub(crate) fn accept_with(fd: BorrowedFd<'_>, flags: SocketFlags) -> io::Result<OwnedFd> {
151 #[cfg(not(target_arch = "x86"))]
152 unsafe {
153 let fd = ret_owned_fd(syscall_readonly!(__NR_accept4, fd, zero(), zero(), flags))?;
154 Ok(fd)
155 }
156 #[cfg(target_arch = "x86")]
157 unsafe {
158 let fd = ret_owned_fd(syscall_readonly!(
159 __NR_socketcall,
160 x86_sys(SYS_ACCEPT4),
161 slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), zero(), zero(), flags.into()])
162 ))?;
163 Ok(fd)
164 }
165 }
166
167 #[inline]
168 pub(crate) fn acceptfrom(fd: BorrowedFd<'_>) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> {
169 #[cfg(not(target_arch = "x86"))]
170 unsafe {
171 let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t;
172 let mut storage = MaybeUninit::<sockaddr>::uninit();
173 let fd = ret_owned_fd(syscall!(
174 __NR_accept,
175 fd,
176 &mut storage,
177 by_mut(&mut addrlen)
178 ))?;
179 Ok((
180 fd,
181 maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()),
182 ))
183 }
184 #[cfg(target_arch = "x86")]
185 unsafe {
186 let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t;
187 let mut storage = MaybeUninit::<sockaddr>::uninit();
188 let fd = ret_owned_fd(syscall!(
189 __NR_socketcall,
190 x86_sys(SYS_ACCEPT),
191 slice_just_addr::<ArgReg<SocketArg>, _>(&[
192 fd.into(),
193 (&mut storage).into(),
194 by_mut(&mut addrlen),
195 ])
196 ))?;
197 Ok((
198 fd,
199 maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()),
200 ))
201 }
202 }
203
204 #[inline]
205 pub(crate) fn acceptfrom_with(
206 fd: BorrowedFd<'_>,
207 flags: SocketFlags,
208 ) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> {
209 #[cfg(not(target_arch = "x86"))]
210 unsafe {
211 let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t;
212 let mut storage = MaybeUninit::<sockaddr>::uninit();
213 let fd = ret_owned_fd(syscall!(
214 __NR_accept4,
215 fd,
216 &mut storage,
217 by_mut(&mut addrlen),
218 flags
219 ))?;
220 Ok((
221 fd,
222 maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()),
223 ))
224 }
225 #[cfg(target_arch = "x86")]
226 unsafe {
227 let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t;
228 let mut storage = MaybeUninit::<sockaddr>::uninit();
229 let fd = ret_owned_fd(syscall!(
230 __NR_socketcall,
231 x86_sys(SYS_ACCEPT4),
232 slice_just_addr::<ArgReg<SocketArg>, _>(&[
233 fd.into(),
234 (&mut storage).into(),
235 by_mut(&mut addrlen),
236 flags.into(),
237 ])
238 ))?;
239 Ok((
240 fd,
241 maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()),
242 ))
243 }
244 }
245
246 #[inline]
247 pub(crate) fn recvmsg(
248 sockfd: BorrowedFd<'_>,
249 iov: &mut [IoSliceMut<'_>],
250 control: &mut RecvAncillaryBuffer<'_>,
251 msg_flags: RecvFlags,
252 ) -> io::Result<RecvMsgReturn> {
253 let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit();
254
255 with_recv_msghdr(&mut storage, iov, control, |msghdr| {
256 #[cfg(not(target_arch = "x86"))]
257 let result =
258 unsafe { ret_usize(syscall!(__NR_recvmsg, sockfd, by_mut(msghdr), msg_flags)) };
259
260 #[cfg(target_arch = "x86")]
261 let result = unsafe {
262 ret_usize(syscall!(
263 __NR_socketcall,
264 x86_sys(SYS_RECVMSG),
265 slice_just_addr::<ArgReg<SocketArg>, _>(&[
266 sockfd.into(),
267 by_mut(msghdr),
268 msg_flags.into(),
269 ])
270 ))
271 };
272
273 result.map(|bytes| {
274 // Get the address of the sender, if any.
275 let addr =
276 unsafe { maybe_read_sockaddr_os(msghdr.msg_name as _, msghdr.msg_namelen as _) };
277
278 RecvMsgReturn {
279 bytes,
280 address: addr,
281 flags: RecvFlags::from_bits_retain(msghdr.msg_flags),
282 }
283 })
284 })
285 }
286
287 #[inline]
288 pub(crate) fn sendmsg(
289 sockfd: BorrowedFd<'_>,
290 iov: &[IoSlice<'_>],
291 control: &mut SendAncillaryBuffer<'_, '_, '_>,
292 msg_flags: SendFlags,
293 ) -> io::Result<usize> {
294 with_noaddr_msghdr(iov, control, |msghdr| {
295 #[cfg(not(target_arch = "x86"))]
296 let result =
297 unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) };
298
299 #[cfg(target_arch = "x86")]
300 let result = unsafe {
301 ret_usize(syscall!(
302 __NR_socketcall,
303 x86_sys(SYS_SENDMSG),
304 slice_just_addr::<ArgReg<SocketArg>, _>(&[
305 sockfd.into(),
306 by_ref(&msghdr),
307 msg_flags.into()
308 ])
309 ))
310 };
311
312 result
313 })
314 }
315
316 #[inline]
317 pub(crate) fn sendmsg_v4(
318 sockfd: BorrowedFd<'_>,
319 addr: &SocketAddrV4,
320 iov: &[IoSlice<'_>],
321 control: &mut SendAncillaryBuffer<'_, '_, '_>,
322 msg_flags: SendFlags,
323 ) -> io::Result<usize> {
324 with_v4_msghdr(addr, iov, control, |msghdr| {
325 #[cfg(not(target_arch = "x86"))]
326 let result =
327 unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) };
328
329 #[cfg(target_arch = "x86")]
330 let result = unsafe {
331 ret_usize(syscall!(
332 __NR_socketcall,
333 x86_sys(SYS_SENDMSG),
334 slice_just_addr::<ArgReg<SocketArg>, _>(&[
335 sockfd.into(),
336 by_ref(&msghdr),
337 msg_flags.into(),
338 ])
339 ))
340 };
341
342 result
343 })
344 }
345
346 #[inline]
347 pub(crate) fn sendmsg_v6(
348 sockfd: BorrowedFd<'_>,
349 addr: &SocketAddrV6,
350 iov: &[IoSlice<'_>],
351 control: &mut SendAncillaryBuffer<'_, '_, '_>,
352 msg_flags: SendFlags,
353 ) -> io::Result<usize> {
354 with_v6_msghdr(addr, iov, control, |msghdr| {
355 #[cfg(not(target_arch = "x86"))]
356 let result =
357 unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) };
358
359 #[cfg(target_arch = "x86")]
360 let result = unsafe {
361 ret_usize(syscall!(
362 __NR_socketcall,
363 x86_sys(SYS_SENDMSG),
364 slice_just_addr::<ArgReg<SocketArg>, _>(&[
365 sockfd.into(),
366 by_ref(&msghdr),
367 msg_flags.into()
368 ])
369 ))
370 };
371
372 result
373 })
374 }
375
376 #[inline]
377 pub(crate) fn sendmsg_unix(
378 sockfd: BorrowedFd<'_>,
379 addr: &SocketAddrUnix,
380 iov: &[IoSlice<'_>],
381 control: &mut SendAncillaryBuffer<'_, '_, '_>,
382 msg_flags: SendFlags,
383 ) -> io::Result<usize> {
384 with_unix_msghdr(addr, iov, control, |msghdr| {
385 #[cfg(not(target_arch = "x86"))]
386 let result =
387 unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) };
388
389 #[cfg(target_arch = "x86")]
390 let result = unsafe {
391 ret_usize(syscall!(
392 __NR_socketcall,
393 x86_sys(SYS_SENDMSG),
394 slice_just_addr::<ArgReg<SocketArg>, _>(&[
395 sockfd.into(),
396 by_ref(&msghdr),
397 msg_flags.into()
398 ])
399 ))
400 };
401
402 result
403 })
404 }
405
406 #[inline]
407 pub(crate) fn shutdown(fd: BorrowedFd<'_>, how: Shutdown) -> io::Result<()> {
408 #[cfg(not(target_arch = "x86"))]
409 unsafe {
410 ret(syscall_readonly!(
411 __NR_shutdown,
412 fd,
413 c_uint(how as c::c_uint)
414 ))
415 }
416 #[cfg(target_arch = "x86")]
417 unsafe {
418 ret(syscall_readonly!(
419 __NR_socketcall,
420 x86_sys(SYS_SHUTDOWN),
421 slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), c_uint(how as c::c_uint)])
422 ))
423 }
424 }
425
426 #[inline]
427 pub(crate) fn send(fd: BorrowedFd<'_>, buf: &[u8], flags: SendFlags) -> io::Result<usize> {
428 let (buf_addr, buf_len) = slice(buf);
429
430 #[cfg(not(any(
431 target_arch = "aarch64",
432 target_arch = "mips64",
433 target_arch = "mips64r6",
434 target_arch = "riscv64",
435 target_arch = "x86",
436 target_arch = "x86_64",
437 )))]
438 unsafe {
439 ret_usize(syscall_readonly!(__NR_send, fd, buf_addr, buf_len, flags))
440 }
441 #[cfg(any(
442 target_arch = "aarch64",
443 target_arch = "mips64",
444 target_arch = "mips64r6",
445 target_arch = "riscv64",
446 target_arch = "x86_64",
447 ))]
448 unsafe {
449 ret_usize(syscall_readonly!(
450 __NR_sendto,
451 fd,
452 buf_addr,
453 buf_len,
454 flags,
455 zero(),
456 zero()
457 ))
458 }
459 #[cfg(target_arch = "x86")]
460 unsafe {
461 ret_usize(syscall_readonly!(
462 __NR_socketcall,
463 x86_sys(SYS_SEND),
464 slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), buf_addr, buf_len, flags.into()])
465 ))
466 }
467 }
468
469 #[inline]
470 pub(crate) fn sendto_v4(
471 fd: BorrowedFd<'_>,
472 buf: &[u8],
473 flags: SendFlags,
474 addr: &SocketAddrV4,
475 ) -> io::Result<usize> {
476 let (buf_addr, buf_len) = slice(buf);
477
478 #[cfg(not(target_arch = "x86"))]
479 unsafe {
480 ret_usize(syscall_readonly!(
481 __NR_sendto,
482 fd,
483 buf_addr,
484 buf_len,
485 flags,
486 by_ref(&encode_sockaddr_v4(addr)),
487 size_of::<sockaddr_in, _>()
488 ))
489 }
490 #[cfg(target_arch = "x86")]
491 unsafe {
492 ret_usize(syscall_readonly!(
493 __NR_socketcall,
494 x86_sys(SYS_SENDTO),
495 slice_just_addr::<ArgReg<SocketArg>, _>(&[
496 fd.into(),
497 buf_addr,
498 buf_len,
499 flags.into(),
500 by_ref(&encode_sockaddr_v4(addr)),
501 size_of::<sockaddr_in, _>(),
502 ])
503 ))
504 }
505 }
506
507 #[inline]
508 pub(crate) fn sendto_v6(
509 fd: BorrowedFd<'_>,
510 buf: &[u8],
511 flags: SendFlags,
512 addr: &SocketAddrV6,
513 ) -> io::Result<usize> {
514 let (buf_addr, buf_len) = slice(buf);
515
516 #[cfg(not(target_arch = "x86"))]
517 unsafe {
518 ret_usize(syscall_readonly!(
519 __NR_sendto,
520 fd,
521 buf_addr,
522 buf_len,
523 flags,
524 by_ref(&encode_sockaddr_v6(addr)),
525 size_of::<sockaddr_in6, _>()
526 ))
527 }
528 #[cfg(target_arch = "x86")]
529 unsafe {
530 ret_usize(syscall_readonly!(
531 __NR_socketcall,
532 x86_sys(SYS_SENDTO),
533 slice_just_addr::<ArgReg<SocketArg>, _>(&[
534 fd.into(),
535 buf_addr,
536 buf_len,
537 flags.into(),
538 by_ref(&encode_sockaddr_v6(addr)),
539 size_of::<sockaddr_in6, _>(),
540 ])
541 ))
542 }
543 }
544
545 #[inline]
546 pub(crate) fn sendto_unix(
547 fd: BorrowedFd<'_>,
548 buf: &[u8],
549 flags: SendFlags,
550 addr: &SocketAddrUnix,
551 ) -> io::Result<usize> {
552 let (buf_addr, buf_len) = slice(buf);
553
554 #[cfg(not(target_arch = "x86"))]
555 unsafe {
556 ret_usize(syscall_readonly!(
557 __NR_sendto,
558 fd,
559 buf_addr,
560 buf_len,
561 flags,
562 by_ref(&addr.unix),
563 socklen_t(addr.addr_len())
564 ))
565 }
566 #[cfg(target_arch = "x86")]
567 unsafe {
568 ret_usize(syscall_readonly!(
569 __NR_socketcall,
570 x86_sys(SYS_SENDTO),
571 slice_just_addr::<ArgReg<SocketArg>, _>(&[
572 fd.into(),
573 buf_addr,
574 buf_len,
575 flags.into(),
576 by_ref(&addr.unix),
577 socklen_t(addr.addr_len()),
578 ])
579 ))
580 }
581 }
582
583 #[inline]
584 pub(crate) fn recv(fd: BorrowedFd<'_>, buf: &mut [u8], flags: RecvFlags) -> io::Result<usize> {
585 let (buf_addr_mut, buf_len) = slice_mut(buf);
586
587 #[cfg(not(any(
588 target_arch = "aarch64",
589 target_arch = "mips64",
590 target_arch = "mips64r6",
591 target_arch = "riscv64",
592 target_arch = "x86",
593 target_arch = "x86_64",
594 )))]
595 unsafe {
596 ret_usize(syscall!(__NR_recv, fd, buf_addr_mut, buf_len, flags))
597 }
598 #[cfg(any(
599 target_arch = "aarch64",
600 target_arch = "mips64",
601 target_arch = "mips64r6",
602 target_arch = "riscv64",
603 target_arch = "x86_64",
604 ))]
605 unsafe {
606 ret_usize(syscall!(
607 __NR_recvfrom,
608 fd,
609 buf_addr_mut,
610 buf_len,
611 flags,
612 zero(),
613 zero()
614 ))
615 }
616 #[cfg(target_arch = "x86")]
617 unsafe {
618 ret_usize(syscall!(
619 __NR_socketcall,
620 x86_sys(SYS_RECV),
621 slice_just_addr::<ArgReg<SocketArg>, _>(&[
622 fd.into(),
623 buf_addr_mut,
624 buf_len,
625 flags.into(),
626 ])
627 ))
628 }
629 }
630
631 #[inline]
632 pub(crate) fn recvfrom(
633 fd: BorrowedFd<'_>,
634 buf: &mut [u8],
635 flags: RecvFlags,
636 ) -> io::Result<(usize, Option<SocketAddrAny>)> {
637 let (buf_addr_mut, buf_len) = slice_mut(buf);
638
639 let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t;
640 let mut storage = MaybeUninit::<sockaddr>::uninit();
641
642 unsafe {
643 // `recvfrom` does not write to the storage if the socket is
644 // connection-oriented sockets, so we initialize the family field to
645 // `AF_UNSPEC` so that we can detect this case.
646 initialize_family_to_unspec(storage.as_mut_ptr());
647
648 #[cfg(not(target_arch = "x86"))]
649 let nread = ret_usize(syscall!(
650 __NR_recvfrom,
651 fd,
652 buf_addr_mut,
653 buf_len,
654 flags,
655 &mut storage,
656 by_mut(&mut addrlen)
657 ))?;
658 #[cfg(target_arch = "x86")]
659 let nread = ret_usize(syscall!(
660 __NR_socketcall,
661 x86_sys(SYS_RECVFROM),
662 slice_just_addr::<ArgReg<SocketArg>, _>(&[
663 fd.into(),
664 buf_addr_mut,
665 buf_len,
666 flags.into(),
667 (&mut storage).into(),
668 by_mut(&mut addrlen),
669 ])
670 ))?;
671
672 Ok((
673 nread,
674 maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()),
675 ))
676 }
677 }
678
679 #[inline]
680 pub(crate) fn getpeername(fd: BorrowedFd<'_>) -> io::Result<Option<SocketAddrAny>> {
681 #[cfg(not(target_arch = "x86"))]
682 unsafe {
683 let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t;
684 let mut storage = MaybeUninit::<sockaddr>::uninit();
685 ret(syscall!(
686 __NR_getpeername,
687 fd,
688 &mut storage,
689 by_mut(&mut addrlen)
690 ))?;
691 Ok(maybe_read_sockaddr_os(
692 &storage.assume_init(),
693 addrlen.try_into().unwrap(),
694 ))
695 }
696 #[cfg(target_arch = "x86")]
697 unsafe {
698 let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t;
699 let mut storage = MaybeUninit::<sockaddr>::uninit();
700 ret(syscall!(
701 __NR_socketcall,
702 x86_sys(SYS_GETPEERNAME),
703 slice_just_addr::<ArgReg<SocketArg>, _>(&[
704 fd.into(),
705 (&mut storage).into(),
706 by_mut(&mut addrlen),
707 ])
708 ))?;
709 Ok(maybe_read_sockaddr_os(
710 &storage.assume_init(),
711 addrlen.try_into().unwrap(),
712 ))
713 }
714 }
715
716 #[inline]
717 pub(crate) fn getsockname(fd: BorrowedFd<'_>) -> io::Result<SocketAddrAny> {
718 #[cfg(not(target_arch = "x86"))]
719 unsafe {
720 let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t;
721 let mut storage = MaybeUninit::<sockaddr>::uninit();
722 ret(syscall!(
723 __NR_getsockname,
724 fd,
725 &mut storage,
726 by_mut(&mut addrlen)
727 ))?;
728 Ok(read_sockaddr_os(
729 &storage.assume_init(),
730 addrlen.try_into().unwrap(),
731 ))
732 }
733 #[cfg(target_arch = "x86")]
734 unsafe {
735 let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t;
736 let mut storage = MaybeUninit::<sockaddr>::uninit();
737 ret(syscall!(
738 __NR_socketcall,
739 x86_sys(SYS_GETSOCKNAME),
740 slice_just_addr::<ArgReg<SocketArg>, _>(&[
741 fd.into(),
742 (&mut storage).into(),
743 by_mut(&mut addrlen),
744 ])
745 ))?;
746 Ok(read_sockaddr_os(
747 &storage.assume_init(),
748 addrlen.try_into().unwrap(),
749 ))
750 }
751 }
752
753 #[inline]
754 pub(crate) fn bind_v4(fd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> {
755 #[cfg(not(target_arch = "x86"))]
756 unsafe {
757 ret(syscall_readonly!(
758 __NR_bind,
759 fd,
760 by_ref(&encode_sockaddr_v4(addr)),
761 size_of::<sockaddr_in, _>()
762 ))
763 }
764 #[cfg(target_arch = "x86")]
765 unsafe {
766 ret(syscall_readonly!(
767 __NR_socketcall,
768 x86_sys(SYS_BIND),
769 slice_just_addr::<ArgReg<SocketArg>, _>(&[
770 fd.into(),
771 by_ref(&encode_sockaddr_v4(addr)),
772 size_of::<sockaddr_in, _>(),
773 ])
774 ))
775 }
776 }
777
778 #[inline]
779 pub(crate) fn bind_v6(fd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> {
780 #[cfg(not(target_arch = "x86"))]
781 unsafe {
782 ret(syscall_readonly!(
783 __NR_bind,
784 fd,
785 by_ref(&encode_sockaddr_v6(addr)),
786 size_of::<sockaddr_in6, _>()
787 ))
788 }
789 #[cfg(target_arch = "x86")]
790 unsafe {
791 ret(syscall_readonly!(
792 __NR_socketcall,
793 x86_sys(SYS_BIND),
794 slice_just_addr::<ArgReg<SocketArg>, _>(&[
795 fd.into(),
796 by_ref(&encode_sockaddr_v6(addr)),
797 size_of::<sockaddr_in6, _>(),
798 ])
799 ))
800 }
801 }
802
803 #[inline]
804 pub(crate) fn bind_unix(fd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> {
805 #[cfg(not(target_arch = "x86"))]
806 unsafe {
807 ret(syscall_readonly!(
808 __NR_bind,
809 fd,
810 by_ref(&addr.unix),
811 socklen_t(addr.addr_len())
812 ))
813 }
814 #[cfg(target_arch = "x86")]
815 unsafe {
816 ret(syscall_readonly!(
817 __NR_socketcall,
818 x86_sys(SYS_BIND),
819 slice_just_addr::<ArgReg<SocketArg>, _>(&[
820 fd.into(),
821 by_ref(&addr.unix),
822 socklen_t(addr.addr_len()),
823 ])
824 ))
825 }
826 }
827
828 #[inline]
829 pub(crate) fn connect_v4(fd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> {
830 #[cfg(not(target_arch = "x86"))]
831 unsafe {
832 ret(syscall_readonly!(
833 __NR_connect,
834 fd,
835 by_ref(&encode_sockaddr_v4(addr)),
836 size_of::<sockaddr_in, _>()
837 ))
838 }
839 #[cfg(target_arch = "x86")]
840 unsafe {
841 ret(syscall_readonly!(
842 __NR_socketcall,
843 x86_sys(SYS_CONNECT),
844 slice_just_addr::<ArgReg<SocketArg>, _>(&[
845 fd.into(),
846 by_ref(&encode_sockaddr_v4(addr)),
847 size_of::<sockaddr_in, _>(),
848 ])
849 ))
850 }
851 }
852
853 #[inline]
854 pub(crate) fn connect_v6(fd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> {
855 #[cfg(not(target_arch = "x86"))]
856 unsafe {
857 ret(syscall_readonly!(
858 __NR_connect,
859 fd,
860 by_ref(&encode_sockaddr_v6(addr)),
861 size_of::<sockaddr_in6, _>()
862 ))
863 }
864 #[cfg(target_arch = "x86")]
865 unsafe {
866 ret(syscall_readonly!(
867 __NR_socketcall,
868 x86_sys(SYS_CONNECT),
869 slice_just_addr::<ArgReg<SocketArg>, _>(&[
870 fd.into(),
871 by_ref(&encode_sockaddr_v6(addr)),
872 size_of::<sockaddr_in6, _>(),
873 ])
874 ))
875 }
876 }
877
878 #[inline]
879 pub(crate) fn connect_unix(fd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> {
880 #[cfg(not(target_arch = "x86"))]
881 unsafe {
882 ret(syscall_readonly!(
883 __NR_connect,
884 fd,
885 by_ref(&addr.unix),
886 socklen_t(addr.addr_len())
887 ))
888 }
889 #[cfg(target_arch = "x86")]
890 unsafe {
891 ret(syscall_readonly!(
892 __NR_socketcall,
893 x86_sys(SYS_CONNECT),
894 slice_just_addr::<ArgReg<SocketArg>, _>(&[
895 fd.into(),
896 by_ref(&addr.unix),
897 socklen_t(addr.addr_len()),
898 ])
899 ))
900 }
901 }
902
903 #[inline]
904 pub(crate) fn listen(fd: BorrowedFd<'_>, backlog: c::c_int) -> io::Result<()> {
905 #[cfg(not(target_arch = "x86"))]
906 unsafe {
907 ret(syscall_readonly!(__NR_listen, fd, c_int(backlog)))
908 }
909 #[cfg(target_arch = "x86")]
910 unsafe {
911 ret(syscall_readonly!(
912 __NR_socketcall,
913 x86_sys(SYS_LISTEN),
914 slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), c_int(backlog)])
915 ))
916 }
917 }
918
919 pub(crate) mod sockopt {
920 use super::{c, BorrowedFd};
921 use crate::io;
922 use crate::net::sockopt::Timeout;
923 use crate::net::{Ipv4Addr, Ipv6Addr, SocketType};
924 use c::{SO_RCVTIMEO_NEW, SO_RCVTIMEO_OLD, SO_SNDTIMEO_NEW, SO_SNDTIMEO_OLD};
925 use core::time::Duration;
926 use linux_raw_sys::general::{__kernel_timespec, timeval};
927
928 #[inline]
929 fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32) -> io::Result<T> {
930 use super::*;
931
932 let mut optlen = core::mem::size_of::<T>();
933 debug_assert!(
934 optlen as usize >= core::mem::size_of::<c::c_int>(),
935 "Socket APIs don't ever use `bool` directly"
936 );
937
938 #[cfg(not(target_arch = "x86"))]
939 unsafe {
940 let mut value = MaybeUninit::<T>::uninit();
941 ret(syscall!(
942 __NR_getsockopt,
943 fd,
944 c_uint(level),
945 c_uint(optname),
946 &mut value,
947 by_mut(&mut optlen)
948 ))?;
949
950 assert_eq!(
951 optlen as usize,
952 core::mem::size_of::<T>(),
953 "unexpected getsockopt size"
954 );
955 Ok(value.assume_init())
956 }
957 #[cfg(target_arch = "x86")]
958 unsafe {
959 let mut value = MaybeUninit::<T>::uninit();
960 ret(syscall!(
961 __NR_socketcall,
962 x86_sys(SYS_GETSOCKOPT),
963 slice_just_addr::<ArgReg<SocketArg>, _>(&[
964 fd.into(),
965 c_uint(level),
966 c_uint(optname),
967 (&mut value).into(),
968 by_mut(&mut optlen),
969 ])
970 ))?;
971 assert_eq!(
972 optlen as usize,
973 core::mem::size_of::<T>(),
974 "unexpected getsockopt size"
975 );
976 Ok(value.assume_init())
977 }
978 }
979
980 #[inline]
981 fn setsockopt<T: Copy>(
982 fd: BorrowedFd<'_>,
983 level: u32,
984 optname: u32,
985 value: T,
986 ) -> io::Result<()> {
987 use super::*;
988
989 let optlen = core::mem::size_of::<T>().try_into().unwrap();
990 debug_assert!(
991 optlen as usize >= core::mem::size_of::<c::c_int>(),
992 "Socket APIs don't ever use `bool` directly"
993 );
994
995 #[cfg(not(target_arch = "x86"))]
996 unsafe {
997 ret(syscall_readonly!(
998 __NR_setsockopt,
999 fd,
1000 c_uint(level),
1001 c_uint(optname),
1002 by_ref(&value),
1003 socklen_t(optlen)
1004 ))
1005 }
1006 #[cfg(target_arch = "x86")]
1007 unsafe {
1008 ret(syscall_readonly!(
1009 __NR_socketcall,
1010 x86_sys(SYS_SETSOCKOPT),
1011 slice_just_addr::<ArgReg<SocketArg>, _>(&[
1012 fd.into(),
1013 c_uint(level),
1014 c_uint(optname),
1015 by_ref(&value),
1016 socklen_t(optlen),
1017 ])
1018 ))
1019 }
1020 }
1021
1022 #[inline]
1023 pub(crate) fn get_socket_type(fd: BorrowedFd<'_>) -> io::Result<SocketType> {
1024 getsockopt(fd, c::SOL_SOCKET as _, c::SO_TYPE)
1025 }
1026
1027 #[inline]
1028 pub(crate) fn set_socket_reuseaddr(fd: BorrowedFd<'_>, reuseaddr: bool) -> io::Result<()> {
1029 setsockopt(
1030 fd,
1031 c::SOL_SOCKET as _,
1032 c::SO_REUSEADDR,
1033 from_bool(reuseaddr),
1034 )
1035 }
1036
1037 #[inline]
1038 pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> {
1039 setsockopt(
1040 fd,
1041 c::SOL_SOCKET as _,
1042 c::SO_BROADCAST,
1043 from_bool(broadcast),
1044 )
1045 }
1046
1047 #[inline]
1048 pub(crate) fn get_socket_broadcast(fd: BorrowedFd<'_>) -> io::Result<bool> {
1049 getsockopt(fd, c::SOL_SOCKET as _, c::SO_BROADCAST).map(to_bool)
1050 }
1051
1052 #[inline]
1053 pub(crate) fn set_socket_linger(
1054 fd: BorrowedFd<'_>,
1055 linger: Option<Duration>,
1056 ) -> io::Result<()> {
1057 // Convert `linger` to seconds, rounding up.
1058 let l_linger = if let Some(linger) = linger {
1059 let mut l_linger = linger.as_secs();
1060 if linger.subsec_nanos() != 0 {
1061 l_linger = l_linger.checked_add(1).ok_or(io::Errno::INVAL)?;
1062 }
1063 l_linger.try_into().map_err(|_e| io::Errno::INVAL)?
1064 } else {
1065 0
1066 };
1067 let linger = c::linger {
1068 l_onoff: c::c_int::from(linger.is_some()),
1069 l_linger,
1070 };
1071 setsockopt(fd, c::SOL_SOCKET as _, c::SO_LINGER, linger)
1072 }
1073
1074 #[inline]
1075 pub(crate) fn get_socket_linger(fd: BorrowedFd<'_>) -> io::Result<Option<Duration>> {
1076 let linger: c::linger = getsockopt(fd, c::SOL_SOCKET as _, c::SO_LINGER)?;
1077 Ok((linger.l_onoff != 0).then(|| Duration::from_secs(linger.l_linger as u64)))
1078 }
1079
1080 #[inline]
1081 pub(crate) fn set_socket_passcred(fd: BorrowedFd<'_>, passcred: bool) -> io::Result<()> {
1082 setsockopt(fd, c::SOL_SOCKET as _, c::SO_PASSCRED, from_bool(passcred))
1083 }
1084
1085 #[inline]
1086 pub(crate) fn get_socket_passcred(fd: BorrowedFd<'_>) -> io::Result<bool> {
1087 getsockopt(fd, c::SOL_SOCKET as _, c::SO_PASSCRED).map(to_bool)
1088 }
1089
1090 #[inline]
1091 pub(crate) fn set_socket_timeout(
1092 fd: BorrowedFd<'_>,
1093 id: Timeout,
1094 timeout: Option<Duration>,
1095 ) -> io::Result<()> {
1096 let time = duration_to_linux(timeout)?;
1097 let optname = match id {
1098 Timeout::Recv => SO_RCVTIMEO_NEW,
1099 Timeout::Send => SO_SNDTIMEO_NEW,
1100 };
1101 match setsockopt(fd, c::SOL_SOCKET, optname, time) {
1102 Err(io::Errno::NOPROTOOPT) if SO_RCVTIMEO_NEW != SO_RCVTIMEO_OLD => {
1103 set_socket_timeout_old(fd, id, timeout)
1104 }
1105 otherwise => otherwise,
1106 }
1107 }
1108
1109 /// Same as `set_socket_timeout` but uses `timeval` instead of
1110 /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`.
1111 fn set_socket_timeout_old(
1112 fd: BorrowedFd<'_>,
1113 id: Timeout,
1114 timeout: Option<Duration>,
1115 ) -> io::Result<()> {
1116 let time = duration_to_linux_old(timeout)?;
1117 let optname = match id {
1118 Timeout::Recv => SO_RCVTIMEO_OLD,
1119 Timeout::Send => SO_SNDTIMEO_OLD,
1120 };
1121 setsockopt(fd, c::SOL_SOCKET, optname, time)
1122 }
1123
1124 #[inline]
1125 pub(crate) fn get_socket_timeout(
1126 fd: BorrowedFd<'_>,
1127 id: Timeout,
1128 ) -> io::Result<Option<Duration>> {
1129 let optname = match id {
1130 Timeout::Recv => SO_RCVTIMEO_NEW,
1131 Timeout::Send => SO_SNDTIMEO_NEW,
1132 };
1133 let time: __kernel_timespec = match getsockopt(fd, c::SOL_SOCKET, optname) {
1134 Err(io::Errno::NOPROTOOPT) if SO_RCVTIMEO_NEW != SO_RCVTIMEO_OLD => {
1135 return get_socket_timeout_old(fd, id)
1136 }
1137 otherwise => otherwise?,
1138 };
1139 Ok(duration_from_linux(time))
1140 }
1141
1142 /// Same as `get_socket_timeout` but uses `timeval` instead of
1143 /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`.
1144 fn get_socket_timeout_old(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> {
1145 let optname = match id {
1146 Timeout::Recv => SO_RCVTIMEO_OLD,
1147 Timeout::Send => SO_SNDTIMEO_OLD,
1148 };
1149 let time: timeval = getsockopt(fd, c::SOL_SOCKET, optname)?;
1150 Ok(duration_from_linux_old(time))
1151 }
1152
1153 /// Convert a C `timespec` to a Rust `Option<Duration>`.
1154 #[inline]
1155 fn duration_from_linux(time: __kernel_timespec) -> Option<Duration> {
1156 if time.tv_sec == 0 && time.tv_nsec == 0 {
1157 None
1158 } else {
1159 Some(
1160 Duration::from_secs(time.tv_sec as u64) + Duration::from_nanos(time.tv_nsec as u64),
1161 )
1162 }
1163 }
1164
1165 /// Like `duration_from_linux` but uses Linux's old 32-bit `timeval`.
1166 fn duration_from_linux_old(time: timeval) -> Option<Duration> {
1167 if time.tv_sec == 0 && time.tv_usec == 0 {
1168 None
1169 } else {
1170 Some(
1171 Duration::from_secs(time.tv_sec as u64)
1172 + Duration::from_micros(time.tv_usec as u64),
1173 )
1174 }
1175 }
1176
1177 /// Convert a Rust `Option<Duration>` to a C `timespec`.
1178 #[inline]
1179 fn duration_to_linux(timeout: Option<Duration>) -> io::Result<__kernel_timespec> {
1180 Ok(match timeout {
1181 Some(timeout) => {
1182 if timeout == Duration::ZERO {
1183 return Err(io::Errno::INVAL);
1184 }
1185 let mut timeout = __kernel_timespec {
1186 tv_sec: timeout.as_secs().try_into().unwrap_or(i64::MAX),
1187 tv_nsec: timeout.subsec_nanos().into(),
1188 };
1189 if timeout.tv_sec == 0 && timeout.tv_nsec == 0 {
1190 timeout.tv_nsec = 1;
1191 }
1192 timeout
1193 }
1194 None => __kernel_timespec {
1195 tv_sec: 0,
1196 tv_nsec: 0,
1197 },
1198 })
1199 }
1200
1201 /// Like `duration_to_linux` but uses Linux's old 32-bit `timeval`.
1202 fn duration_to_linux_old(timeout: Option<Duration>) -> io::Result<timeval> {
1203 Ok(match timeout {
1204 Some(timeout) => {
1205 if timeout == Duration::ZERO {
1206 return Err(io::Errno::INVAL);
1207 }
1208
1209 // `subsec_micros` rounds down, so we use `subsec_nanos` and
1210 // manually round up.
1211 let mut timeout = timeval {
1212 tv_sec: timeout.as_secs().try_into().unwrap_or(c::c_long::MAX),
1213 tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _,
1214 };
1215 if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
1216 timeout.tv_usec = 1;
1217 }
1218 timeout
1219 }
1220 None => timeval {
1221 tv_sec: 0,
1222 tv_usec: 0,
1223 },
1224 })
1225 }
1226
1227 #[inline]
1228 pub(crate) fn get_socket_error(fd: BorrowedFd<'_>) -> io::Result<Result<(), io::Errno>> {
1229 let err: c::c_int = getsockopt(fd, c::SOL_SOCKET as _, c::SO_ERROR)?;
1230 Ok(if err == 0 {
1231 Ok(())
1232 } else {
1233 Err(io::Errno::from_raw_os_error(err))
1234 })
1235 }
1236
1237 #[inline]
1238 pub(crate) fn set_socket_keepalive(fd: BorrowedFd<'_>, keepalive: bool) -> io::Result<()> {
1239 setsockopt(
1240 fd,
1241 c::SOL_SOCKET as _,
1242 c::SO_KEEPALIVE,
1243 from_bool(keepalive),
1244 )
1245 }
1246
1247 #[inline]
1248 pub(crate) fn get_socket_keepalive(fd: BorrowedFd<'_>) -> io::Result<bool> {
1249 getsockopt(fd, c::SOL_SOCKET as _, c::SO_KEEPALIVE).map(to_bool)
1250 }
1251
1252 #[inline]
1253 pub(crate) fn set_socket_recv_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
1254 let size: c::c_int = size.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1255 setsockopt(fd, c::SOL_SOCKET as _, c::SO_RCVBUF, size)
1256 }
1257
1258 #[inline]
1259 pub(crate) fn get_socket_recv_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
1260 getsockopt(fd, c::SOL_SOCKET as _, c::SO_RCVBUF).map(|size: u32| size as usize)
1261 }
1262
1263 #[inline]
1264 pub(crate) fn set_socket_send_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
1265 let size: c::c_int = size.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1266 setsockopt(fd, c::SOL_SOCKET as _, c::SO_SNDBUF, size)
1267 }
1268
1269 #[inline]
1270 pub(crate) fn get_socket_send_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
1271 getsockopt(fd, c::SOL_SOCKET as _, c::SO_SNDBUF).map(|size: u32| size as usize)
1272 }
1273
1274 #[inline]
1275 pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> {
1276 setsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL, ttl)
1277 }
1278
1279 #[inline]
1280 pub(crate) fn get_ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
1281 getsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL)
1282 }
1283
1284 #[inline]
1285 pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> {
1286 setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY, from_bool(only_v6))
1287 }
1288
1289 #[inline]
1290 pub(crate) fn get_ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> {
1291 getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY).map(to_bool)
1292 }
1293
1294 #[inline]
1295 pub(crate) fn set_ip_multicast_loop(
1296 fd: BorrowedFd<'_>,
1297 multicast_loop: bool,
1298 ) -> io::Result<()> {
1299 setsockopt(
1300 fd,
1301 c::IPPROTO_IP as _,
1302 c::IP_MULTICAST_LOOP,
1303 from_bool(multicast_loop),
1304 )
1305 }
1306
1307 #[inline]
1308 pub(crate) fn get_ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
1309 getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_LOOP).map(to_bool)
1310 }
1311
1312 #[inline]
1313 pub(crate) fn set_ip_multicast_ttl(fd: BorrowedFd<'_>, multicast_ttl: u32) -> io::Result<()> {
1314 setsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL, multicast_ttl)
1315 }
1316
1317 #[inline]
1318 pub(crate) fn get_ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
1319 getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL)
1320 }
1321
1322 #[inline]
1323 pub(crate) fn set_ipv6_multicast_loop(
1324 fd: BorrowedFd<'_>,
1325 multicast_loop: bool,
1326 ) -> io::Result<()> {
1327 setsockopt(
1328 fd,
1329 c::IPPROTO_IPV6 as _,
1330 c::IPV6_MULTICAST_LOOP,
1331 from_bool(multicast_loop),
1332 )
1333 }
1334
1335 #[inline]
1336 pub(crate) fn get_ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
1337 getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_MULTICAST_LOOP).map(to_bool)
1338 }
1339
1340 #[inline]
1341 pub(crate) fn set_ipv6_multicast_hops(
1342 fd: BorrowedFd<'_>,
1343 multicast_hops: u32,
1344 ) -> io::Result<()> {
1345 setsockopt(
1346 fd,
1347 c::IPPROTO_IP as _,
1348 c::IPV6_MULTICAST_HOPS,
1349 multicast_hops,
1350 )
1351 }
1352
1353 #[inline]
1354 pub(crate) fn get_ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> {
1355 getsockopt(fd, c::IPPROTO_IP as _, c::IPV6_MULTICAST_HOPS)
1356 }
1357
1358 #[inline]
1359 pub(crate) fn set_ip_add_membership(
1360 fd: BorrowedFd<'_>,
1361 multiaddr: &Ipv4Addr,
1362 interface: &Ipv4Addr,
1363 ) -> io::Result<()> {
1364 let mreq = to_imr(multiaddr, interface);
1365 setsockopt(fd, c::IPPROTO_IP as _, c::IP_ADD_MEMBERSHIP, mreq)
1366 }
1367
1368 #[inline]
1369 pub(crate) fn set_ipv6_add_membership(
1370 fd: BorrowedFd<'_>,
1371 multiaddr: &Ipv6Addr,
1372 interface: u32,
1373 ) -> io::Result<()> {
1374 let mreq = to_ipv6mr(multiaddr, interface);
1375 setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_ADD_MEMBERSHIP, mreq)
1376 }
1377
1378 #[inline]
1379 pub(crate) fn set_ip_drop_membership(
1380 fd: BorrowedFd<'_>,
1381 multiaddr: &Ipv4Addr,
1382 interface: &Ipv4Addr,
1383 ) -> io::Result<()> {
1384 let mreq = to_imr(multiaddr, interface);
1385 setsockopt(fd, c::IPPROTO_IP as _, c::IP_DROP_MEMBERSHIP, mreq)
1386 }
1387
1388 #[inline]
1389 pub(crate) fn set_ipv6_drop_membership(
1390 fd: BorrowedFd<'_>,
1391 multiaddr: &Ipv6Addr,
1392 interface: u32,
1393 ) -> io::Result<()> {
1394 let mreq = to_ipv6mr(multiaddr, interface);
1395 setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_DROP_MEMBERSHIP, mreq)
1396 }
1397
1398 #[inline]
1399 pub(crate) fn get_ipv6_unicast_hops(fd: BorrowedFd<'_>) -> io::Result<u8> {
1400 getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_UNICAST_HOPS).map(|hops: c::c_int| hops as u8)
1401 }
1402
1403 #[inline]
1404 pub(crate) fn set_ipv6_unicast_hops(fd: BorrowedFd<'_>, hops: Option<u8>) -> io::Result<()> {
1405 let hops = match hops {
1406 Some(hops) => hops.into(),
1407 None => -1,
1408 };
1409 setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_UNICAST_HOPS, hops)
1410 }
1411
1412 #[inline]
1413 pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> {
1414 setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY, from_bool(nodelay))
1415 }
1416
1417 #[inline]
1418 pub(crate) fn get_tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> {
1419 getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY).map(to_bool)
1420 }
1421
1422 #[inline]
1423 fn to_imr(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq {
1424 c::ip_mreq {
1425 imr_multiaddr: to_imr_addr(multiaddr),
1426 imr_interface: to_imr_addr(interface),
1427 }
1428 }
1429
1430 #[inline]
1431 fn to_imr_addr(addr: &Ipv4Addr) -> c::in_addr {
1432 c::in_addr {
1433 s_addr: u32::from_ne_bytes(addr.octets()),
1434 }
1435 }
1436
1437 #[inline]
1438 fn to_ipv6mr(multiaddr: &Ipv6Addr, interface: u32) -> c::ipv6_mreq {
1439 c::ipv6_mreq {
1440 ipv6mr_multiaddr: to_ipv6mr_multiaddr(multiaddr),
1441 ipv6mr_ifindex: to_ipv6mr_interface(interface),
1442 }
1443 }
1444
1445 #[inline]
1446 fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr {
1447 c::in6_addr {
1448 in6_u: linux_raw_sys::net::in6_addr__bindgen_ty_1 {
1449 u6_addr8: multiaddr.octets(),
1450 },
1451 }
1452 }
1453
1454 #[inline]
1455 fn to_ipv6mr_interface(interface: u32) -> c::c_int {
1456 interface as c::c_int
1457 }
1458
1459 #[inline]
1460 fn from_bool(value: bool) -> c::c_uint {
1461 c::c_uint::from(value)
1462 }
1463
1464 #[inline]
1465 fn to_bool(value: c::c_uint) -> bool {
1466 value != 0
1467 }
1468 }