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