1#[cfg(test)]
2mod tests;
3
4use crate::ffi::{c_int, c_void};
5use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut};
6use crate::mem::MaybeUninit;
7use crate::net::{
8 Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs,
9};
10use crate::sys::helpers::run_with_cstr;
11use crate::sys::net::connection::each_addr;
12use crate::sys::{AsInner, FromInner};
13use crate::time::Duration;
14use crate::{cmp, fmt, mem, ptr};
15
16cfg_select! {
17 target_os = "hermit" => {
18 mod hermit;
19 pub use hermit::*;
20 }
21 target_os = "solid_asp3" => {
22 mod solid;
23 pub use solid::*;
24 }
25 any(target_family = "unix", target_os = "wasi") => {
26 mod unix;
27 pub use unix::*;
28 }
29 target_os = "windows" => {
30 mod windows;
31 pub use windows::*;
32 }
33 _ => {}
34}
35
36use netc as c;
37
38const MAX_SEND_LEN: usize =
39 if cfg!(target_vendor = "apple") { c_int::MAX as usize } else { <wrlen_t>::MAX as usize };
40
41cfg_select! {
42 any(
43 target_os = "dragonfly",
44 target_os = "freebsd",
45 target_os = "openbsd",
46 target_os = "netbsd",
47 target_os = "illumos",
48 target_os = "solaris",
49 target_os = "haiku",
50 target_os = "l4re",
51 target_os = "nto",
52 target_os = "qnx",
53 target_os = "nuttx",
54 target_vendor = "apple",
55 ) => {
56 use c::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
57 use c::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
58 }
59 _ => {
60 use c::IPV6_ADD_MEMBERSHIP;
61 use c::IPV6_DROP_MEMBERSHIP;
62 }
63}
64
65cfg_select! {
66 any(
67 target_os = "linux", target_os = "android",
68 target_os = "hurd",
69 target_os = "dragonfly", target_os = "freebsd",
70 target_os = "openbsd", target_os = "netbsd",
71 target_os = "solaris", target_os = "illumos",
72 target_os = "haiku",
73 target_os = "nto", target_os = "qnx",
74 target_os = "cygwin",
75 ) => {
76 use libc::MSG_NOSIGNAL;
77 }
78 _ => {
79 const MSG_NOSIGNAL: c_int = 0x0;
80 }
81}
82
83cfg_select! {
84 any(
85 target_os = "dragonfly", target_os = "freebsd",
86 target_os = "openbsd", target_os = "netbsd",
87 target_os = "solaris", target_os = "illumos",
88 target_os = "nto", target_os = "qnx",
89 ) => {
90 use crate::ffi::c_uchar;
91 type IpV4MultiCastType = c_uchar;
92 }
93 _ => {
94 type IpV4MultiCastType = c_int;
95 }
96}
97
98fn ip_v4_addr_to_c(addr: &Ipv4Addr) -> c::in_addr {
103 c::in_addr { s_addr: u32::from_ne_bytes(addr.octets()) }
106}
107
108fn ip_v6_addr_to_c(addr: &Ipv6Addr) -> c::in6_addr {
109 c::in6_addr { s6_addr: addr.octets() }
110}
111
112fn ip_v4_addr_from_c(addr: c::in_addr) -> Ipv4Addr {
113 Ipv4Addr::from(addr.s_addr.to_ne_bytes())
114}
115
116fn ip_v6_addr_from_c(addr: c::in6_addr) -> Ipv6Addr {
117 Ipv6Addr::from(addr.s6_addr)
118}
119
120fn socket_addr_v4_to_c(addr: &SocketAddrV4) -> c::sockaddr_in {
121 c::sockaddr_in {
122 sin_family: c::AF_INET as c::sa_family_t,
123 sin_port: addr.port().to_be(),
124 sin_addr: ip_v4_addr_to_c(addr.ip()),
125 ..unsafe { mem::zeroed() }
126 }
127}
128
129fn socket_addr_v6_to_c(addr: &SocketAddrV6) -> c::sockaddr_in6 {
130 c::sockaddr_in6 {
131 sin6_family: c::AF_INET6 as c::sa_family_t,
132 sin6_port: addr.port().to_be(),
133 sin6_addr: ip_v6_addr_to_c(addr.ip()),
134 sin6_flowinfo: addr.flowinfo(),
135 sin6_scope_id: addr.scope_id(),
136 ..unsafe { mem::zeroed() }
137 }
138}
139
140fn socket_addr_v4_from_c(addr: c::sockaddr_in) -> SocketAddrV4 {
141 SocketAddrV4::new(ip_v4_addr_from_c(addr.sin_addr), u16::from_be(addr.sin_port))
142}
143
144fn socket_addr_v6_from_c(addr: c::sockaddr_in6) -> SocketAddrV6 {
145 SocketAddrV6::new(
146 ip_v6_addr_from_c(addr.sin6_addr),
147 u16::from_be(addr.sin6_port),
148 addr.sin6_flowinfo,
149 addr.sin6_scope_id,
150 )
151}
152
153#[repr(C)]
158union SocketAddrCRepr {
159 v4: c::sockaddr_in,
160 v6: c::sockaddr_in6,
161}
162
163impl SocketAddrCRepr {
164 fn as_ptr(&self) -> *const c::sockaddr {
165 self as *const _ as *const c::sockaddr
166 }
167}
168
169fn socket_addr_to_c(addr: &SocketAddr) -> (SocketAddrCRepr, c::socklen_t) {
170 match addr {
171 SocketAddr::V4(a) => {
172 let sockaddr = SocketAddrCRepr { v4: socket_addr_v4_to_c(a) };
173 (sockaddr, size_of::<c::sockaddr_in>() as c::socklen_t)
174 }
175 SocketAddr::V6(a) => {
176 let sockaddr = SocketAddrCRepr { v6: socket_addr_v6_to_c(a) };
177 (sockaddr, size_of::<c::sockaddr_in6>() as c::socklen_t)
178 }
179 }
180}
181
182fn addr_family(addr: &SocketAddr) -> c_int {
183 match addr {
184 SocketAddr::V4(..) => c::AF_INET,
185 SocketAddr::V6(..) => c::AF_INET6,
186 }
187}
188
189unsafe fn socket_addr_from_c(
195 storage: *const c::sockaddr_storage,
196 len: usize,
197) -> io::Result<SocketAddr> {
198 match (*storage).ss_family as c_int {
199 c::AF_INET => {
200 assert!(len >= size_of::<c::sockaddr_in>());
201 Ok(SocketAddr::V4(socket_addr_v4_from_c(unsafe {
202 *(storage as *const _ as *const c::sockaddr_in)
203 })))
204 }
205 c::AF_INET6 => {
206 assert!(len >= size_of::<c::sockaddr_in6>());
207 Ok(SocketAddr::V6(socket_addr_v6_from_c(unsafe {
208 *(storage as *const _ as *const c::sockaddr_in6)
209 })))
210 }
211 _ => Err(io::const_error!(ErrorKind::InvalidInput, "invalid argument")),
212 }
213}
214
215pub unsafe fn setsockopt<T>(
224 sock: &Socket,
225 level: c_int,
226 option_name: c_int,
227 option_value: T,
228) -> io::Result<()> {
229 let option_len = size_of::<T>() as c::socklen_t;
230 cvt(unsafe {
237 c::setsockopt(
238 sock.as_raw(),
239 level,
240 option_name,
241 (&raw const option_value) as *const _,
242 option_len,
243 )
244 })?;
245 Ok(())
246}
247
248pub unsafe fn getsockopt<T: Copy>(
253 sock: &Socket,
254 level: c_int,
255 option_name: c_int,
256) -> io::Result<T> {
257 let mut option_value = MaybeUninit::<T>::zeroed();
258 let mut option_len = size_of::<T>() as c::socklen_t;
259
260 cvt(unsafe {
265 c::getsockopt(
266 sock.as_raw(),
267 level,
268 option_name,
269 option_value.as_mut_ptr().cast(),
270 &mut option_len,
271 )
272 })?;
273
274 Ok(unsafe { option_value.assume_init() })
278}
279
280unsafe fn sockname<F>(f: F) -> io::Result<SocketAddr>
288where
289 F: FnOnce(*mut c::sockaddr, *mut c::socklen_t) -> c_int,
290{
291 let mut storage = MaybeUninit::<c::sockaddr_storage>::zeroed();
292 let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t;
293 cvt(f(storage.as_mut_ptr().cast(), &mut len))?;
294 unsafe { socket_addr_from_c(storage.as_ptr(), len as usize) }
298}
299
300#[cfg(target_os = "android")]
301fn to_ipv6mr_interface(value: u32) -> c_int {
302 value as c_int
303}
304
305#[cfg(not(target_os = "android"))]
306fn to_ipv6mr_interface(value: u32) -> crate::ffi::c_uint {
307 value as crate::ffi::c_uint
308}
309
310pub struct LookupHost {
315 original: *mut c::addrinfo,
316 cur: *mut c::addrinfo,
317 port: u16,
318}
319
320impl Iterator for LookupHost {
321 type Item = SocketAddr;
322 fn next(&mut self) -> Option<SocketAddr> {
323 loop {
324 unsafe {
325 let cur = self.cur.as_ref()?;
326 self.cur = cur.ai_next;
327 match socket_addr_from_c(cur.ai_addr.cast(), cur.ai_addrlen as usize) {
328 Ok(mut addr) => {
329 addr.set_port(self.port);
330 return Some(addr);
331 }
332 Err(_) => continue,
333 }
334 }
335 }
336 }
337}
338
339unsafe impl Sync for LookupHost {}
340unsafe impl Send for LookupHost {}
341
342impl Drop for LookupHost {
343 fn drop(&mut self) {
344 unsafe { c::freeaddrinfo(self.original) }
345 }
346}
347
348pub fn lookup_host(host: &str, port: u16) -> io::Result<LookupHost> {
349 init();
350 run_with_cstr(host.as_bytes(), &|c_host| {
351 let mut hints: c::addrinfo = unsafe { mem::zeroed() };
352 hints.ai_socktype = c::SOCK_STREAM;
353 let mut res = ptr::null_mut();
354 unsafe {
355 cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res))
356 .map(|_| LookupHost { original: res, cur: res, port })
357 }
358 })
359}
360
361pub struct TcpStream {
366 inner: Socket,
367}
368
369impl TcpStream {
370 pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
371 init();
372 return each_addr(addr, inner);
373
374 fn inner(addr: &SocketAddr) -> io::Result<TcpStream> {
375 let sock = Socket::new(addr_family(addr), c::SOCK_STREAM)?;
376 sock.connect(addr)?;
377 Ok(TcpStream { inner: sock })
378 }
379 }
380
381 pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
382 init();
383
384 let sock = Socket::new(addr_family(addr), c::SOCK_STREAM)?;
385 sock.connect_timeout(addr, timeout)?;
386 Ok(TcpStream { inner: sock })
387 }
388
389 #[inline]
390 pub fn socket(&self) -> &Socket {
391 &self.inner
392 }
393
394 pub fn into_socket(self) -> Socket {
395 self.inner
396 }
397
398 pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
399 self.inner.set_timeout(dur, c::SO_RCVTIMEO)
400 }
401
402 pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
403 self.inner.set_timeout(dur, c::SO_SNDTIMEO)
404 }
405
406 pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
407 self.inner.timeout(c::SO_RCVTIMEO)
408 }
409
410 pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
411 self.inner.timeout(c::SO_SNDTIMEO)
412 }
413
414 pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
415 self.inner.peek(buf)
416 }
417
418 pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
419 self.inner.read(buf)
420 }
421
422 pub fn read_buf(&self, buf: BorrowedCursor<'_, u8>) -> io::Result<()> {
423 self.inner.read_buf(buf)
424 }
425
426 pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
427 self.inner.read_vectored(bufs)
428 }
429
430 #[inline]
431 pub fn is_read_vectored(&self) -> bool {
432 self.inner.is_read_vectored()
433 }
434
435 pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
436 let len = cmp::min(buf.len(), MAX_SEND_LEN) as wrlen_t;
437 let ret = cvt(unsafe {
438 c::send(self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL)
439 })?;
440 Ok(ret as usize)
441 }
442
443 pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
444 self.inner.write_vectored(bufs)
445 }
446
447 #[inline]
448 pub fn is_write_vectored(&self) -> bool {
449 self.inner.is_write_vectored()
450 }
451
452 pub fn peer_addr(&self) -> io::Result<SocketAddr> {
453 unsafe { sockname(|buf, len| c::getpeername(self.inner.as_raw(), buf, len)) }
454 }
455
456 pub fn socket_addr(&self) -> io::Result<SocketAddr> {
457 unsafe { sockname(|buf, len| c::getsockname(self.inner.as_raw(), buf, len)) }
458 }
459
460 pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
461 self.inner.shutdown(how)
462 }
463
464 pub fn duplicate(&self) -> io::Result<TcpStream> {
465 self.inner.duplicate().map(|s| TcpStream { inner: s })
466 }
467
468 pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
469 self.inner.set_linger(linger)
470 }
471
472 pub fn linger(&self) -> io::Result<Option<Duration>> {
473 self.inner.linger()
474 }
475
476 pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
477 self.inner.set_keepalive(keepalive)
478 }
479
480 pub fn keepalive(&self) -> io::Result<bool> {
481 self.inner.keepalive()
482 }
483
484 pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
485 self.inner.set_nodelay(nodelay)
486 }
487
488 pub fn nodelay(&self) -> io::Result<bool> {
489 self.inner.nodelay()
490 }
491
492 pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
493 unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) }
494 }
495
496 pub fn ttl(&self) -> io::Result<u32> {
497 let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)? };
498 Ok(raw as u32)
499 }
500
501 pub fn take_error(&self) -> io::Result<Option<io::Error>> {
502 self.inner.take_error()
503 }
504
505 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
506 self.inner.set_nonblocking(nonblocking)
507 }
508}
509
510impl AsInner<Socket> for TcpStream {
511 #[inline]
512 fn as_inner(&self) -> &Socket {
513 &self.inner
514 }
515}
516
517impl FromInner<Socket> for TcpStream {
518 fn from_inner(socket: Socket) -> TcpStream {
519 TcpStream { inner: socket }
520 }
521}
522
523impl fmt::Debug for TcpStream {
524 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
525 let mut res = f.debug_struct("TcpStream");
526
527 if let Ok(addr) = self.socket_addr() {
528 res.field("addr", &addr);
529 }
530
531 if let Ok(peer) = self.peer_addr() {
532 res.field("peer", &peer);
533 }
534
535 let name = if cfg!(windows) { "socket" } else { "fd" };
536 res.field(name, &self.inner.as_raw()).finish()
537 }
538}
539
540pub struct TcpListener {
545 inner: Socket,
546}
547
548impl TcpListener {
549 pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
550 init();
551 return each_addr(addr, inner);
552
553 fn inner(addr: &SocketAddr) -> io::Result<TcpListener> {
554 let sock = Socket::new(addr_family(addr), c::SOCK_STREAM)?;
555
556 #[cfg(not(windows))]
564 unsafe {
565 setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?
566 };
567
568 let (addr, len) = socket_addr_to_c(addr);
570 cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
571
572 let backlog = if cfg!(target_os = "horizon") {
573 20
577 } else if cfg!(target_os = "haiku") {
578 32
581 } else {
582 128
584 };
585
586 cvt(unsafe { c::listen(sock.as_raw(), backlog) })?;
588 Ok(TcpListener { inner: sock })
589 }
590 }
591
592 #[inline]
593 pub fn socket(&self) -> &Socket {
594 &self.inner
595 }
596
597 pub fn into_socket(self) -> Socket {
598 self.inner
599 }
600
601 pub fn socket_addr(&self) -> io::Result<SocketAddr> {
602 unsafe { sockname(|buf, len| c::getsockname(self.inner.as_raw(), buf, len)) }
603 }
604
605 pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
606 let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit();
610 let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t;
611 let sock = self.inner.accept(storage.as_mut_ptr() as *mut _, &mut len)?;
612 let addr = unsafe { socket_addr_from_c(storage.as_ptr(), len as usize)? };
613 Ok((TcpStream { inner: sock }, addr))
614 }
615
616 pub fn duplicate(&self) -> io::Result<TcpListener> {
617 self.inner.duplicate().map(|s| TcpListener { inner: s })
618 }
619
620 pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
621 unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) }
622 }
623
624 pub fn ttl(&self) -> io::Result<u32> {
625 let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)? };
626 Ok(raw as u32)
627 }
628
629 pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
630 unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int) }
631 }
632
633 pub fn only_v6(&self) -> io::Result<bool> {
634 let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)? };
635 Ok(raw != 0)
636 }
637
638 pub fn take_error(&self) -> io::Result<Option<io::Error>> {
639 self.inner.take_error()
640 }
641
642 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
643 self.inner.set_nonblocking(nonblocking)
644 }
645}
646
647impl FromInner<Socket> for TcpListener {
648 fn from_inner(socket: Socket) -> TcpListener {
649 TcpListener { inner: socket }
650 }
651}
652
653impl fmt::Debug for TcpListener {
654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
655 let mut res = f.debug_struct("TcpListener");
656
657 if let Ok(addr) = self.socket_addr() {
658 res.field("addr", &addr);
659 }
660
661 let name = if cfg!(windows) { "socket" } else { "fd" };
662 res.field(name, &self.inner.as_raw()).finish()
663 }
664}
665
666pub struct UdpSocket {
671 inner: Socket,
672}
673
674impl UdpSocket {
675 pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
676 init();
677 return each_addr(addr, inner);
678
679 fn inner(addr: &SocketAddr) -> io::Result<UdpSocket> {
680 let sock = Socket::new(addr_family(addr), c::SOCK_DGRAM)?;
681 let (addr, len) = socket_addr_to_c(addr);
682 cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
683 Ok(UdpSocket { inner: sock })
684 }
685 }
686
687 #[inline]
688 pub fn socket(&self) -> &Socket {
689 &self.inner
690 }
691
692 pub fn into_socket(self) -> Socket {
693 self.inner
694 }
695
696 pub fn peer_addr(&self) -> io::Result<SocketAddr> {
697 unsafe { sockname(|buf, len| c::getpeername(self.inner.as_raw(), buf, len)) }
698 }
699
700 pub fn socket_addr(&self) -> io::Result<SocketAddr> {
701 unsafe { sockname(|buf, len| c::getsockname(self.inner.as_raw(), buf, len)) }
702 }
703
704 pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
705 self.inner.recv_from(buf)
706 }
707
708 pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
709 self.inner.peek_from(buf)
710 }
711
712 #[allow(clippy::absurd_extreme_comparisons)]
714 pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
715 if buf.len() > MAX_SEND_LEN {
716 return Err(io::Error::from_raw_os_error(c::EMSGSIZE));
717 }
718 let (dst, dstlen) = socket_addr_to_c(dst);
719 let ret = cvt(unsafe {
720 c::sendto(
721 self.inner.as_raw(),
722 buf.as_ptr() as *const c_void,
723 buf.len() as wrlen_t,
724 MSG_NOSIGNAL,
725 dst.as_ptr(),
726 dstlen,
727 )
728 })?;
729 Ok(ret as usize)
730 }
731
732 pub fn duplicate(&self) -> io::Result<UdpSocket> {
733 self.inner.duplicate().map(|s| UdpSocket { inner: s })
734 }
735
736 pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
737 self.inner.set_timeout(dur, c::SO_RCVTIMEO)
738 }
739
740 pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
741 self.inner.set_timeout(dur, c::SO_SNDTIMEO)
742 }
743
744 pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
745 self.inner.timeout(c::SO_RCVTIMEO)
746 }
747
748 pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
749 self.inner.timeout(c::SO_SNDTIMEO)
750 }
751
752 pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
753 unsafe { setsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST, broadcast as c_int) }
754 }
755
756 pub fn broadcast(&self) -> io::Result<bool> {
757 let raw: c_int = unsafe { getsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST)? };
758 Ok(raw != 0)
759 }
760
761 pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
762 unsafe {
763 setsockopt(
764 &self.inner,
765 c::IPPROTO_IP,
766 c::IP_MULTICAST_LOOP,
767 multicast_loop_v4 as IpV4MultiCastType,
768 )
769 }
770 }
771
772 pub fn multicast_loop_v4(&self) -> io::Result<bool> {
773 let raw: IpV4MultiCastType =
774 unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)? };
775 Ok(raw != 0)
776 }
777
778 pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
779 unsafe {
780 setsockopt(
781 &self.inner,
782 c::IPPROTO_IP,
783 c::IP_MULTICAST_TTL,
784 multicast_ttl_v4 as IpV4MultiCastType,
785 )
786 }
787 }
788
789 pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
790 let raw: IpV4MultiCastType =
791 unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)? };
792 Ok(raw as u32)
793 }
794
795 pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
796 unsafe {
797 setsockopt(
798 &self.inner,
799 c::IPPROTO_IPV6,
800 c::IPV6_MULTICAST_LOOP,
801 multicast_loop_v6 as c_int,
802 )
803 }
804 }
805
806 pub fn multicast_loop_v6(&self) -> io::Result<bool> {
807 let raw: c_int =
808 unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP)? };
809 Ok(raw != 0)
810 }
811
812 pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
813 let mreq = c::ip_mreq {
814 imr_multiaddr: ip_v4_addr_to_c(multiaddr),
815 imr_interface: ip_v4_addr_to_c(interface),
816 };
817 unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) }
818 }
819
820 pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
821 let mreq = c::ipv6_mreq {
822 ipv6mr_multiaddr: ip_v6_addr_to_c(multiaddr),
823 ipv6mr_interface: to_ipv6mr_interface(interface),
824 };
825 unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) }
826 }
827
828 pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
829 let mreq = c::ip_mreq {
830 imr_multiaddr: ip_v4_addr_to_c(multiaddr),
831 imr_interface: ip_v4_addr_to_c(interface),
832 };
833 unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) }
834 }
835
836 pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
837 let mreq = c::ipv6_mreq {
838 ipv6mr_multiaddr: ip_v6_addr_to_c(multiaddr),
839 ipv6mr_interface: to_ipv6mr_interface(interface),
840 };
841 unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) }
842 }
843
844 pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
845 unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) }
846 }
847
848 pub fn ttl(&self) -> io::Result<u32> {
849 let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)? };
850 Ok(raw as u32)
851 }
852
853 pub fn take_error(&self) -> io::Result<Option<io::Error>> {
854 self.inner.take_error()
855 }
856
857 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
858 self.inner.set_nonblocking(nonblocking)
859 }
860
861 pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
862 self.inner.read(buf)
863 }
864
865 pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
866 self.inner.peek(buf)
867 }
868
869 #[allow(clippy::absurd_extreme_comparisons)]
871 pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
872 if buf.len() > MAX_SEND_LEN {
873 return Err(io::Error::from_raw_os_error(c::EMSGSIZE));
874 }
875 let ret = cvt(unsafe {
876 c::send(
877 self.inner.as_raw(),
878 buf.as_ptr() as *const c_void,
879 buf.len() as wrlen_t,
880 MSG_NOSIGNAL,
881 )
882 })?;
883 Ok(ret as usize)
884 }
885
886 pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
887 return each_addr(addr, |addr| inner(self, addr));
888
889 fn inner(this: &UdpSocket, addr: &SocketAddr) -> io::Result<()> {
890 let (addr, len) = socket_addr_to_c(addr);
891 cvt_r(|| unsafe { c::connect(this.inner.as_raw(), addr.as_ptr(), len) }).map(drop)
892 }
893 }
894}
895
896impl FromInner<Socket> for UdpSocket {
897 fn from_inner(socket: Socket) -> UdpSocket {
898 UdpSocket { inner: socket }
899 }
900}
901
902impl fmt::Debug for UdpSocket {
903 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
904 let mut res = f.debug_struct("UdpSocket");
905
906 if let Ok(addr) = self.socket_addr() {
907 res.field("addr", &addr);
908 }
909
910 let name = if cfg!(windows) { "socket" } else { "fd" };
911 res.field(name, &self.inner.as_raw()).finish()
912 }
913}