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