rustix/net/send_recv/
mod.rs

1//! `recv`, `send`, and variants.
2
3#![allow(unsafe_code)]
4
5use crate::buffer::split_init;
6#[cfg(target_os = "linux")]
7use crate::net::xdp::SocketAddrXdp;
8#[cfg(unix)]
9use crate::net::SocketAddrUnix;
10use crate::net::{SocketAddr, SocketAddrAny, SocketAddrV4, SocketAddrV6};
11use crate::{backend, io};
12use backend::fd::{AsFd, BorrowedFd};
13use core::cmp::min;
14use core::mem::MaybeUninit;
15
16pub use backend::net::send_recv::{RecvFlags, SendFlags};
17
18#[cfg(not(any(
19    windows,
20    target_os = "espidf",
21    target_os = "redox",
22    target_os = "vita",
23    target_os = "wasi"
24)))]
25mod msg;
26
27#[cfg(not(any(
28    windows,
29    target_os = "espidf",
30    target_os = "redox",
31    target_os = "vita",
32    target_os = "wasi"
33)))]
34pub use msg::*;
35
36/// `recv(fd, buf, flags)`—Reads data from a socket.
37///
38/// This takes a `&mut [u8]` which Rust requires to contain initialized memory.
39/// To use an uninitialized buffer, use [`recv_uninit`].
40///
41/// # References
42///  - [Beej's Guide to Network Programming]
43///  - [POSIX]
44///  - [Linux]
45///  - [Apple]
46///  - [Winsock]
47///  - [FreeBSD]
48///  - [NetBSD]
49///  - [OpenBSD]
50///  - [DragonFly BSD]
51///  - [illumos]
52///  - [glibc]
53///
54/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendrecv
55/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/recv.html
56/// [Linux]: https://man7.org/linux/man-pages/man2/recv.2.html
57/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recv.2.html
58/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recv
59/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recv&sektion=2
60/// [NetBSD]: https://man.netbsd.org/recv.2
61/// [OpenBSD]: https://man.openbsd.org/recv.2
62/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recv&section=2
63/// [illumos]: https://illumos.org/man/3SOCKET/recv
64/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Receiving-Data.html
65#[inline]
66pub fn recv<Fd: AsFd>(fd: Fd, buf: &mut [u8], flags: RecvFlags) -> io::Result<usize> {
67    unsafe { backend::net::syscalls::recv(fd.as_fd(), buf.as_mut_ptr(), buf.len(), flags) }
68}
69
70/// `recv(fd, buf, flags)`—Reads data from a socket.
71///
72/// This is equivalent to [`recv`], except that it can read into uninitialized
73/// memory. It returns the slice that was initialized by this function and the
74/// slice that remains uninitialized.
75///
76/// Because this interface returns the length via the returned slice, it's
77/// unsable to return the untruncated length that would be returned when the
78/// `RecvFlags::TRUNC` flag is used. If you need the untruncated length, use
79/// [`recv`].
80#[inline]
81pub fn recv_uninit<Fd: AsFd>(
82    fd: Fd,
83    buf: &mut [MaybeUninit<u8>],
84    flags: RecvFlags,
85) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>])> {
86    let length = unsafe {
87        backend::net::syscalls::recv(fd.as_fd(), buf.as_mut_ptr().cast::<u8>(), buf.len(), flags)?
88    };
89
90    // If the `TRUNC` flag is set, the returned `length` may be longer than the
91    // buffer length.
92    Ok(unsafe { split_init(buf, min(length, buf.len())) })
93}
94
95/// `send(fd, buf, flags)`—Writes data to a socket.
96///
97/// # References
98///  - [Beej's Guide to Network Programming]
99///  - [POSIX]
100///  - [Linux]
101///  - [Apple]
102///  - [Winsock]
103///  - [FreeBSD]
104///  - [NetBSD]
105///  - [OpenBSD]
106///  - [DragonFly BSD]
107///  - [illumos]
108///  - [glibc]
109///
110/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendrecv
111/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/send.html
112/// [Linux]: https://man7.org/linux/man-pages/man2/send.2.html
113/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/send.2.html
114/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send
115/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=send&sektion=2
116/// [NetBSD]: https://man.netbsd.org/send.2
117/// [OpenBSD]: https://man.openbsd.org/send.2
118/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=send&section=2
119/// [illumos]: https://illumos.org/man/3SOCKET/send
120/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Sending-Data.html
121#[inline]
122pub fn send<Fd: AsFd>(fd: Fd, buf: &[u8], flags: SendFlags) -> io::Result<usize> {
123    backend::net::syscalls::send(fd.as_fd(), buf, flags)
124}
125
126/// `recvfrom(fd, buf, flags, addr, len)`—Reads data from a socket and
127/// returns the sender address.
128///
129/// This takes a `&mut [u8]` which Rust requires to contain initialized memory.
130/// To use an uninitialized buffer, use [`recvfrom_uninit`].
131///
132/// # References
133///  - [Beej's Guide to Network Programming]
134///  - [POSIX]
135///  - [Linux]
136///  - [Apple]
137///  - [Winsock]
138///  - [FreeBSD]
139///  - [NetBSD]
140///  - [OpenBSD]
141///  - [DragonFly BSD]
142///  - [illumos]
143///  - [glibc]
144///
145/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv
146/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/recvfrom.html
147/// [Linux]: https://man7.org/linux/man-pages/man2/recvfrom.2.html
148/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recvfrom.2.html
149/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recvfrom
150/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recvfrom&sektion=2
151/// [NetBSD]: https://man.netbsd.org/recvfrom.2
152/// [OpenBSD]: https://man.openbsd.org/recvfrom.2
153/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recvfrom&section=2
154/// [illumos]: https://illumos.org/man/3SOCKET/recvfrom
155/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Receiving-Datagrams.html
156#[inline]
157pub fn recvfrom<Fd: AsFd>(
158    fd: Fd,
159    buf: &mut [u8],
160    flags: RecvFlags,
161) -> io::Result<(usize, Option<SocketAddrAny>)> {
162    unsafe { backend::net::syscalls::recvfrom(fd.as_fd(), buf.as_mut_ptr(), buf.len(), flags) }
163}
164
165/// `recvfrom(fd, buf, flags, addr, len)`—Reads data from a socket and
166/// returns the sender address.
167///
168/// This is equivalent to [`recvfrom`], except that it can read into
169/// uninitialized memory. It returns the slice that was initialized by this
170/// function and the slice that remains uninitialized.
171///
172/// Because this interface returns the length via the returned slice, it's
173/// unsable to return the untruncated length that would be returned when the
174/// `RecvFlags::TRUNC` flag is used. If you need the untruncated length, use
175/// [`recvfrom`].
176#[allow(clippy::type_complexity)]
177#[inline]
178pub fn recvfrom_uninit<Fd: AsFd>(
179    fd: Fd,
180    buf: &mut [MaybeUninit<u8>],
181    flags: RecvFlags,
182) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>], Option<SocketAddrAny>)> {
183    let (length, addr) = unsafe {
184        backend::net::syscalls::recvfrom(
185            fd.as_fd(),
186            buf.as_mut_ptr().cast::<u8>(),
187            buf.len(),
188            flags,
189        )?
190    };
191
192    // If the `TRUNC` flag is set, the returned `length` may be longer than the
193    // buffer length.
194    let (init, uninit) = unsafe { split_init(buf, min(length, buf.len())) };
195    Ok((init, uninit, addr))
196}
197
198/// `sendto(fd, buf, flags, addr)`—Writes data to a socket to a specific IP
199/// address.
200///
201/// # References
202///  - [Beej's Guide to Network Programming]
203///  - [POSIX]
204///  - [Linux]
205///  - [Apple]
206///  - [Winsock]
207///  - [FreeBSD]
208///  - [NetBSD]
209///  - [OpenBSD]
210///  - [DragonFly BSD]
211///  - [illumos]
212///  - [glibc]
213///
214/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv
215/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendto.html
216/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html
217/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html
218/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto
219/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2
220/// [NetBSD]: https://man.netbsd.org/sendto.2
221/// [OpenBSD]: https://man.openbsd.org/sendto.2
222/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto&section=2
223/// [illumos]: https://illumos.org/man/3SOCKET/sendto
224/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Sending-Datagrams.html
225pub fn sendto<Fd: AsFd>(
226    fd: Fd,
227    buf: &[u8],
228    flags: SendFlags,
229    addr: &SocketAddr,
230) -> io::Result<usize> {
231    _sendto(fd.as_fd(), buf, flags, addr)
232}
233
234fn _sendto(
235    fd: BorrowedFd<'_>,
236    buf: &[u8],
237    flags: SendFlags,
238    addr: &SocketAddr,
239) -> io::Result<usize> {
240    match addr {
241        SocketAddr::V4(v4) => backend::net::syscalls::sendto_v4(fd, buf, flags, v4),
242        SocketAddr::V6(v6) => backend::net::syscalls::sendto_v6(fd, buf, flags, v6),
243    }
244}
245
246/// `sendto(fd, buf, flags, addr)`—Writes data to a socket to a specific
247/// address.
248///
249/// # References
250///  - [Beej's Guide to Network Programming]
251///  - [POSIX]
252///  - [Linux]
253///  - [Apple]
254///  - [Winsock]
255///  - [FreeBSD]
256///  - [NetBSD]
257///  - [OpenBSD]
258///  - [DragonFly BSD]
259///  - [illumos]
260///  - [glibc]
261///
262/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv
263/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendto.html
264/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html
265/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html
266/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto
267/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2
268/// [NetBSD]: https://man.netbsd.org/sendto.2
269/// [OpenBSD]: https://man.openbsd.org/sendto.2
270/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto&section=2
271/// [illumos]: https://illumos.org/man/3SOCKET/sendto
272/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Sending-Datagrams.html
273pub fn sendto_any<Fd: AsFd>(
274    fd: Fd,
275    buf: &[u8],
276    flags: SendFlags,
277    addr: &SocketAddrAny,
278) -> io::Result<usize> {
279    _sendto_any(fd.as_fd(), buf, flags, addr)
280}
281
282fn _sendto_any(
283    fd: BorrowedFd<'_>,
284    buf: &[u8],
285    flags: SendFlags,
286    addr: &SocketAddrAny,
287) -> io::Result<usize> {
288    match addr {
289        SocketAddrAny::V4(v4) => backend::net::syscalls::sendto_v4(fd, buf, flags, v4),
290        SocketAddrAny::V6(v6) => backend::net::syscalls::sendto_v6(fd, buf, flags, v6),
291        #[cfg(unix)]
292        SocketAddrAny::Unix(unix) => backend::net::syscalls::sendto_unix(fd, buf, flags, unix),
293        #[cfg(target_os = "linux")]
294        SocketAddrAny::Xdp(xdp) => backend::net::syscalls::sendto_xdp(fd, buf, flags, xdp),
295    }
296}
297
298/// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_in))`—Writes data to
299/// a socket to a specific IPv4 address.
300///
301/// # References
302///  - [Beej's Guide to Network Programming]
303///  - [POSIX]
304///  - [Linux]
305///  - [Apple]
306///  - [Winsock]
307///  - [FreeBSD]
308///  - [NetBSD]
309///  - [OpenBSD]
310///  - [DragonFly BSD]
311///  - [illumos]
312///  - [glibc]
313///
314/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv
315/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendto.html
316/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html
317/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html
318/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto
319/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2
320/// [NetBSD]: https://man.netbsd.org/sendto.2
321/// [OpenBSD]: https://man.openbsd.org/sendto.2
322/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto&section=2
323/// [illumos]: https://illumos.org/man/3SOCKET/sendto
324/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Sending-Datagrams.html
325#[inline]
326#[doc(alias = "sendto")]
327pub fn sendto_v4<Fd: AsFd>(
328    fd: Fd,
329    buf: &[u8],
330    flags: SendFlags,
331    addr: &SocketAddrV4,
332) -> io::Result<usize> {
333    backend::net::syscalls::sendto_v4(fd.as_fd(), buf, flags, addr)
334}
335
336/// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_in6))`—Writes data
337/// to a socket to a specific IPv6 address.
338///
339/// # References
340///  - [Beej's Guide to Network Programming]
341///  - [POSIX]
342///  - [Linux]
343///  - [Apple]
344///  - [Winsock]
345///  - [FreeBSD]
346///  - [NetBSD]
347///  - [OpenBSD]
348///  - [DragonFly BSD]
349///  - [illumos]
350///  - [glibc]
351///
352/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv
353/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendto.html
354/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html
355/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html
356/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto
357/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2
358/// [NetBSD]: https://man.netbsd.org/sendto.2
359/// [OpenBSD]: https://man.openbsd.org/sendto.2
360/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto&section=2
361/// [illumos]: https://illumos.org/man/3SOCKET/sendto
362/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Sending-Datagrams.html
363#[inline]
364#[doc(alias = "sendto")]
365pub fn sendto_v6<Fd: AsFd>(
366    fd: Fd,
367    buf: &[u8],
368    flags: SendFlags,
369    addr: &SocketAddrV6,
370) -> io::Result<usize> {
371    backend::net::syscalls::sendto_v6(fd.as_fd(), buf, flags, addr)
372}
373
374/// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_un))`—Writes data to
375/// a socket to a specific Unix-domain socket address.
376///
377/// # References
378///  - [Beej's Guide to Network Programming]
379///  - [POSIX]
380///  - [Linux]
381///  - [Apple]
382///  - [Winsock]
383///  - [FreeBSD]
384///  - [NetBSD]
385///  - [OpenBSD]
386///  - [DragonFly BSD]
387///  - [illumos]
388///  - [glibc]
389///
390/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv
391/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendto.html
392/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html
393/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html
394/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto
395/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2
396/// [NetBSD]: https://man.netbsd.org/sendto.2
397/// [OpenBSD]: https://man.openbsd.org/sendto.2
398/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto&section=2
399/// [illumos]: https://illumos.org/man/3SOCKET/sendto
400/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Sending-Datagrams.html
401#[cfg(unix)]
402#[inline]
403#[doc(alias = "sendto")]
404pub fn sendto_unix<Fd: AsFd>(
405    fd: Fd,
406    buf: &[u8],
407    flags: SendFlags,
408    addr: &SocketAddrUnix,
409) -> io::Result<usize> {
410    backend::net::syscalls::sendto_unix(fd.as_fd(), buf, flags, addr)
411}
412
413/// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_xdp))`—Writes data
414/// to a socket to a specific XDP address.
415///
416/// # References
417///  - [Linux]
418///
419/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html
420#[cfg(target_os = "linux")]
421#[inline]
422#[doc(alias = "sendto")]
423pub fn sendto_xdp<Fd: AsFd>(
424    fd: Fd,
425    buf: &[u8],
426    flags: SendFlags,
427    addr: &SocketAddrXdp,
428) -> io::Result<usize> {
429    backend::net::syscalls::sendto_xdp(fd.as_fd(), buf, flags, addr)
430}