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::cmp::min; |
14 | use core::mem::MaybeUninit; |
15 | |
16 | pub 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 | )))] |
25 | mod 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 | )))] |
34 | pub 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§ion=2 |
63 | /// [illumos]: https://illumos.org/man/3SOCKET/recv |
64 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Receiving-Data.html |
65 | #[inline ] |
66 | pub 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 ] |
81 | pub 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: usize = 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, init_len:min(v1:length, v2: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§ion=2 |
119 | /// [illumos]: https://illumos.org/man/3SOCKET/send |
120 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Sending-Data.html |
121 | #[inline ] |
122 | pub 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§ion=2 |
154 | /// [illumos]: https://illumos.org/man/3SOCKET/recvfrom |
155 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Receiving-Datagrams.html |
156 | #[inline ] |
157 | pub 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 ] |
178 | pub 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: usize, addr: Option) = 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: &mut [u8], uninit: &mut [MaybeUninit]) = unsafe { split_init(buf, init_len:min(v1:length, v2: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§ion=2 |
223 | /// [illumos]: https://illumos.org/man/3SOCKET/sendto |
224 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Sending-Datagrams.html |
225 | pub 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 | |
234 | fn _sendto( |
235 | fd: BorrowedFd<'_>, |
236 | buf: &[u8], |
237 | flags: SendFlags, |
238 | addr: &SocketAddr, |
239 | ) -> io::Result<usize> { |
240 | match addr { |
241 | SocketAddr::V4(v4: &SocketAddrV4) => backend::net::syscalls::sendto_v4(fd, buf, flags, addr:v4), |
242 | SocketAddr::V6(v6: &SocketAddrV6) => backend::net::syscalls::sendto_v6(fd, buf, flags, addr: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§ion=2 |
271 | /// [illumos]: https://illumos.org/man/3SOCKET/sendto |
272 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Sending-Datagrams.html |
273 | pub 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 | |
282 | fn _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: &SocketAddrV4) => backend::net::syscalls::sendto_v4(fd, buf, flags, addr:v4), |
290 | SocketAddrAny::V6(v6: &SocketAddrV6) => backend::net::syscalls::sendto_v6(fd, buf, flags, addr:v6), |
291 | #[cfg (unix)] |
292 | SocketAddrAny::Unix(unix: &SocketAddrUnix) => backend::net::syscalls::sendto_unix(fd, buf, flags, addr:unix), |
293 | #[cfg (target_os = "linux" )] |
294 | SocketAddrAny::Xdp(xdp: &SocketAddrXdp) => backend::net::syscalls::sendto_xdp(fd, buf, flags, addr: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§ion=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" )] |
327 | pub 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§ion=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" )] |
365 | pub 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§ion=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" )] |
404 | pub 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" )] |
423 | pub 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 | } |
431 | |