]> git.proxmox.com Git - rustc.git/blob - vendor/rustix-0.37.11/src/backend/linux_raw/net/syscalls.rs
New upstream version 1.72.1+dfsg1
[rustc.git] / vendor / rustix-0.37.11 / 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::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::{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]
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]
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]
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]
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]
146 pub(crate) fn accept_with(fd: BorrowedFd<'_>, flags: SocketFlags) -> 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]
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]
201 pub(crate) fn acceptfrom_with(
202 fd: BorrowedFd<'_>,
203 flags: SocketFlags,
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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`.
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]
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`.
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]
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`.
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]
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`.
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]
1069 pub(crate) fn get_socket_error(fd: BorrowedFd<'_>) -> io::Result<Result<(), io::Errno>> {
1070 let err: c::c_int = getsockopt(fd, c::SOL_SOCKET as _, c::SO_ERROR)?;
1071 Ok(if err == 0 {
1072 Ok(())
1073 } else {
1074 Err(io::Errno::from_raw_os_error(err))
1075 })
1076 }
1077
1078 #[inline]
1079 pub(crate) fn set_socket_keepalive(fd: BorrowedFd<'_>, keepalive: bool) -> io::Result<()> {
1080 setsockopt(
1081 fd,
1082 c::SOL_SOCKET as _,
1083 c::SO_KEEPALIVE,
1084 from_bool(keepalive),
1085 )
1086 }
1087
1088 #[inline]
1089 pub(crate) fn get_socket_keepalive(fd: BorrowedFd<'_>) -> io::Result<bool> {
1090 getsockopt(fd, c::SOL_SOCKET as _, c::SO_KEEPALIVE).map(to_bool)
1091 }
1092
1093 #[inline]
1094 pub(crate) fn set_socket_recv_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
1095 let size: c::c_int = size.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1096 setsockopt(fd, c::SOL_SOCKET as _, c::SO_RCVBUF, size)
1097 }
1098
1099 #[inline]
1100 pub(crate) fn get_socket_recv_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
1101 getsockopt(fd, c::SOL_SOCKET as _, c::SO_RCVBUF).map(|size: u32| size as usize)
1102 }
1103
1104 #[inline]
1105 pub(crate) fn set_socket_send_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
1106 let size: c::c_int = size.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1107 setsockopt(fd, c::SOL_SOCKET as _, c::SO_SNDBUF, size)
1108 }
1109
1110 #[inline]
1111 pub(crate) fn get_socket_send_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
1112 getsockopt(fd, c::SOL_SOCKET as _, c::SO_SNDBUF).map(|size: u32| size as usize)
1113 }
1114
1115 #[inline]
1116 pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> {
1117 setsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL, ttl)
1118 }
1119
1120 #[inline]
1121 pub(crate) fn get_ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
1122 getsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL)
1123 }
1124
1125 #[inline]
1126 pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> {
1127 setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY, from_bool(only_v6))
1128 }
1129
1130 #[inline]
1131 pub(crate) fn get_ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> {
1132 getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY).map(to_bool)
1133 }
1134
1135 #[inline]
1136 pub(crate) fn set_ip_multicast_loop(
1137 fd: BorrowedFd<'_>,
1138 multicast_loop: bool,
1139 ) -> io::Result<()> {
1140 setsockopt(
1141 fd,
1142 c::IPPROTO_IP as _,
1143 c::IP_MULTICAST_LOOP,
1144 from_bool(multicast_loop),
1145 )
1146 }
1147
1148 #[inline]
1149 pub(crate) fn get_ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
1150 getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_LOOP).map(to_bool)
1151 }
1152
1153 #[inline]
1154 pub(crate) fn set_ip_multicast_ttl(fd: BorrowedFd<'_>, multicast_ttl: u32) -> io::Result<()> {
1155 setsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL, multicast_ttl)
1156 }
1157
1158 #[inline]
1159 pub(crate) fn get_ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
1160 getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL)
1161 }
1162
1163 #[inline]
1164 pub(crate) fn set_ipv6_multicast_loop(
1165 fd: BorrowedFd<'_>,
1166 multicast_loop: bool,
1167 ) -> io::Result<()> {
1168 setsockopt(
1169 fd,
1170 c::IPPROTO_IPV6 as _,
1171 c::IPV6_MULTICAST_LOOP,
1172 from_bool(multicast_loop),
1173 )
1174 }
1175
1176 #[inline]
1177 pub(crate) fn get_ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
1178 getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_MULTICAST_LOOP).map(to_bool)
1179 }
1180
1181 #[inline]
1182 pub(crate) fn set_ipv6_multicast_hops(
1183 fd: BorrowedFd<'_>,
1184 multicast_hops: u32,
1185 ) -> io::Result<()> {
1186 setsockopt(
1187 fd,
1188 c::IPPROTO_IP as _,
1189 c::IPV6_MULTICAST_LOOP,
1190 multicast_hops,
1191 )
1192 }
1193
1194 #[inline]
1195 pub(crate) fn get_ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> {
1196 getsockopt(fd, c::IPPROTO_IP as _, c::IPV6_MULTICAST_LOOP)
1197 }
1198
1199 #[inline]
1200 pub(crate) fn set_ip_add_membership(
1201 fd: BorrowedFd<'_>,
1202 multiaddr: &Ipv4Addr,
1203 interface: &Ipv4Addr,
1204 ) -> io::Result<()> {
1205 let mreq = to_imr(multiaddr, interface);
1206 setsockopt(fd, c::IPPROTO_IP as _, c::IP_ADD_MEMBERSHIP, mreq)
1207 }
1208
1209 #[inline]
1210 pub(crate) fn set_ipv6_add_membership(
1211 fd: BorrowedFd<'_>,
1212 multiaddr: &Ipv6Addr,
1213 interface: u32,
1214 ) -> io::Result<()> {
1215 let mreq = to_ipv6mr(multiaddr, interface);
1216 setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_ADD_MEMBERSHIP, mreq)
1217 }
1218
1219 #[inline]
1220 pub(crate) fn set_ip_drop_membership(
1221 fd: BorrowedFd<'_>,
1222 multiaddr: &Ipv4Addr,
1223 interface: &Ipv4Addr,
1224 ) -> io::Result<()> {
1225 let mreq = to_imr(multiaddr, interface);
1226 setsockopt(fd, c::IPPROTO_IP as _, c::IP_DROP_MEMBERSHIP, mreq)
1227 }
1228
1229 #[inline]
1230 pub(crate) fn set_ipv6_drop_membership(
1231 fd: BorrowedFd<'_>,
1232 multiaddr: &Ipv6Addr,
1233 interface: u32,
1234 ) -> io::Result<()> {
1235 let mreq = to_ipv6mr(multiaddr, interface);
1236 setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_DROP_MEMBERSHIP, mreq)
1237 }
1238
1239 #[inline]
1240 pub(crate) fn get_ipv6_unicast_hops(fd: BorrowedFd<'_>) -> io::Result<u8> {
1241 getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_UNICAST_HOPS).map(|hops: c::c_int| hops as u8)
1242 }
1243
1244 #[inline]
1245 pub(crate) fn set_ipv6_unicast_hops(fd: BorrowedFd<'_>, hops: Option<u8>) -> io::Result<()> {
1246 let hops = match hops {
1247 Some(hops) => hops as c::c_int,
1248 None => -1,
1249 };
1250 setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_UNICAST_HOPS, hops)
1251 }
1252
1253 #[inline]
1254 pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> {
1255 setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY, from_bool(nodelay))
1256 }
1257
1258 #[inline]
1259 pub(crate) fn get_tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> {
1260 getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY).map(to_bool)
1261 }
1262
1263 #[inline]
1264 fn to_imr(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq {
1265 c::ip_mreq {
1266 imr_multiaddr: to_imr_addr(multiaddr),
1267 imr_interface: to_imr_addr(interface),
1268 }
1269 }
1270
1271 #[inline]
1272 fn to_imr_addr(addr: &Ipv4Addr) -> c::in_addr {
1273 c::in_addr {
1274 s_addr: u32::from_ne_bytes(addr.octets()),
1275 }
1276 }
1277
1278 #[inline]
1279 fn to_ipv6mr(multiaddr: &Ipv6Addr, interface: u32) -> c::ipv6_mreq {
1280 c::ipv6_mreq {
1281 ipv6mr_multiaddr: to_ipv6mr_multiaddr(multiaddr),
1282 ipv6mr_ifindex: to_ipv6mr_interface(interface),
1283 }
1284 }
1285
1286 #[inline]
1287 fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr {
1288 c::in6_addr {
1289 in6_u: linux_raw_sys::general::in6_addr__bindgen_ty_1 {
1290 u6_addr8: multiaddr.octets(),
1291 },
1292 }
1293 }
1294
1295 #[inline]
1296 fn to_ipv6mr_interface(interface: u32) -> c::c_int {
1297 interface as c::c_int
1298 }
1299
1300 #[inline]
1301 fn from_bool(value: bool) -> c::c_uint {
1302 c::c_uint::from(value)
1303 }
1304
1305 #[inline]
1306 fn to_bool(value: c::c_uint) -> bool {
1307 value != 0
1308 }
1309 }