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