nix/sys/socket/
addr.rs

1#[cfg(any(
2    target_os = "android",
3    target_os = "dragonfly",
4    target_os = "freebsd",
5    target_os = "ios",
6    target_os = "linux",
7    target_os = "macos",
8    target_os = "illumos",
9    target_os = "netbsd",
10    target_os = "openbsd",
11    target_os = "haiku",
12    target_os = "fuchsia"
13))]
14#[cfg(feature = "net")]
15pub use self::datalink::LinkAddr;
16#[cfg(any(target_os = "android", target_os = "linux"))]
17pub use self::vsock::VsockAddr;
18use super::sa_family_t;
19use crate::errno::Errno;
20#[cfg(any(target_os = "android", target_os = "linux"))]
21use crate::sys::socket::addr::alg::AlgAddr;
22#[cfg(any(target_os = "android", target_os = "linux"))]
23use crate::sys::socket::addr::netlink::NetlinkAddr;
24#[cfg(all(
25    feature = "ioctl",
26    any(target_os = "ios", target_os = "macos")
27))]
28use crate::sys::socket::addr::sys_control::SysControlAddr;
29use crate::{NixPath, Result};
30use cfg_if::cfg_if;
31use memoffset::offset_of;
32use std::convert::TryInto;
33use std::ffi::OsStr;
34use std::hash::{Hash, Hasher};
35use std::os::unix::ffi::OsStrExt;
36#[cfg(any(target_os = "ios", target_os = "macos"))]
37use std::os::unix::io::RawFd;
38use std::path::Path;
39use std::{fmt, mem, net, ptr, slice};
40
41/// Convert a std::net::Ipv4Addr into the libc form.
42#[cfg(feature = "net")]
43pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr {
44    static_assertions::assert_eq_size!(net::Ipv4Addr, libc::in_addr);
45    // Safe because both types have the same memory layout, and no fancy Drop
46    // impls.
47    unsafe {
48        mem::transmute(addr)
49    }
50}
51
52/// Convert a std::net::Ipv6Addr into the libc form.
53#[cfg(feature = "net")]
54pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr {
55    static_assertions::assert_eq_size!(net::Ipv6Addr, libc::in6_addr);
56    // Safe because both are Newtype wrappers around the same libc type
57    unsafe {
58        mem::transmute(*addr)
59    }
60}
61
62/// These constants specify the protocol family to be used
63/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
64///
65/// # References
66///
67/// [address_families(7)](https://man7.org/linux/man-pages/man7/address_families.7.html)
68// Should this be u8?
69#[repr(i32)]
70#[non_exhaustive]
71#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
72pub enum AddressFamily {
73    /// Local communication (see [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html))
74    Unix = libc::AF_UNIX,
75    /// IPv4 Internet protocols (see [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html))
76    Inet = libc::AF_INET,
77    /// IPv6 Internet protocols (see [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html))
78    Inet6 = libc::AF_INET6,
79    /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html))
80    #[cfg(any(target_os = "android", target_os = "linux"))]
81    #[cfg_attr(docsrs, doc(cfg(all())))]
82    Netlink = libc::AF_NETLINK,
83    /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html))
84    #[cfg(any(
85        target_os = "android",
86        target_os = "linux",
87        target_os = "illumos",
88        target_os = "fuchsia",
89        target_os = "solaris"
90    ))]
91    #[cfg_attr(docsrs, doc(cfg(all())))]
92    Packet = libc::AF_PACKET,
93    /// KEXT Controls and Notifications
94    #[cfg(any(target_os = "ios", target_os = "macos"))]
95    #[cfg_attr(docsrs, doc(cfg(all())))]
96    System = libc::AF_SYSTEM,
97    /// Amateur radio AX.25 protocol
98    #[cfg(any(target_os = "android", target_os = "linux"))]
99    #[cfg_attr(docsrs, doc(cfg(all())))]
100    Ax25 = libc::AF_AX25,
101    /// IPX - Novell protocols
102    Ipx = libc::AF_IPX,
103    /// AppleTalk
104    AppleTalk = libc::AF_APPLETALK,
105    /// AX.25 packet layer protocol.
106    /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/))
107    #[cfg(any(target_os = "android", target_os = "linux"))]
108    #[cfg_attr(docsrs, doc(cfg(all())))]
109    NetRom = libc::AF_NETROM,
110    /// Can't be used for creating sockets; mostly used for bridge
111    /// links in
112    /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html)
113    /// protocol commands.
114    #[cfg(any(target_os = "android", target_os = "linux"))]
115    #[cfg_attr(docsrs, doc(cfg(all())))]
116    Bridge = libc::AF_BRIDGE,
117    /// Access to raw ATM PVCs
118    #[cfg(any(target_os = "android", target_os = "linux"))]
119    #[cfg_attr(docsrs, doc(cfg(all())))]
120    AtmPvc = libc::AF_ATMPVC,
121    /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html))
122    #[cfg(any(target_os = "android", target_os = "linux"))]
123    #[cfg_attr(docsrs, doc(cfg(all())))]
124    X25 = libc::AF_X25,
125    /// RATS (Radio Amateur Telecommunications Society) Open
126    /// Systems environment (ROSE) AX.25 packet layer protocol.
127    /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/))
128    #[cfg(any(target_os = "android", target_os = "linux"))]
129    #[cfg_attr(docsrs, doc(cfg(all())))]
130    Rose = libc::AF_ROSE,
131    /// DECet protocol sockets.
132    #[cfg(not(target_os = "haiku"))]
133    Decnet = libc::AF_DECnet,
134    /// Reserved for "802.2LLC project"; never used.
135    #[cfg(any(target_os = "android", target_os = "linux"))]
136    #[cfg_attr(docsrs, doc(cfg(all())))]
137    NetBeui = libc::AF_NETBEUI,
138    /// This was a short-lived (between Linux 2.1.30 and
139    /// 2.1.99pre2) protocol family for firewall upcalls.
140    #[cfg(any(target_os = "android", target_os = "linux"))]
141    #[cfg_attr(docsrs, doc(cfg(all())))]
142    Security = libc::AF_SECURITY,
143    /// Key management protocol.
144    #[cfg(any(target_os = "android", target_os = "linux"))]
145    #[cfg_attr(docsrs, doc(cfg(all())))]
146    Key = libc::AF_KEY,
147    #[allow(missing_docs)] // Not documented anywhere that I can find
148    #[cfg(any(target_os = "android", target_os = "linux"))]
149    #[cfg_attr(docsrs, doc(cfg(all())))]
150    Ash = libc::AF_ASH,
151    /// Acorn Econet protocol
152    #[cfg(any(target_os = "android", target_os = "linux"))]
153    #[cfg_attr(docsrs, doc(cfg(all())))]
154    Econet = libc::AF_ECONET,
155    /// Access to ATM Switched Virtual Circuits
156    #[cfg(any(target_os = "android", target_os = "linux"))]
157    #[cfg_attr(docsrs, doc(cfg(all())))]
158    AtmSvc = libc::AF_ATMSVC,
159    /// Reliable Datagram Sockets (RDS) protocol
160    #[cfg(any(target_os = "android", target_os = "linux"))]
161    #[cfg_attr(docsrs, doc(cfg(all())))]
162    Rds = libc::AF_RDS,
163    /// IBM SNA
164    #[cfg(not(target_os = "haiku"))]
165    Sna = libc::AF_SNA,
166    /// Socket interface over IrDA
167    #[cfg(any(target_os = "android", target_os = "linux"))]
168    #[cfg_attr(docsrs, doc(cfg(all())))]
169    Irda = libc::AF_IRDA,
170    /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE)
171    #[cfg(any(target_os = "android", target_os = "linux"))]
172    #[cfg_attr(docsrs, doc(cfg(all())))]
173    Pppox = libc::AF_PPPOX,
174    /// Legacy protocol for wide area network (WAN) connectivity that was used
175    /// by Sangoma WAN cards
176    #[cfg(any(target_os = "android", target_os = "linux"))]
177    #[cfg_attr(docsrs, doc(cfg(all())))]
178    Wanpipe = libc::AF_WANPIPE,
179    /// Logical link control (IEEE 802.2 LLC) protocol
180    #[cfg(any(target_os = "android", target_os = "linux"))]
181    #[cfg_attr(docsrs, doc(cfg(all())))]
182    Llc = libc::AF_LLC,
183    /// InfiniBand native addressing
184    #[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
185    #[cfg_attr(docsrs, doc(cfg(all())))]
186    Ib = libc::AF_IB,
187    /// Multiprotocol Label Switching
188    #[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
189    #[cfg_attr(docsrs, doc(cfg(all())))]
190    Mpls = libc::AF_MPLS,
191    /// Controller Area Network automotive bus protocol
192    #[cfg(any(target_os = "android", target_os = "linux"))]
193    #[cfg_attr(docsrs, doc(cfg(all())))]
194    Can = libc::AF_CAN,
195    /// TIPC, "cluster domain sockets" protocol
196    #[cfg(any(target_os = "android", target_os = "linux"))]
197    #[cfg_attr(docsrs, doc(cfg(all())))]
198    Tipc = libc::AF_TIPC,
199    /// Bluetooth low-level socket protocol
200    #[cfg(not(any(
201        target_os = "illumos",
202        target_os = "ios",
203        target_os = "macos",
204        target_os = "solaris"
205    )))]
206    #[cfg_attr(docsrs, doc(cfg(all())))]
207    Bluetooth = libc::AF_BLUETOOTH,
208    /// IUCV (inter-user communication vehicle) z/VM protocol for
209    /// hypervisor-guest interaction
210    #[cfg(any(target_os = "android", target_os = "linux"))]
211    #[cfg_attr(docsrs, doc(cfg(all())))]
212    Iucv = libc::AF_IUCV,
213    /// Rx, Andrew File System remote procedure call protocol
214    #[cfg(any(target_os = "android", target_os = "linux"))]
215    #[cfg_attr(docsrs, doc(cfg(all())))]
216    RxRpc = libc::AF_RXRPC,
217    /// New "modular ISDN" driver interface protocol
218    #[cfg(not(any(
219        target_os = "illumos",
220        target_os = "solaris",
221        target_os = "haiku"
222    )))]
223    #[cfg_attr(docsrs, doc(cfg(all())))]
224    Isdn = libc::AF_ISDN,
225    /// Nokia cellular modem IPC/RPC interface
226    #[cfg(any(target_os = "android", target_os = "linux"))]
227    #[cfg_attr(docsrs, doc(cfg(all())))]
228    Phonet = libc::AF_PHONET,
229    /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol
230    #[cfg(any(target_os = "android", target_os = "linux"))]
231    #[cfg_attr(docsrs, doc(cfg(all())))]
232    Ieee802154 = libc::AF_IEEE802154,
233    /// Ericsson's Communication CPU to Application CPU interface (CAIF)
234    /// protocol.
235    #[cfg(any(target_os = "android", target_os = "linux"))]
236    #[cfg_attr(docsrs, doc(cfg(all())))]
237    Caif = libc::AF_CAIF,
238    /// Interface to kernel crypto API
239    #[cfg(any(target_os = "android", target_os = "linux"))]
240    #[cfg_attr(docsrs, doc(cfg(all())))]
241    Alg = libc::AF_ALG,
242    /// Near field communication
243    #[cfg(target_os = "linux")]
244    #[cfg_attr(docsrs, doc(cfg(all())))]
245    Nfc = libc::AF_NFC,
246    /// VMWare VSockets protocol for hypervisor-guest interaction.
247    #[cfg(any(target_os = "android", target_os = "linux"))]
248    #[cfg_attr(docsrs, doc(cfg(all())))]
249    Vsock = libc::AF_VSOCK,
250    /// ARPANet IMP addresses
251    #[cfg(any(
252        target_os = "dragonfly",
253        target_os = "freebsd",
254        target_os = "ios",
255        target_os = "macos",
256        target_os = "netbsd",
257        target_os = "openbsd"
258    ))]
259    #[cfg_attr(docsrs, doc(cfg(all())))]
260    ImpLink = libc::AF_IMPLINK,
261    /// PUP protocols, e.g. BSP
262    #[cfg(any(
263        target_os = "dragonfly",
264        target_os = "freebsd",
265        target_os = "ios",
266        target_os = "macos",
267        target_os = "netbsd",
268        target_os = "openbsd"
269    ))]
270    #[cfg_attr(docsrs, doc(cfg(all())))]
271    Pup = libc::AF_PUP,
272    /// MIT CHAOS protocols
273    #[cfg(any(
274        target_os = "dragonfly",
275        target_os = "freebsd",
276        target_os = "ios",
277        target_os = "macos",
278        target_os = "netbsd",
279        target_os = "openbsd"
280    ))]
281    #[cfg_attr(docsrs, doc(cfg(all())))]
282    Chaos = libc::AF_CHAOS,
283    /// Novell and Xerox protocol
284    #[cfg(any(
285        target_os = "ios",
286        target_os = "macos",
287        target_os = "netbsd",
288        target_os = "openbsd"
289    ))]
290    #[cfg_attr(docsrs, doc(cfg(all())))]
291    Ns = libc::AF_NS,
292    #[allow(missing_docs)] // Not documented anywhere that I can find
293    #[cfg(any(
294        target_os = "dragonfly",
295        target_os = "freebsd",
296        target_os = "ios",
297        target_os = "macos",
298        target_os = "netbsd",
299        target_os = "openbsd"
300    ))]
301    #[cfg_attr(docsrs, doc(cfg(all())))]
302    Iso = libc::AF_ISO,
303    /// Bell Labs virtual circuit switch ?
304    #[cfg(any(
305        target_os = "dragonfly",
306        target_os = "freebsd",
307        target_os = "ios",
308        target_os = "macos",
309        target_os = "netbsd",
310        target_os = "openbsd"
311    ))]
312    #[cfg_attr(docsrs, doc(cfg(all())))]
313    Datakit = libc::AF_DATAKIT,
314    /// CCITT protocols, X.25 etc
315    #[cfg(any(
316        target_os = "dragonfly",
317        target_os = "freebsd",
318        target_os = "ios",
319        target_os = "macos",
320        target_os = "netbsd",
321        target_os = "openbsd"
322    ))]
323    #[cfg_attr(docsrs, doc(cfg(all())))]
324    Ccitt = libc::AF_CCITT,
325    /// DEC Direct data link interface
326    #[cfg(any(
327        target_os = "dragonfly",
328        target_os = "freebsd",
329        target_os = "ios",
330        target_os = "macos",
331        target_os = "netbsd",
332        target_os = "openbsd"
333    ))]
334    #[cfg_attr(docsrs, doc(cfg(all())))]
335    Dli = libc::AF_DLI,
336    #[allow(missing_docs)] // Not documented anywhere that I can find
337    #[cfg(any(
338        target_os = "dragonfly",
339        target_os = "freebsd",
340        target_os = "ios",
341        target_os = "macos",
342        target_os = "netbsd",
343        target_os = "openbsd"
344    ))]
345    #[cfg_attr(docsrs, doc(cfg(all())))]
346    Lat = libc::AF_LAT,
347    /// NSC Hyperchannel
348    #[cfg(any(
349        target_os = "dragonfly",
350        target_os = "freebsd",
351        target_os = "ios",
352        target_os = "macos",
353        target_os = "netbsd",
354        target_os = "openbsd"
355    ))]
356    #[cfg_attr(docsrs, doc(cfg(all())))]
357    Hylink = libc::AF_HYLINK,
358    /// Link layer interface
359    #[cfg(any(
360        target_os = "dragonfly",
361        target_os = "freebsd",
362        target_os = "ios",
363        target_os = "macos",
364        target_os = "illumos",
365        target_os = "netbsd",
366        target_os = "openbsd"
367    ))]
368    #[cfg_attr(docsrs, doc(cfg(all())))]
369    Link = libc::AF_LINK,
370    /// connection-oriented IP, aka ST II
371    #[cfg(any(
372        target_os = "dragonfly",
373        target_os = "freebsd",
374        target_os = "ios",
375        target_os = "macos",
376        target_os = "netbsd",
377        target_os = "openbsd"
378    ))]
379    #[cfg_attr(docsrs, doc(cfg(all())))]
380    Coip = libc::AF_COIP,
381    /// Computer Network Technology
382    #[cfg(any(
383        target_os = "dragonfly",
384        target_os = "freebsd",
385        target_os = "ios",
386        target_os = "macos",
387        target_os = "netbsd",
388        target_os = "openbsd"
389    ))]
390    #[cfg_attr(docsrs, doc(cfg(all())))]
391    Cnt = libc::AF_CNT,
392    /// Native ATM access
393    #[cfg(any(
394        target_os = "dragonfly",
395        target_os = "freebsd",
396        target_os = "ios",
397        target_os = "macos",
398        target_os = "netbsd",
399        target_os = "openbsd"
400    ))]
401    #[cfg_attr(docsrs, doc(cfg(all())))]
402    Natm = libc::AF_NATM,
403    /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html))
404    #[cfg(any(target_os = "android", target_os = "linux"))]
405    #[cfg_attr(docsrs, doc(cfg(all())))]
406    Unspec = libc::AF_UNSPEC,
407}
408
409impl AddressFamily {
410    /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from
411    /// the `sa_family` field of a `sockaddr`.
412    ///
413    /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet
414    /// and System. Returns None for unsupported or unknown address families.
415    pub const fn from_i32(family: i32) -> Option<AddressFamily> {
416        match family {
417            libc::AF_UNIX => Some(AddressFamily::Unix),
418            libc::AF_INET => Some(AddressFamily::Inet),
419            libc::AF_INET6 => Some(AddressFamily::Inet6),
420            #[cfg(any(target_os = "android", target_os = "linux"))]
421            libc::AF_NETLINK => Some(AddressFamily::Netlink),
422            #[cfg(any(target_os = "macos", target_os = "macos"))]
423            libc::AF_SYSTEM => Some(AddressFamily::System),
424            #[cfg(any(target_os = "android", target_os = "linux"))]
425            libc::AF_PACKET => Some(AddressFamily::Packet),
426            #[cfg(any(
427                target_os = "dragonfly",
428                target_os = "freebsd",
429                target_os = "ios",
430                target_os = "macos",
431                target_os = "netbsd",
432                target_os = "illumos",
433                target_os = "openbsd"
434            ))]
435            libc::AF_LINK => Some(AddressFamily::Link),
436            #[cfg(any(target_os = "android", target_os = "linux"))]
437            libc::AF_VSOCK => Some(AddressFamily::Vsock),
438            _ => None,
439        }
440    }
441}
442
443feature! {
444#![feature = "net"]
445
446#[deprecated(
447    since = "0.24.0",
448    note = "use SockaddrIn, SockaddrIn6, or SockaddrStorage instead"
449)]
450#[allow(missing_docs)]  // Since they're all deprecated anyway
451#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
452pub enum InetAddr {
453    V4(libc::sockaddr_in),
454    V6(libc::sockaddr_in6),
455}
456
457#[allow(missing_docs)]  // It's deprecated anyway
458#[allow(deprecated)]
459impl InetAddr {
460    #[allow(clippy::needless_update)]   // It isn't needless on all OSes
461    pub fn from_std(std: &net::SocketAddr) -> InetAddr {
462        match *std {
463            net::SocketAddr::V4(ref addr) => {
464                InetAddr::V4(libc::sockaddr_in {
465                    #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
466                              target_os = "haiku", target_os = "hermit",
467                              target_os = "ios", target_os = "macos",
468                              target_os = "netbsd", target_os = "openbsd"))]
469                    sin_len: mem::size_of::<libc::sockaddr_in>() as u8,
470                    sin_family: AddressFamily::Inet as sa_family_t,
471                    sin_port: addr.port().to_be(),  // network byte order
472                    sin_addr: Ipv4Addr::from_std(addr.ip()).0,
473                    .. unsafe { mem::zeroed() }
474                })
475            }
476            net::SocketAddr::V6(ref addr) => {
477                InetAddr::V6(libc::sockaddr_in6 {
478                    #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
479                              target_os = "haiku", target_os = "hermit",
480                              target_os = "ios", target_os = "macos",
481                              target_os = "netbsd", target_os = "openbsd"))]
482                    sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8,
483                    sin6_family: AddressFamily::Inet6 as sa_family_t,
484                    sin6_port: addr.port().to_be(),  // network byte order
485                    sin6_addr: Ipv6Addr::from_std(addr.ip()).0,
486                    sin6_flowinfo: addr.flowinfo(),  // host byte order
487                    sin6_scope_id: addr.scope_id(),  // host byte order
488                    .. unsafe { mem::zeroed() }
489                })
490            }
491        }
492    }
493
494    #[allow(clippy::needless_update)]   // It isn't needless on all OSes
495    pub fn new(ip: IpAddr, port: u16) -> InetAddr {
496        match ip {
497            IpAddr::V4(ref ip) => {
498                InetAddr::V4(libc::sockaddr_in {
499                    sin_family: AddressFamily::Inet as sa_family_t,
500                    sin_port: port.to_be(),
501                    sin_addr: ip.0,
502                    .. unsafe { mem::zeroed() }
503                })
504            }
505            IpAddr::V6(ref ip) => {
506                InetAddr::V6(libc::sockaddr_in6 {
507                    sin6_family: AddressFamily::Inet6 as sa_family_t,
508                    sin6_port: port.to_be(),
509                    sin6_addr: ip.0,
510                    .. unsafe { mem::zeroed() }
511                })
512            }
513        }
514    }
515    /// Gets the IP address associated with this socket address.
516    pub const fn ip(&self) -> IpAddr {
517        match *self {
518            InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)),
519            InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)),
520        }
521    }
522
523    /// Gets the port number associated with this socket address
524    pub const fn port(&self) -> u16 {
525        match *self {
526            InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port),
527            InetAddr::V4(ref sa) => u16::from_be(sa.sin_port),
528        }
529    }
530
531    pub fn to_std(&self) -> net::SocketAddr {
532        match *self {
533            InetAddr::V4(ref sa) => net::SocketAddr::V4(
534                net::SocketAddrV4::new(
535                    Ipv4Addr(sa.sin_addr).to_std(),
536                    self.port())),
537            InetAddr::V6(ref sa) => net::SocketAddr::V6(
538                net::SocketAddrV6::new(
539                    Ipv6Addr(sa.sin6_addr).to_std(),
540                    self.port(),
541                    sa.sin6_flowinfo,
542                    sa.sin6_scope_id)),
543        }
544    }
545
546    #[deprecated(since = "0.23.0", note = "use .to_string() instead")]
547    pub fn to_str(&self) -> String {
548        format!("{}", self)
549    }
550}
551
552#[allow(deprecated)]
553impl fmt::Display for InetAddr {
554    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
555        match *self {
556            InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()),
557            InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()),
558        }
559    }
560}
561
562/*
563 *
564 * ===== IpAddr =====
565 *
566 */
567#[allow(missing_docs)]  // Since they're all deprecated anyway
568#[allow(deprecated)]
569#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
570#[deprecated(
571    since = "0.24.0",
572    note = "Use std::net::IpAddr instead"
573)]
574pub enum IpAddr {
575    V4(Ipv4Addr),
576    V6(Ipv6Addr),
577}
578
579#[allow(deprecated)]
580#[allow(missing_docs)]  // Since they're all deprecated anyway
581impl IpAddr {
582    /// Create a new IpAddr that contains an IPv4 address.
583    ///
584    /// The result will represent the IP address a.b.c.d
585    pub const fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
586        IpAddr::V4(Ipv4Addr::new(a, b, c, d))
587    }
588
589    /// Create a new IpAddr that contains an IPv6 address.
590    ///
591    /// The result will represent the IP address a:b:c:d:e:f
592    #[allow(clippy::many_single_char_names)]
593    #[allow(clippy::too_many_arguments)]
594    pub const fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr {
595        IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
596    }
597
598    pub fn from_std(std: &net::IpAddr) -> IpAddr {
599        match *std {
600            net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)),
601            net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)),
602        }
603    }
604
605    pub const fn to_std(&self) -> net::IpAddr {
606        match *self {
607            IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()),
608            IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()),
609        }
610    }
611}
612
613#[allow(deprecated)]
614impl fmt::Display for IpAddr {
615    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
616        match *self {
617            IpAddr::V4(ref v4) => v4.fmt(f),
618            IpAddr::V6(ref v6) => v6.fmt(f)
619        }
620    }
621}
622
623/*
624 *
625 * ===== Ipv4Addr =====
626 *
627 */
628
629#[deprecated(
630    since = "0.24.0",
631    note = "Use std::net::Ipv4Addr instead"
632)]
633#[allow(missing_docs)]  // Since they're all deprecated anyway
634#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
635#[repr(transparent)]
636pub struct Ipv4Addr(pub libc::in_addr);
637
638#[allow(deprecated)]
639#[allow(missing_docs)]  // Since they're all deprecated anyway
640impl Ipv4Addr {
641    #[allow(clippy::identity_op)]   // More readable this way
642    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
643        let ip = (((a as u32) << 24) |
644                  ((b as u32) << 16) |
645                  ((c as u32) <<  8) |
646                  ((d as u32) <<  0)).to_be();
647
648        Ipv4Addr(libc::in_addr { s_addr: ip })
649    }
650
651    // Use pass by reference for symmetry with Ipv6Addr::from_std
652    #[allow(clippy::trivially_copy_pass_by_ref)]
653    pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
654        let bits = std.octets();
655        Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
656    }
657
658    pub const fn any() -> Ipv4Addr {
659        Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY })
660    }
661
662    pub const fn octets(self) -> [u8; 4] {
663        let bits = u32::from_be(self.0.s_addr);
664        [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
665    }
666
667    pub const fn to_std(self) -> net::Ipv4Addr {
668        let bits = self.octets();
669        net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
670    }
671}
672
673#[allow(deprecated)]
674impl fmt::Display for Ipv4Addr {
675    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
676        let octets = self.octets();
677        write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
678    }
679}
680
681/*
682 *
683 * ===== Ipv6Addr =====
684 *
685 */
686
687#[deprecated(
688    since = "0.24.0",
689    note = "Use std::net::Ipv6Addr instead"
690)]
691#[allow(missing_docs)]  // Since they're all deprecated anyway
692#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
693#[repr(transparent)]
694pub struct Ipv6Addr(pub libc::in6_addr);
695
696// Note that IPv6 addresses are stored in big endian order on all architectures.
697// See https://tools.ietf.org/html/rfc1700 or consult your favorite search
698// engine.
699
700macro_rules! to_u8_array {
701    ($($num:ident),*) => {
702        [ $(($num>>8) as u8, ($num&0xff) as u8,)* ]
703    }
704}
705
706macro_rules! to_u16_array {
707    ($slf:ident, $($first:expr, $second:expr),*) => {
708        [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*]
709    }
710}
711
712#[allow(deprecated)]
713#[allow(missing_docs)]  // Since they're all deprecated anyway
714impl Ipv6Addr {
715    #[allow(clippy::many_single_char_names)]
716    #[allow(clippy::too_many_arguments)]
717    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
718        Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)})
719    }
720
721    pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr {
722        let s = std.segments();
723        Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
724    }
725
726    /// Return the eight 16-bit segments that make up this address
727    pub const fn segments(&self) -> [u16; 8] {
728        to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
729    }
730
731    pub const fn to_std(&self) -> net::Ipv6Addr {
732        let s = self.segments();
733        net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
734    }
735}
736
737#[allow(deprecated)]
738impl fmt::Display for Ipv6Addr {
739    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
740        self.to_std().fmt(fmt)
741    }
742}
743}
744
745/// A wrapper around `sockaddr_un`.
746#[derive(Clone, Copy, Debug)]
747#[repr(C)]
748pub struct UnixAddr {
749    // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts
750    sun: libc::sockaddr_un,
751    /// The length of the valid part of `sun`, including the sun_family field
752    /// but excluding any trailing nul.
753    // On the BSDs, this field is built into sun
754    #[cfg(any(
755        target_os = "android",
756        target_os = "fuchsia",
757        target_os = "illumos",
758        target_os = "linux"
759    ))]
760    sun_len: u8,
761}
762
763// linux man page unix(7) says there are 3 kinds of unix socket:
764// pathname: addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1
765// unnamed: addrlen = sizeof(sa_family_t)
766// abstract: addren > sizeof(sa_family_t), name = sun_path[..(addrlen - sizeof(sa_family_t))]
767//
768// what we call path_len = addrlen - offsetof(struct sockaddr_un, sun_path)
769#[derive(PartialEq, Eq, Hash)]
770enum UnixAddrKind<'a> {
771    Pathname(&'a Path),
772    Unnamed,
773    #[cfg(any(target_os = "android", target_os = "linux"))]
774    Abstract(&'a [u8]),
775}
776impl<'a> UnixAddrKind<'a> {
777    /// Safety: sun & sun_len must be valid
778    unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self {
779        assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path));
780        let path_len =
781            sun_len as usize - offset_of!(libc::sockaddr_un, sun_path);
782        if path_len == 0 {
783            return Self::Unnamed;
784        }
785        #[cfg(any(target_os = "android", target_os = "linux"))]
786        if sun.sun_path[0] == 0 {
787            let name = slice::from_raw_parts(
788                sun.sun_path.as_ptr().add(1) as *const u8,
789                path_len - 1,
790            );
791            return Self::Abstract(name);
792        }
793        let pathname =
794            slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len);
795        if pathname.last() == Some(&0) {
796            // A trailing NUL is not considered part of the path, and it does
797            // not need to be included in the addrlen passed to functions like
798            // bind().  However, Linux adds a trailing NUL, even if one was not
799            // originally present, when returning addrs from functions like
800            // getsockname() (the BSDs do not do that).  So we need to filter
801            // out any trailing NUL here, so sockaddrs can round-trip through
802            // the kernel and still compare equal.
803            Self::Pathname(Path::new(OsStr::from_bytes(
804                &pathname[0..pathname.len() - 1],
805            )))
806        } else {
807            Self::Pathname(Path::new(OsStr::from_bytes(pathname)))
808        }
809    }
810}
811
812impl UnixAddr {
813    /// Create a new sockaddr_un representing a filesystem path.
814    pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> {
815        path.with_nix_path(|cstr| unsafe {
816            let mut ret = libc::sockaddr_un {
817                sun_family: AddressFamily::Unix as sa_family_t,
818                ..mem::zeroed()
819            };
820
821            let bytes = cstr.to_bytes();
822
823            if bytes.len() >= ret.sun_path.len() {
824                return Err(Errno::ENAMETOOLONG);
825            }
826
827            let sun_len = (bytes.len()
828                + offset_of!(libc::sockaddr_un, sun_path))
829            .try_into()
830            .unwrap();
831
832            #[cfg(any(
833                target_os = "dragonfly",
834                target_os = "freebsd",
835                target_os = "ios",
836                target_os = "macos",
837                target_os = "netbsd",
838                target_os = "openbsd"
839            ))]
840            {
841                ret.sun_len = sun_len;
842            }
843            ptr::copy_nonoverlapping(
844                bytes.as_ptr(),
845                ret.sun_path.as_mut_ptr() as *mut u8,
846                bytes.len(),
847            );
848
849            Ok(UnixAddr::from_raw_parts(ret, sun_len))
850        })?
851    }
852
853    /// Create a new `sockaddr_un` representing an address in the "abstract namespace".
854    ///
855    /// The leading nul byte for the abstract namespace is automatically added;
856    /// thus the input `path` is expected to be the bare name, not NUL-prefixed.
857    /// This is a Linux-specific extension, primarily used to allow chrooted
858    /// processes to communicate with processes having a different filesystem view.
859    #[cfg(any(target_os = "android", target_os = "linux"))]
860    #[cfg_attr(docsrs, doc(cfg(all())))]
861    pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> {
862        unsafe {
863            let mut ret = libc::sockaddr_un {
864                sun_family: AddressFamily::Unix as sa_family_t,
865                ..mem::zeroed()
866            };
867
868            if path.len() >= ret.sun_path.len() {
869                return Err(Errno::ENAMETOOLONG);
870            }
871            let sun_len =
872                (path.len() + 1 + offset_of!(libc::sockaddr_un, sun_path))
873                    .try_into()
874                    .unwrap();
875
876            // Abstract addresses are represented by sun_path[0] ==
877            // b'\0', so copy starting one byte in.
878            ptr::copy_nonoverlapping(
879                path.as_ptr(),
880                ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
881                path.len(),
882            );
883
884            Ok(UnixAddr::from_raw_parts(ret, sun_len))
885        }
886    }
887
888    /// Create a new `sockaddr_un` representing an "unnamed" unix socket address.
889    #[cfg(any(target_os = "android", target_os = "linux"))]
890    #[cfg_attr(docsrs, doc(cfg(all())))]
891    pub fn new_unnamed() -> UnixAddr {
892        let ret = libc::sockaddr_un {
893            sun_family: AddressFamily::Unix as sa_family_t,
894            .. unsafe { mem::zeroed() }
895        };
896
897        let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap();
898
899        unsafe { UnixAddr::from_raw_parts(ret, sun_len) }
900    }
901
902    /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len`
903    /// is the size of the valid portion of the struct, excluding any trailing
904    /// NUL.
905    ///
906    /// # Safety
907    /// This pair of sockaddr_un & sun_len must be a valid unix addr, which
908    /// means:
909    /// - sun_len >= offset_of(sockaddr_un, sun_path)
910    /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path)
911    /// - if this is a unix addr with a pathname, sun.sun_path is a
912    ///   fs path, not necessarily nul-terminated.
913    pub(crate) unsafe fn from_raw_parts(
914        sun: libc::sockaddr_un,
915        sun_len: u8,
916    ) -> UnixAddr {
917        cfg_if! {
918            if #[cfg(any(target_os = "android",
919                     target_os = "fuchsia",
920                     target_os = "illumos",
921                     target_os = "linux"
922                ))]
923            {
924                UnixAddr { sun, sun_len }
925            } else {
926                assert_eq!(sun_len, sun.sun_len);
927                UnixAddr {sun}
928            }
929        }
930    }
931
932    fn kind(&self) -> UnixAddrKind<'_> {
933        // SAFETY: our sockaddr is always valid because of the invariant on the struct
934        unsafe { UnixAddrKind::get(&self.sun, self.sun_len()) }
935    }
936
937    /// If this address represents a filesystem path, return that path.
938    pub fn path(&self) -> Option<&Path> {
939        match self.kind() {
940            UnixAddrKind::Pathname(path) => Some(path),
941            _ => None,
942        }
943    }
944
945    /// If this address represents an abstract socket, return its name.
946    ///
947    /// For abstract sockets only the bare name is returned, without the
948    /// leading NUL byte. `None` is returned for unnamed or path-backed sockets.
949    #[cfg(any(target_os = "android", target_os = "linux"))]
950    #[cfg_attr(docsrs, doc(cfg(all())))]
951    pub fn as_abstract(&self) -> Option<&[u8]> {
952        match self.kind() {
953            UnixAddrKind::Abstract(name) => Some(name),
954            _ => None,
955        }
956    }
957
958    /// Check if this address is an "unnamed" unix socket address.
959    #[cfg(any(target_os = "android", target_os = "linux"))]
960    #[cfg_attr(docsrs, doc(cfg(all())))]
961    #[inline]
962    pub fn is_unnamed(&self) -> bool {
963        matches!(self.kind(), UnixAddrKind::Unnamed)
964    }
965
966    /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)`
967    #[inline]
968    pub fn path_len(&self) -> usize {
969        self.sun_len() as usize - offset_of!(libc::sockaddr_un, sun_path)
970    }
971    /// Returns a pointer to the raw `sockaddr_un` struct
972    #[inline]
973    pub fn as_ptr(&self) -> *const libc::sockaddr_un {
974        &self.sun
975    }
976    /// Returns a mutable pointer to the raw `sockaddr_un` struct
977    #[inline]
978    pub fn as_mut_ptr(&mut self) -> *mut libc::sockaddr_un {
979        &mut self.sun
980    }
981
982    fn sun_len(&self) -> u8 {
983        cfg_if! {
984            if #[cfg(any(target_os = "android",
985                     target_os = "fuchsia",
986                     target_os = "illumos",
987                     target_os = "linux"
988                ))]
989            {
990                self.sun_len
991            } else {
992                self.sun.sun_len
993            }
994        }
995    }
996}
997
998impl private::SockaddrLikePriv for UnixAddr {}
999impl SockaddrLike for UnixAddr {
1000    #[cfg(any(
1001        target_os = "android",
1002        target_os = "fuchsia",
1003        target_os = "illumos",
1004        target_os = "linux"
1005    ))]
1006    fn len(&self) -> libc::socklen_t {
1007        self.sun_len.into()
1008    }
1009
1010    unsafe fn from_raw(
1011        addr: *const libc::sockaddr,
1012        len: Option<libc::socklen_t>,
1013    ) -> Option<Self>
1014    where
1015        Self: Sized,
1016    {
1017        if let Some(l) = len {
1018            if (l as usize) < offset_of!(libc::sockaddr_un, sun_path)
1019                || l > u8::MAX as libc::socklen_t
1020            {
1021                return None;
1022            }
1023        }
1024        if (*addr).sa_family as i32 != libc::AF_UNIX {
1025            return None;
1026        }
1027        let mut su: libc::sockaddr_un = mem::zeroed();
1028        let sup = &mut su as *mut libc::sockaddr_un as *mut u8;
1029        cfg_if! {
1030            if #[cfg(any(target_os = "android",
1031                         target_os = "fuchsia",
1032                         target_os = "illumos",
1033                         target_os = "linux"
1034                ))] {
1035                let su_len = len.unwrap_or(
1036                    mem::size_of::<libc::sockaddr_un>() as libc::socklen_t
1037                );
1038            } else {
1039                let su_len = len.unwrap_or((*addr).sa_len as libc::socklen_t);
1040            }
1041        };
1042        ptr::copy(addr as *const u8, sup, su_len as usize);
1043        Some(Self::from_raw_parts(su, su_len as u8))
1044    }
1045
1046    fn size() -> libc::socklen_t
1047    where
1048        Self: Sized,
1049    {
1050        mem::size_of::<libc::sockaddr_un>() as libc::socklen_t
1051    }
1052}
1053
1054impl AsRef<libc::sockaddr_un> for UnixAddr {
1055    fn as_ref(&self) -> &libc::sockaddr_un {
1056        &self.sun
1057    }
1058}
1059
1060#[cfg(any(target_os = "android", target_os = "linux"))]
1061fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
1062    use fmt::Write;
1063    f.write_str("@\"")?;
1064    for &b in abs {
1065        use fmt::Display;
1066        char::from(b).escape_default().fmt(f)?;
1067    }
1068    f.write_char('"')?;
1069    Ok(())
1070}
1071
1072impl fmt::Display for UnixAddr {
1073    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1074        match self.kind() {
1075            UnixAddrKind::Pathname(path) => path.display().fmt(f),
1076            UnixAddrKind::Unnamed => f.pad("<unbound UNIX socket>"),
1077            #[cfg(any(target_os = "android", target_os = "linux"))]
1078            UnixAddrKind::Abstract(name) => fmt_abstract(name, f),
1079        }
1080    }
1081}
1082
1083impl PartialEq for UnixAddr {
1084    fn eq(&self, other: &UnixAddr) -> bool {
1085        self.kind() == other.kind()
1086    }
1087}
1088
1089impl Eq for UnixAddr {}
1090
1091impl Hash for UnixAddr {
1092    fn hash<H: Hasher>(&self, s: &mut H) {
1093        self.kind().hash(s)
1094    }
1095}
1096
1097/// Anything that, in C, can be cast back and forth to `sockaddr`.
1098///
1099/// Most implementors also implement `AsRef<libc::XXX>` to access their
1100/// inner type read-only.
1101#[allow(clippy::len_without_is_empty)]
1102pub trait SockaddrLike: private::SockaddrLikePriv {
1103    /// Returns a raw pointer to the inner structure.  Useful for FFI.
1104    fn as_ptr(&self) -> *const libc::sockaddr {
1105        self as *const Self as *const libc::sockaddr
1106    }
1107
1108    /// Unsafe constructor from a variable length source
1109    ///
1110    /// Some C APIs from provide `len`, and others do not.  If it's provided it
1111    /// will be validated.  If not, it will be guessed based on the family.
1112    ///
1113    /// # Arguments
1114    ///
1115    /// - `addr`:   raw pointer to something that can be cast to a
1116    ///             `libc::sockaddr`. For example, `libc::sockaddr_in`,
1117    ///             `libc::sockaddr_in6`, etc.
1118    /// - `len`:    For fixed-width types like `sockaddr_in`, it will be
1119    ///             validated if present and ignored if not.  For variable-width
1120    ///             types it is required and must be the total length of valid
1121    ///             data.  For example, if `addr` points to a
1122    ///             named `sockaddr_un`, then `len` must be the length of the
1123    ///             structure up to but not including the trailing NUL.
1124    ///
1125    /// # Safety
1126    ///
1127    /// `addr` must be valid for the specific type of sockaddr.  `len`, if
1128    /// present, must not exceed the length of valid data in `addr`.
1129    unsafe fn from_raw(
1130        addr: *const libc::sockaddr,
1131        len: Option<libc::socklen_t>,
1132    ) -> Option<Self>
1133    where
1134        Self: Sized;
1135
1136    /// Return the address family of this socket
1137    ///
1138    /// # Examples
1139    /// One common use is to match on the family of a union type, like this:
1140    /// ```
1141    /// # use nix::sys::socket::*;
1142    /// let fd = socket(AddressFamily::Inet, SockType::Stream,
1143    ///     SockFlag::empty(), None).unwrap();
1144    /// let ss: SockaddrStorage = getsockname(fd).unwrap();
1145    /// match ss.family().unwrap() {
1146    ///     AddressFamily::Inet => println!("{}", ss.as_sockaddr_in().unwrap()),
1147    ///     AddressFamily::Inet6 => println!("{}", ss.as_sockaddr_in6().unwrap()),
1148    ///     _ => println!("Unexpected address family")
1149    /// }
1150    /// ```
1151    fn family(&self) -> Option<AddressFamily> {
1152        // Safe since all implementors have a sa_family field at the same
1153        // address, and they're all repr(C)
1154        AddressFamily::from_i32(unsafe {
1155            (*(self as *const Self as *const libc::sockaddr)).sa_family as i32
1156        })
1157    }
1158
1159    cfg_if! {
1160        if #[cfg(any(target_os = "dragonfly",
1161                  target_os = "freebsd",
1162                  target_os = "ios",
1163                  target_os = "macos",
1164                  target_os = "netbsd",
1165                  target_os = "openbsd"))] {
1166            /// Return the length of valid data in the sockaddr structure.
1167            ///
1168            /// For fixed-size sockaddrs, this should be the size of the
1169            /// structure.  But for variable-sized types like [`UnixAddr`] it
1170            /// may be less.
1171            fn len(&self) -> libc::socklen_t {
1172                // Safe since all implementors have a sa_len field at the same
1173                // address, and they're all repr(transparent).
1174                // Robust for all implementors.
1175                unsafe {
1176                    (*(self as *const Self as *const libc::sockaddr)).sa_len
1177                }.into()
1178            }
1179        } else {
1180            /// Return the length of valid data in the sockaddr structure.
1181            ///
1182            /// For fixed-size sockaddrs, this should be the size of the
1183            /// structure.  But for variable-sized types like [`UnixAddr`] it
1184            /// may be less.
1185            fn len(&self) -> libc::socklen_t {
1186                // No robust default implementation is possible without an
1187                // sa_len field.  Implementors with a variable size must
1188                // override this method.
1189                mem::size_of_val(self) as libc::socklen_t
1190            }
1191        }
1192    }
1193
1194    /// Return the available space in the structure
1195    fn size() -> libc::socklen_t
1196    where
1197        Self: Sized,
1198    {
1199        mem::size_of::<Self>() as libc::socklen_t
1200    }
1201}
1202
1203impl private::SockaddrLikePriv for () {
1204    fn as_mut_ptr(&mut self) -> *mut libc::sockaddr {
1205        ptr::null_mut()
1206    }
1207}
1208
1209/// `()` can be used in place of a real Sockaddr when no address is expected,
1210/// for example for a field of `Option<S> where S: SockaddrLike`.
1211// If this RFC ever stabilizes, then ! will be a better choice.
1212// https://github.com/rust-lang/rust/issues/35121
1213impl SockaddrLike for () {
1214    fn as_ptr(&self) -> *const libc::sockaddr {
1215        ptr::null()
1216    }
1217
1218    unsafe fn from_raw(
1219        _: *const libc::sockaddr,
1220        _: Option<libc::socklen_t>,
1221    ) -> Option<Self>
1222    where
1223        Self: Sized,
1224    {
1225        None
1226    }
1227
1228    fn family(&self) -> Option<AddressFamily> {
1229        None
1230    }
1231
1232    fn len(&self) -> libc::socklen_t {
1233        0
1234    }
1235}
1236
1237/// An IPv4 socket address
1238// This is identical to net::SocketAddrV4.  But the standard library
1239// doesn't allow direct access to the libc fields, which we need.  So we
1240// reimplement it here.
1241#[cfg(feature = "net")]
1242#[repr(transparent)]
1243#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1244pub struct SockaddrIn(libc::sockaddr_in);
1245
1246#[cfg(feature = "net")]
1247impl SockaddrIn {
1248    /// Returns the IP address associated with this socket address, in native
1249    /// endian.
1250    pub const fn ip(&self) -> libc::in_addr_t {
1251        u32::from_be(self.0.sin_addr.s_addr)
1252    }
1253
1254    /// Creates a new socket address from IPv4 octets and a port number.
1255    pub fn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self {
1256        Self(libc::sockaddr_in {
1257            #[cfg(any(
1258                target_os = "dragonfly",
1259                target_os = "freebsd",
1260                target_os = "ios",
1261                target_os = "macos",
1262                target_os = "netbsd",
1263                target_os = "haiku",
1264                target_os = "openbsd"
1265            ))]
1266            sin_len: Self::size() as u8,
1267            sin_family: AddressFamily::Inet as sa_family_t,
1268            sin_port: u16::to_be(port),
1269            sin_addr: libc::in_addr {
1270                s_addr: u32::from_ne_bytes([a, b, c, d]),
1271            },
1272            sin_zero: unsafe { mem::zeroed() },
1273        })
1274    }
1275
1276    /// Returns the port number associated with this socket address, in native
1277    /// endian.
1278    pub const fn port(&self) -> u16 {
1279        u16::from_be(self.0.sin_port)
1280    }
1281}
1282
1283#[cfg(feature = "net")]
1284impl private::SockaddrLikePriv for SockaddrIn {}
1285#[cfg(feature = "net")]
1286impl SockaddrLike for SockaddrIn {
1287    unsafe fn from_raw(
1288        addr: *const libc::sockaddr,
1289        len: Option<libc::socklen_t>,
1290    ) -> Option<Self>
1291    where
1292        Self: Sized,
1293    {
1294        if let Some(l) = len {
1295            if l != mem::size_of::<libc::sockaddr_in>() as libc::socklen_t {
1296                return None;
1297            }
1298        }
1299        if (*addr).sa_family as i32 != libc::AF_INET {
1300            return None;
1301        }
1302        Some(Self(ptr::read_unaligned(addr as *const _)))
1303    }
1304}
1305
1306#[cfg(feature = "net")]
1307impl AsRef<libc::sockaddr_in> for SockaddrIn {
1308    fn as_ref(&self) -> &libc::sockaddr_in {
1309        &self.0
1310    }
1311}
1312
1313#[cfg(feature = "net")]
1314impl fmt::Display for SockaddrIn {
1315    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1316        let ne = u32::from_be(self.0.sin_addr.s_addr);
1317        let port = u16::from_be(self.0.sin_port);
1318        write!(
1319            f,
1320            "{}.{}.{}.{}:{}",
1321            ne >> 24,
1322            (ne >> 16) & 0xFF,
1323            (ne >> 8) & 0xFF,
1324            ne & 0xFF,
1325            port
1326        )
1327    }
1328}
1329
1330#[cfg(feature = "net")]
1331impl From<net::SocketAddrV4> for SockaddrIn {
1332    fn from(addr: net::SocketAddrV4) -> Self {
1333        Self(libc::sockaddr_in {
1334            #[cfg(any(
1335                target_os = "dragonfly",
1336                target_os = "freebsd",
1337                target_os = "haiku",
1338                target_os = "hermit",
1339                target_os = "ios",
1340                target_os = "macos",
1341                target_os = "netbsd",
1342                target_os = "openbsd"
1343            ))]
1344            sin_len: mem::size_of::<libc::sockaddr_in>() as u8,
1345            sin_family: AddressFamily::Inet as sa_family_t,
1346            sin_port: addr.port().to_be(), // network byte order
1347            sin_addr: ipv4addr_to_libc(*addr.ip()),
1348            ..unsafe { mem::zeroed() }
1349        })
1350    }
1351}
1352
1353#[cfg(feature = "net")]
1354impl From<SockaddrIn> for net::SocketAddrV4 {
1355    fn from(addr: SockaddrIn) -> Self {
1356        net::SocketAddrV4::new(
1357            net::Ipv4Addr::from(addr.0.sin_addr.s_addr.to_ne_bytes()),
1358            u16::from_be(addr.0.sin_port),
1359        )
1360    }
1361}
1362
1363#[cfg(feature = "net")]
1364impl std::str::FromStr for SockaddrIn {
1365    type Err = net::AddrParseError;
1366
1367    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1368        net::SocketAddrV4::from_str(s).map(SockaddrIn::from)
1369    }
1370}
1371
1372/// An IPv6 socket address
1373#[cfg(feature = "net")]
1374#[repr(transparent)]
1375#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1376pub struct SockaddrIn6(libc::sockaddr_in6);
1377
1378#[cfg(feature = "net")]
1379impl SockaddrIn6 {
1380    /// Returns the flow information associated with this address.
1381    pub const fn flowinfo(&self) -> u32 {
1382        self.0.sin6_flowinfo
1383    }
1384
1385    /// Returns the IP address associated with this socket address.
1386    pub fn ip(&self) -> net::Ipv6Addr {
1387        net::Ipv6Addr::from(self.0.sin6_addr.s6_addr)
1388    }
1389
1390    /// Returns the port number associated with this socket address, in native
1391    /// endian.
1392    pub const fn port(&self) -> u16 {
1393        u16::from_be(self.0.sin6_port)
1394    }
1395
1396    /// Returns the scope ID associated with this address.
1397    pub const fn scope_id(&self) -> u32 {
1398        self.0.sin6_scope_id
1399    }
1400}
1401
1402#[cfg(feature = "net")]
1403impl private::SockaddrLikePriv for SockaddrIn6 {}
1404#[cfg(feature = "net")]
1405impl SockaddrLike for SockaddrIn6 {
1406    unsafe fn from_raw(
1407        addr: *const libc::sockaddr,
1408        len: Option<libc::socklen_t>,
1409    ) -> Option<Self>
1410    where
1411        Self: Sized,
1412    {
1413        if let Some(l) = len {
1414            if l != mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t {
1415                return None;
1416            }
1417        }
1418        if (*addr).sa_family as i32 != libc::AF_INET6 {
1419            return None;
1420        }
1421        Some(Self(ptr::read_unaligned(addr as *const _)))
1422    }
1423}
1424
1425#[cfg(feature = "net")]
1426impl AsRef<libc::sockaddr_in6> for SockaddrIn6 {
1427    fn as_ref(&self) -> &libc::sockaddr_in6 {
1428        &self.0
1429    }
1430}
1431
1432#[cfg(feature = "net")]
1433impl fmt::Display for SockaddrIn6 {
1434    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1435        // These things are really hard to display properly.  Easier to let std
1436        // do it.
1437        let std = net::SocketAddrV6::new(
1438            self.ip(),
1439            self.port(),
1440            self.flowinfo(),
1441            self.scope_id(),
1442        );
1443        std.fmt(f)
1444    }
1445}
1446
1447#[cfg(feature = "net")]
1448impl From<net::SocketAddrV6> for SockaddrIn6 {
1449    fn from(addr: net::SocketAddrV6) -> Self {
1450        #[allow(clippy::needless_update)] // It isn't needless on Illumos
1451        Self(libc::sockaddr_in6 {
1452            #[cfg(any(
1453                target_os = "dragonfly",
1454                target_os = "freebsd",
1455                target_os = "haiku",
1456                target_os = "hermit",
1457                target_os = "ios",
1458                target_os = "macos",
1459                target_os = "netbsd",
1460                target_os = "openbsd"
1461            ))]
1462            sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8,
1463            sin6_family: AddressFamily::Inet6 as sa_family_t,
1464            sin6_port: addr.port().to_be(), // network byte order
1465            sin6_addr: ipv6addr_to_libc(addr.ip()),
1466            sin6_flowinfo: addr.flowinfo(), // host byte order
1467            sin6_scope_id: addr.scope_id(), // host byte order
1468            ..unsafe { mem::zeroed() }
1469        })
1470    }
1471}
1472
1473#[cfg(feature = "net")]
1474impl From<SockaddrIn6> for net::SocketAddrV6 {
1475    fn from(addr: SockaddrIn6) -> Self {
1476        net::SocketAddrV6::new(
1477            net::Ipv6Addr::from(addr.0.sin6_addr.s6_addr),
1478            u16::from_be(addr.0.sin6_port),
1479            u32::from_be(addr.0.sin6_flowinfo),
1480            u32::from_be(addr.0.sin6_scope_id),
1481        )
1482    }
1483}
1484
1485#[cfg(feature = "net")]
1486impl std::str::FromStr for SockaddrIn6 {
1487    type Err = net::AddrParseError;
1488
1489    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1490        net::SocketAddrV6::from_str(s).map(SockaddrIn6::from)
1491    }
1492}
1493
1494/// A container for any sockaddr type
1495///
1496/// Just like C's `sockaddr_storage`, this type is large enough to hold any type
1497/// of sockaddr.  It can be used as an argument with functions like
1498/// [`bind`](super::bind) and [`getsockname`](super::getsockname).  Though it is
1499/// a union, it can be safely accessed through the `as_*` methods.
1500///
1501/// # Example
1502/// ```
1503/// # use nix::sys::socket::*;
1504/// # use std::str::FromStr;
1505/// let localhost = SockaddrIn::from_str("127.0.0.1:8081").unwrap();
1506/// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(),
1507///     None).unwrap();
1508/// bind(fd, &localhost).expect("bind");
1509/// let ss: SockaddrStorage = getsockname(fd).expect("getsockname");
1510/// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap());
1511/// ```
1512#[derive(Clone, Copy, Eq)]
1513#[repr(C)]
1514pub union SockaddrStorage {
1515    #[cfg(any(target_os = "android", target_os = "linux"))]
1516    #[cfg_attr(docsrs, doc(cfg(all())))]
1517    alg: AlgAddr,
1518    #[cfg(feature = "net")]
1519    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1520    dl: LinkAddr,
1521    #[cfg(any(target_os = "android", target_os = "linux"))]
1522    nl: NetlinkAddr,
1523    #[cfg(all(
1524        feature = "ioctl",
1525        any(target_os = "ios", target_os = "macos")
1526    ))]
1527    #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
1528    sctl: SysControlAddr,
1529    #[cfg(feature = "net")]
1530    sin: SockaddrIn,
1531    #[cfg(feature = "net")]
1532    sin6: SockaddrIn6,
1533    ss: libc::sockaddr_storage,
1534    su: UnixAddr,
1535    #[cfg(any(target_os = "android", target_os = "linux"))]
1536    #[cfg_attr(docsrs, doc(cfg(all())))]
1537    vsock: VsockAddr,
1538}
1539impl private::SockaddrLikePriv for SockaddrStorage {}
1540impl SockaddrLike for SockaddrStorage {
1541    unsafe fn from_raw(
1542        addr: *const libc::sockaddr,
1543        l: Option<libc::socklen_t>,
1544    ) -> Option<Self>
1545    where
1546        Self: Sized,
1547    {
1548        if addr.is_null() {
1549            return None;
1550        }
1551        if let Some(len) = l {
1552            let ulen = len as usize;
1553            if ulen < offset_of!(libc::sockaddr, sa_data)
1554                || ulen > mem::size_of::<libc::sockaddr_storage>()
1555            {
1556                None
1557            } else {
1558                let mut ss: libc::sockaddr_storage = mem::zeroed();
1559                let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8;
1560                ptr::copy(addr as *const u8, ssp, len as usize);
1561                #[cfg(any(
1562                    target_os = "android",
1563                    target_os = "fuchsia",
1564                    target_os = "illumos",
1565                    target_os = "linux"
1566                ))]
1567                if i32::from(ss.ss_family) == libc::AF_UNIX {
1568                    // Safe because we UnixAddr is strictly smaller than
1569                    // SockaddrStorage, and we just initialized the structure.
1570                    (*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8;
1571                }
1572                Some(Self { ss })
1573            }
1574        } else {
1575            // If length is not available and addr is of a fixed-length type,
1576            // copy it.  If addr is of a variable length type and len is not
1577            // available, then there's nothing we can do.
1578            match (*addr).sa_family as i32 {
1579                #[cfg(any(target_os = "android", target_os = "linux"))]
1580                libc::AF_ALG => {
1581                    AlgAddr::from_raw(addr, l).map(|alg| Self { alg })
1582                }
1583                #[cfg(feature = "net")]
1584                libc::AF_INET => {
1585                    SockaddrIn::from_raw(addr, l).map(|sin| Self { sin })
1586                }
1587                #[cfg(feature = "net")]
1588                libc::AF_INET6 => {
1589                    SockaddrIn6::from_raw(addr, l).map(|sin6| Self { sin6 })
1590                }
1591                #[cfg(any(
1592                    target_os = "dragonfly",
1593                    target_os = "freebsd",
1594                    target_os = "ios",
1595                    target_os = "macos",
1596                    target_os = "illumos",
1597                    target_os = "netbsd",
1598                    target_os = "haiku",
1599                    target_os = "openbsd"
1600                ))]
1601                #[cfg(feature = "net")]
1602                libc::AF_LINK => {
1603                    LinkAddr::from_raw(addr, l).map(|dl| Self { dl })
1604                }
1605                #[cfg(any(target_os = "android", target_os = "linux"))]
1606                libc::AF_NETLINK => {
1607                    NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl })
1608                }
1609                #[cfg(any(
1610                    target_os = "android",
1611                    target_os = "fuchsia",
1612                    target_os = "linux"
1613                ))]
1614                #[cfg(feature = "net")]
1615                libc::AF_PACKET => {
1616                    LinkAddr::from_raw(addr, l).map(|dl| Self { dl })
1617                }
1618                #[cfg(all(
1619                    feature = "ioctl",
1620                    any(target_os = "ios", target_os = "macos")
1621                ))]
1622                libc::AF_SYSTEM => {
1623                    SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl })
1624                }
1625                #[cfg(any(target_os = "android", target_os = "linux"))]
1626                libc::AF_VSOCK => {
1627                    VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock })
1628                }
1629                _ => None,
1630            }
1631        }
1632    }
1633
1634    #[cfg(any(
1635        target_os = "android",
1636        target_os = "fuchsia",
1637        target_os = "illumos",
1638        target_os = "linux"
1639    ))]
1640    fn len(&self) -> libc::socklen_t {
1641        match self.as_unix_addr() {
1642            // The UnixAddr type knows its own length
1643            Some(ua) => ua.len(),
1644            // For all else, we're just a boring SockaddrStorage
1645            None => mem::size_of_val(self) as libc::socklen_t
1646        }
1647    }
1648}
1649
1650macro_rules! accessors {
1651    (
1652        $fname:ident,
1653        $fname_mut:ident,
1654        $sockty:ty,
1655        $family:expr,
1656        $libc_ty:ty,
1657        $field:ident) => {
1658        /// Safely and falliably downcast to an immutable reference
1659        pub fn $fname(&self) -> Option<&$sockty> {
1660            if self.family() == Some($family)
1661                && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t
1662            {
1663                // Safe because family and len are validated
1664                Some(unsafe { &self.$field })
1665            } else {
1666                None
1667            }
1668        }
1669
1670        /// Safely and falliably downcast to a mutable reference
1671        pub fn $fname_mut(&mut self) -> Option<&mut $sockty> {
1672            if self.family() == Some($family)
1673                && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t
1674            {
1675                // Safe because family and len are validated
1676                Some(unsafe { &mut self.$field })
1677            } else {
1678                None
1679            }
1680        }
1681    };
1682}
1683
1684impl SockaddrStorage {
1685    /// Downcast to an immutable `[UnixAddr]` reference.
1686    pub fn as_unix_addr(&self) -> Option<&UnixAddr> {
1687        cfg_if! {
1688            if #[cfg(any(target_os = "android",
1689                     target_os = "fuchsia",
1690                     target_os = "illumos",
1691                     target_os = "linux"
1692                ))]
1693            {
1694                let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
1695                // Safe because UnixAddr is strictly smaller than
1696                // sockaddr_storage, and we're fully initialized
1697                let len = unsafe {
1698                    (*(p as *const UnixAddr )).sun_len as usize
1699                };
1700            } else {
1701                let len = self.len() as usize;
1702            }
1703        }
1704        // Sanity checks
1705        if self.family() != Some(AddressFamily::Unix) ||
1706           len < offset_of!(libc::sockaddr_un, sun_path) ||
1707           len > mem::size_of::<libc::sockaddr_un>() {
1708            None
1709        } else {
1710            Some(unsafe{&self.su})
1711        }
1712    }
1713
1714    /// Downcast to a mutable `[UnixAddr]` reference.
1715    pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> {
1716        cfg_if! {
1717            if #[cfg(any(target_os = "android",
1718                     target_os = "fuchsia",
1719                     target_os = "illumos",
1720                     target_os = "linux"
1721                ))]
1722            {
1723                let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
1724                // Safe because UnixAddr is strictly smaller than
1725                // sockaddr_storage, and we're fully initialized
1726                let len = unsafe {
1727                    (*(p as *const UnixAddr )).sun_len as usize
1728                };
1729            } else {
1730                let len = self.len() as usize;
1731            }
1732        }
1733        // Sanity checks
1734        if self.family() != Some(AddressFamily::Unix) ||
1735           len < offset_of!(libc::sockaddr_un, sun_path) ||
1736           len > mem::size_of::<libc::sockaddr_un>() {
1737            None
1738        } else {
1739            Some(unsafe{&mut self.su})
1740        }
1741    }
1742
1743    #[cfg(any(target_os = "android", target_os = "linux"))]
1744    accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr,
1745    AddressFamily::Alg, libc::sockaddr_alg, alg}
1746
1747    #[cfg(any(
1748        target_os = "android",
1749        target_os = "fuchsia",
1750        target_os = "linux"
1751    ))]
1752    #[cfg(feature = "net")]
1753    accessors! {
1754    as_link_addr, as_link_addr_mut, LinkAddr,
1755    AddressFamily::Packet, libc::sockaddr_ll, dl}
1756
1757    #[cfg(any(
1758        target_os = "dragonfly",
1759        target_os = "freebsd",
1760        target_os = "ios",
1761        target_os = "macos",
1762        target_os = "illumos",
1763        target_os = "netbsd",
1764        target_os = "openbsd"
1765    ))]
1766    #[cfg(feature = "net")]
1767    accessors! {
1768    as_link_addr, as_link_addr_mut, LinkAddr,
1769    AddressFamily::Link, libc::sockaddr_dl, dl}
1770
1771    #[cfg(feature = "net")]
1772    accessors! {
1773    as_sockaddr_in, as_sockaddr_in_mut, SockaddrIn,
1774    AddressFamily::Inet, libc::sockaddr_in, sin}
1775
1776    #[cfg(feature = "net")]
1777    accessors! {
1778    as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6,
1779    AddressFamily::Inet6, libc::sockaddr_in6, sin6}
1780
1781    #[cfg(any(target_os = "android", target_os = "linux"))]
1782    accessors! {as_netlink_addr, as_netlink_addr_mut, NetlinkAddr,
1783    AddressFamily::Netlink, libc::sockaddr_nl, nl}
1784
1785    #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))]
1786    #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
1787    accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr,
1788    AddressFamily::System, libc::sockaddr_ctl, sctl}
1789
1790    #[cfg(any(target_os = "android", target_os = "linux"))]
1791    #[cfg_attr(docsrs, doc(cfg(all())))]
1792    accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr,
1793    AddressFamily::Vsock, libc::sockaddr_vm, vsock}
1794}
1795
1796impl fmt::Debug for SockaddrStorage {
1797    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1798        f.debug_struct("SockaddrStorage")
1799            // Safe because sockaddr_storage has the least specific
1800            // field types
1801            .field("ss", unsafe { &self.ss })
1802            .finish()
1803    }
1804}
1805
1806impl fmt::Display for SockaddrStorage {
1807    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1808        unsafe {
1809            match self.ss.ss_family as i32 {
1810                #[cfg(any(target_os = "android", target_os = "linux"))]
1811                libc::AF_ALG => self.alg.fmt(f),
1812                #[cfg(feature = "net")]
1813                libc::AF_INET => self.sin.fmt(f),
1814                #[cfg(feature = "net")]
1815                libc::AF_INET6 => self.sin6.fmt(f),
1816                #[cfg(any(
1817                    target_os = "dragonfly",
1818                    target_os = "freebsd",
1819                    target_os = "ios",
1820                    target_os = "macos",
1821                    target_os = "illumos",
1822                    target_os = "netbsd",
1823                    target_os = "openbsd"
1824                ))]
1825                #[cfg(feature = "net")]
1826                libc::AF_LINK => self.dl.fmt(f),
1827                #[cfg(any(target_os = "android", target_os = "linux"))]
1828                libc::AF_NETLINK => self.nl.fmt(f),
1829                #[cfg(any(
1830                    target_os = "android",
1831                    target_os = "linux",
1832                    target_os = "fuchsia"
1833                ))]
1834                #[cfg(feature = "net")]
1835                libc::AF_PACKET => self.dl.fmt(f),
1836                #[cfg(any(target_os = "ios", target_os = "macos"))]
1837                #[cfg(feature = "ioctl")]
1838                libc::AF_SYSTEM => self.sctl.fmt(f),
1839                libc::AF_UNIX => self.su.fmt(f),
1840                #[cfg(any(target_os = "android", target_os = "linux"))]
1841                libc::AF_VSOCK => self.vsock.fmt(f),
1842                _ => "<Address family unspecified>".fmt(f),
1843            }
1844        }
1845    }
1846}
1847
1848#[cfg(feature = "net")]
1849impl From<net::SocketAddrV4> for SockaddrStorage {
1850    fn from(s: net::SocketAddrV4) -> Self {
1851        unsafe {
1852            let mut ss: Self = mem::zeroed();
1853            ss.sin = SockaddrIn::from(s);
1854            ss
1855        }
1856    }
1857}
1858
1859#[cfg(feature = "net")]
1860impl From<net::SocketAddrV6> for SockaddrStorage {
1861    fn from(s: net::SocketAddrV6) -> Self {
1862        unsafe {
1863            let mut ss: Self = mem::zeroed();
1864            ss.sin6 = SockaddrIn6::from(s);
1865            ss
1866        }
1867    }
1868}
1869
1870#[cfg(feature = "net")]
1871impl From<net::SocketAddr> for SockaddrStorage {
1872    fn from(s: net::SocketAddr) -> Self {
1873        match s {
1874            net::SocketAddr::V4(sa4) => Self::from(sa4),
1875            net::SocketAddr::V6(sa6) => Self::from(sa6),
1876        }
1877    }
1878}
1879
1880impl Hash for SockaddrStorage {
1881    fn hash<H: Hasher>(&self, s: &mut H) {
1882        unsafe {
1883            match self.ss.ss_family as i32 {
1884                #[cfg(any(target_os = "android", target_os = "linux"))]
1885                libc::AF_ALG => self.alg.hash(s),
1886                #[cfg(feature = "net")]
1887                libc::AF_INET => self.sin.hash(s),
1888                #[cfg(feature = "net")]
1889                libc::AF_INET6 => self.sin6.hash(s),
1890                #[cfg(any(
1891                    target_os = "dragonfly",
1892                    target_os = "freebsd",
1893                    target_os = "ios",
1894                    target_os = "macos",
1895                    target_os = "illumos",
1896                    target_os = "netbsd",
1897                    target_os = "openbsd"
1898                ))]
1899                #[cfg(feature = "net")]
1900                libc::AF_LINK => self.dl.hash(s),
1901                #[cfg(any(target_os = "android", target_os = "linux"))]
1902                libc::AF_NETLINK => self.nl.hash(s),
1903                #[cfg(any(
1904                    target_os = "android",
1905                    target_os = "linux",
1906                    target_os = "fuchsia"
1907                ))]
1908                #[cfg(feature = "net")]
1909                libc::AF_PACKET => self.dl.hash(s),
1910                #[cfg(any(target_os = "ios", target_os = "macos"))]
1911                #[cfg(feature = "ioctl")]
1912                libc::AF_SYSTEM => self.sctl.hash(s),
1913                libc::AF_UNIX => self.su.hash(s),
1914                #[cfg(any(target_os = "android", target_os = "linux"))]
1915                libc::AF_VSOCK => self.vsock.hash(s),
1916                _ => self.ss.hash(s),
1917            }
1918        }
1919    }
1920}
1921
1922impl PartialEq for SockaddrStorage {
1923    fn eq(&self, other: &Self) -> bool {
1924        unsafe {
1925            match (self.ss.ss_family as i32, other.ss.ss_family as i32) {
1926                #[cfg(any(target_os = "android", target_os = "linux"))]
1927                (libc::AF_ALG, libc::AF_ALG) => self.alg == other.alg,
1928                #[cfg(feature = "net")]
1929                (libc::AF_INET, libc::AF_INET) => self.sin == other.sin,
1930                #[cfg(feature = "net")]
1931                (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6,
1932                #[cfg(any(
1933                    target_os = "dragonfly",
1934                    target_os = "freebsd",
1935                    target_os = "ios",
1936                    target_os = "macos",
1937                    target_os = "illumos",
1938                    target_os = "netbsd",
1939                    target_os = "openbsd"
1940                ))]
1941                #[cfg(feature = "net")]
1942                (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl,
1943                #[cfg(any(target_os = "android", target_os = "linux"))]
1944                (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl,
1945                #[cfg(any(
1946                    target_os = "android",
1947                    target_os = "fuchsia",
1948                    target_os = "linux"
1949                ))]
1950                #[cfg(feature = "net")]
1951                (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl,
1952                #[cfg(any(target_os = "ios", target_os = "macos"))]
1953                #[cfg(feature = "ioctl")]
1954                (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl,
1955                (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su,
1956                #[cfg(any(target_os = "android", target_os = "linux"))]
1957                (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock,
1958                _ => false,
1959            }
1960        }
1961    }
1962}
1963
1964mod private {
1965    pub trait SockaddrLikePriv {
1966        /// Returns a mutable raw pointer to the inner structure.
1967        ///
1968        /// # Safety
1969        ///
1970        /// This method is technically safe, but modifying the inner structure's
1971        /// `family` or `len` fields may result in violating Nix's invariants.
1972        /// It is best to use this method only with foreign functions that do
1973        /// not change the sockaddr type.
1974        fn as_mut_ptr(&mut self) -> *mut libc::sockaddr {
1975            self as *mut Self as *mut libc::sockaddr
1976        }
1977    }
1978}
1979
1980/// Represents a socket address
1981#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1982#[deprecated(
1983    since = "0.24.0",
1984    note = "use SockaddrLike or SockaddrStorage instead"
1985)]
1986#[allow(missing_docs)] // Since they're all deprecated anyway
1987#[allow(deprecated)]
1988#[non_exhaustive]
1989pub enum SockAddr {
1990    #[cfg(feature = "net")]
1991    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1992    Inet(InetAddr),
1993    Unix(UnixAddr),
1994    #[cfg(any(target_os = "android", target_os = "linux"))]
1995    #[cfg_attr(docsrs, doc(cfg(all())))]
1996    Netlink(NetlinkAddr),
1997    #[cfg(any(target_os = "android", target_os = "linux"))]
1998    #[cfg_attr(docsrs, doc(cfg(all())))]
1999    Alg(AlgAddr),
2000    #[cfg(all(
2001        feature = "ioctl",
2002        any(target_os = "ios", target_os = "macos")
2003    ))]
2004    #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
2005    SysControl(SysControlAddr),
2006    /// Datalink address (MAC)
2007    #[cfg(any(
2008        target_os = "android",
2009        target_os = "dragonfly",
2010        target_os = "freebsd",
2011        target_os = "ios",
2012        target_os = "linux",
2013        target_os = "macos",
2014        target_os = "illumos",
2015        target_os = "netbsd",
2016        target_os = "openbsd"
2017    ))]
2018    #[cfg(feature = "net")]
2019    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
2020    Link(LinkAddr),
2021    #[cfg(any(target_os = "android", target_os = "linux"))]
2022    #[cfg_attr(docsrs, doc(cfg(all())))]
2023    Vsock(VsockAddr),
2024}
2025
2026#[allow(missing_docs)] // Since they're all deprecated anyway
2027#[allow(deprecated)]
2028impl SockAddr {
2029    feature! {
2030    #![feature = "net"]
2031    pub fn new_inet(addr: InetAddr) -> SockAddr {
2032        SockAddr::Inet(addr)
2033    }
2034    }
2035
2036    pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> {
2037        Ok(SockAddr::Unix(UnixAddr::new(path)?))
2038    }
2039
2040    #[cfg(any(target_os = "android", target_os = "linux"))]
2041    #[cfg_attr(docsrs, doc(cfg(all())))]
2042    pub fn new_netlink(pid: u32, groups: u32) -> SockAddr {
2043        SockAddr::Netlink(NetlinkAddr::new(pid, groups))
2044    }
2045
2046    #[cfg(any(target_os = "android", target_os = "linux"))]
2047    #[cfg_attr(docsrs, doc(cfg(all())))]
2048    pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr {
2049        SockAddr::Alg(AlgAddr::new(alg_type, alg_name))
2050    }
2051
2052    feature! {
2053    #![feature = "ioctl"]
2054    #[cfg(any(target_os = "ios", target_os = "macos"))]
2055    pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
2056        SysControlAddr::from_name(sockfd, name, unit).map(SockAddr::SysControl)
2057    }
2058    }
2059
2060    #[cfg(any(target_os = "android", target_os = "linux"))]
2061    #[cfg_attr(docsrs, doc(cfg(all())))]
2062    pub fn new_vsock(cid: u32, port: u32) -> SockAddr {
2063        SockAddr::Vsock(VsockAddr::new(cid, port))
2064    }
2065
2066    pub fn family(&self) -> AddressFamily {
2067        match *self {
2068            #[cfg(feature = "net")]
2069            SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
2070            #[cfg(feature = "net")]
2071            SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
2072            SockAddr::Unix(..) => AddressFamily::Unix,
2073            #[cfg(any(target_os = "android", target_os = "linux"))]
2074            SockAddr::Netlink(..) => AddressFamily::Netlink,
2075            #[cfg(any(target_os = "android", target_os = "linux"))]
2076            SockAddr::Alg(..) => AddressFamily::Alg,
2077            #[cfg(all(
2078                feature = "ioctl",
2079                any(target_os = "ios", target_os = "macos")
2080            ))]
2081            SockAddr::SysControl(..) => AddressFamily::System,
2082            #[cfg(any(target_os = "android", target_os = "linux"))]
2083            #[cfg(feature = "net")]
2084            SockAddr::Link(..) => AddressFamily::Packet,
2085            #[cfg(any(
2086                target_os = "dragonfly",
2087                target_os = "freebsd",
2088                target_os = "ios",
2089                target_os = "macos",
2090                target_os = "netbsd",
2091                target_os = "illumos",
2092                target_os = "openbsd"
2093            ))]
2094            #[cfg(feature = "net")]
2095            SockAddr::Link(..) => AddressFamily::Link,
2096            #[cfg(any(target_os = "android", target_os = "linux"))]
2097            SockAddr::Vsock(..) => AddressFamily::Vsock,
2098        }
2099    }
2100
2101    #[deprecated(since = "0.23.0", note = "use .to_string() instead")]
2102    pub fn to_str(&self) -> String {
2103        format!("{}", self)
2104    }
2105
2106    /// Creates a `SockAddr` struct from libc's sockaddr.
2107    ///
2108    /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System.
2109    /// Returns None for unsupported families.
2110    ///
2111    /// # Safety
2112    ///
2113    /// unsafe because it takes a raw pointer as argument.  The caller must
2114    /// ensure that the pointer is valid.
2115    #[cfg(not(target_os = "fuchsia"))]
2116    #[cfg(feature = "net")]
2117    pub(crate) unsafe fn from_libc_sockaddr(
2118        addr: *const libc::sockaddr,
2119    ) -> Option<SockAddr> {
2120        if addr.is_null() {
2121            None
2122        } else {
2123            match AddressFamily::from_i32(i32::from((*addr).sa_family)) {
2124                Some(AddressFamily::Unix) => None,
2125                #[cfg(feature = "net")]
2126                Some(AddressFamily::Inet) => Some(SockAddr::Inet(
2127                    InetAddr::V4(ptr::read_unaligned(addr as *const _)),
2128                )),
2129                #[cfg(feature = "net")]
2130                Some(AddressFamily::Inet6) => Some(SockAddr::Inet(
2131                    InetAddr::V6(ptr::read_unaligned(addr as *const _)),
2132                )),
2133                #[cfg(any(target_os = "android", target_os = "linux"))]
2134                Some(AddressFamily::Netlink) => Some(SockAddr::Netlink(
2135                    NetlinkAddr(ptr::read_unaligned(addr as *const _)),
2136                )),
2137                #[cfg(all(
2138                    feature = "ioctl",
2139                    any(target_os = "ios", target_os = "macos")
2140                ))]
2141                Some(AddressFamily::System) => Some(SockAddr::SysControl(
2142                    SysControlAddr(ptr::read_unaligned(addr as *const _)),
2143                )),
2144                #[cfg(any(target_os = "android", target_os = "linux"))]
2145                #[cfg(feature = "net")]
2146                Some(AddressFamily::Packet) => Some(SockAddr::Link(LinkAddr(
2147                    ptr::read_unaligned(addr as *const _),
2148                ))),
2149                #[cfg(any(
2150                    target_os = "dragonfly",
2151                    target_os = "freebsd",
2152                    target_os = "ios",
2153                    target_os = "macos",
2154                    target_os = "netbsd",
2155                    target_os = "illumos",
2156                    target_os = "openbsd"
2157                ))]
2158                #[cfg(feature = "net")]
2159                Some(AddressFamily::Link) => {
2160                    let ether_addr =
2161                        LinkAddr(ptr::read_unaligned(addr as *const _));
2162                    if ether_addr.is_empty() {
2163                        None
2164                    } else {
2165                        Some(SockAddr::Link(ether_addr))
2166                    }
2167                }
2168                #[cfg(any(target_os = "android", target_os = "linux"))]
2169                Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(VsockAddr(
2170                    ptr::read_unaligned(addr as *const _),
2171                ))),
2172                // Other address families are currently not supported and simply yield a None
2173                // entry instead of a proper conversion to a `SockAddr`.
2174                Some(_) | None => None,
2175            }
2176        }
2177    }
2178
2179    /// Conversion from nix's SockAddr type to the underlying libc sockaddr type.
2180    ///
2181    /// This is useful for interfacing with other libc functions that don't yet have nix wrappers.
2182    /// Returns a reference to the underlying data type (as a sockaddr reference) along
2183    /// with the size of the actual data type. sockaddr is commonly used as a proxy for
2184    /// a superclass as C doesn't support inheritance, so many functions that take
2185    /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back.
2186    pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
2187        match *self {
2188            #[cfg(feature = "net")]
2189            SockAddr::Inet(InetAddr::V4(ref addr)) => (
2190                // This cast is always allowed in C
2191                unsafe {
2192                    &*(addr as *const libc::sockaddr_in
2193                        as *const libc::sockaddr)
2194                },
2195                mem::size_of_val(addr) as libc::socklen_t,
2196            ),
2197            #[cfg(feature = "net")]
2198            SockAddr::Inet(InetAddr::V6(ref addr)) => (
2199                // This cast is always allowed in C
2200                unsafe {
2201                    &*(addr as *const libc::sockaddr_in6
2202                        as *const libc::sockaddr)
2203                },
2204                mem::size_of_val(addr) as libc::socklen_t,
2205            ),
2206            SockAddr::Unix(ref unix_addr) => (
2207                // This cast is always allowed in C
2208                unsafe {
2209                    &*(&unix_addr.sun as *const libc::sockaddr_un
2210                        as *const libc::sockaddr)
2211                },
2212                unix_addr.sun_len() as libc::socklen_t,
2213            ),
2214            #[cfg(any(target_os = "android", target_os = "linux"))]
2215            SockAddr::Netlink(NetlinkAddr(ref sa)) => (
2216                // This cast is always allowed in C
2217                unsafe {
2218                    &*(sa as *const libc::sockaddr_nl as *const libc::sockaddr)
2219                },
2220                mem::size_of_val(sa) as libc::socklen_t,
2221            ),
2222            #[cfg(any(target_os = "android", target_os = "linux"))]
2223            SockAddr::Alg(AlgAddr(ref sa)) => (
2224                // This cast is always allowed in C
2225                unsafe {
2226                    &*(sa as *const libc::sockaddr_alg as *const libc::sockaddr)
2227                },
2228                mem::size_of_val(sa) as libc::socklen_t,
2229            ),
2230            #[cfg(all(
2231                feature = "ioctl",
2232                any(target_os = "ios", target_os = "macos")
2233            ))]
2234            SockAddr::SysControl(SysControlAddr(ref sa)) => (
2235                // This cast is always allowed in C
2236                unsafe {
2237                    &*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr)
2238                },
2239                mem::size_of_val(sa) as libc::socklen_t,
2240            ),
2241            #[cfg(any(target_os = "android", target_os = "linux"))]
2242            #[cfg(feature = "net")]
2243            SockAddr::Link(LinkAddr(ref addr)) => (
2244                // This cast is always allowed in C
2245                unsafe {
2246                    &*(addr as *const libc::sockaddr_ll
2247                        as *const libc::sockaddr)
2248                },
2249                mem::size_of_val(addr) as libc::socklen_t,
2250            ),
2251            #[cfg(any(
2252                target_os = "dragonfly",
2253                target_os = "freebsd",
2254                target_os = "ios",
2255                target_os = "macos",
2256                target_os = "illumos",
2257                target_os = "netbsd",
2258                target_os = "openbsd"
2259            ))]
2260            #[cfg(feature = "net")]
2261            SockAddr::Link(LinkAddr(ref addr)) => (
2262                // This cast is always allowed in C
2263                unsafe {
2264                    &*(addr as *const libc::sockaddr_dl
2265                        as *const libc::sockaddr)
2266                },
2267                mem::size_of_val(addr) as libc::socklen_t,
2268            ),
2269            #[cfg(any(target_os = "android", target_os = "linux"))]
2270            SockAddr::Vsock(VsockAddr(ref sa)) => (
2271                // This cast is always allowed in C
2272                unsafe {
2273                    &*(sa as *const libc::sockaddr_vm as *const libc::sockaddr)
2274                },
2275                mem::size_of_val(sa) as libc::socklen_t,
2276            ),
2277        }
2278    }
2279}
2280
2281#[allow(deprecated)]
2282impl fmt::Display for SockAddr {
2283    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2284        match *self {
2285            #[cfg(feature = "net")]
2286            SockAddr::Inet(ref inet) => inet.fmt(f),
2287            SockAddr::Unix(ref unix) => unix.fmt(f),
2288            #[cfg(any(target_os = "android", target_os = "linux"))]
2289            SockAddr::Netlink(ref nl) => nl.fmt(f),
2290            #[cfg(any(target_os = "android", target_os = "linux"))]
2291            SockAddr::Alg(ref nl) => nl.fmt(f),
2292            #[cfg(all(
2293                feature = "ioctl",
2294                any(target_os = "ios", target_os = "macos")
2295            ))]
2296            SockAddr::SysControl(ref sc) => sc.fmt(f),
2297            #[cfg(any(
2298                target_os = "android",
2299                target_os = "dragonfly",
2300                target_os = "freebsd",
2301                target_os = "ios",
2302                target_os = "linux",
2303                target_os = "macos",
2304                target_os = "netbsd",
2305                target_os = "illumos",
2306                target_os = "openbsd"
2307            ))]
2308            #[cfg(feature = "net")]
2309            SockAddr::Link(ref ether_addr) => ether_addr.fmt(f),
2310            #[cfg(any(target_os = "android", target_os = "linux"))]
2311            SockAddr::Vsock(ref svm) => svm.fmt(f),
2312        }
2313    }
2314}
2315
2316#[cfg(not(target_os = "fuchsia"))]
2317#[cfg(feature = "net")]
2318#[allow(deprecated)]
2319impl private::SockaddrLikePriv for SockAddr {}
2320#[cfg(not(target_os = "fuchsia"))]
2321#[cfg(feature = "net")]
2322#[allow(deprecated)]
2323impl SockaddrLike for SockAddr {
2324    unsafe fn from_raw(
2325        addr: *const libc::sockaddr,
2326        _len: Option<libc::socklen_t>,
2327    ) -> Option<Self> {
2328        Self::from_libc_sockaddr(addr)
2329    }
2330}
2331
2332#[cfg(any(target_os = "android", target_os = "linux"))]
2333#[cfg_attr(docsrs, doc(cfg(all())))]
2334pub mod netlink {
2335    use super::*;
2336    use crate::sys::socket::addr::AddressFamily;
2337    use libc::{sa_family_t, sockaddr_nl};
2338    use std::{fmt, mem};
2339
2340    /// Address for the Linux kernel user interface device.
2341    ///
2342    /// # References
2343    ///
2344    /// [netlink(7)](https://man7.org/linux/man-pages/man7/netlink.7.html)
2345    #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
2346    #[repr(transparent)]
2347    pub struct NetlinkAddr(pub(in super::super) sockaddr_nl);
2348
2349    impl NetlinkAddr {
2350        /// Construct a new socket address from its port ID and multicast groups
2351        /// mask.
2352        pub fn new(pid: u32, groups: u32) -> NetlinkAddr {
2353            let mut addr: sockaddr_nl = unsafe { mem::zeroed() };
2354            addr.nl_family = AddressFamily::Netlink as sa_family_t;
2355            addr.nl_pid = pid;
2356            addr.nl_groups = groups;
2357
2358            NetlinkAddr(addr)
2359        }
2360
2361        /// Return the socket's port ID.
2362        pub const fn pid(&self) -> u32 {
2363            self.0.nl_pid
2364        }
2365
2366        /// Return the socket's multicast groups mask
2367        pub const fn groups(&self) -> u32 {
2368            self.0.nl_groups
2369        }
2370    }
2371
2372    impl private::SockaddrLikePriv for NetlinkAddr {}
2373    impl SockaddrLike for NetlinkAddr {
2374        unsafe fn from_raw(
2375            addr: *const libc::sockaddr,
2376            len: Option<libc::socklen_t>,
2377        ) -> Option<Self>
2378        where
2379            Self: Sized,
2380        {
2381            if let Some(l) = len {
2382                if l != mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t {
2383                    return None;
2384                }
2385            }
2386            if (*addr).sa_family as i32 != libc::AF_NETLINK {
2387                return None;
2388            }
2389            Some(Self(ptr::read_unaligned(addr as *const _)))
2390        }
2391    }
2392
2393    impl AsRef<libc::sockaddr_nl> for NetlinkAddr {
2394        fn as_ref(&self) -> &libc::sockaddr_nl {
2395            &self.0
2396        }
2397    }
2398
2399    impl fmt::Display for NetlinkAddr {
2400        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2401            write!(f, "pid: {} groups: {}", self.pid(), self.groups())
2402        }
2403    }
2404}
2405
2406#[cfg(any(target_os = "android", target_os = "linux"))]
2407#[cfg_attr(docsrs, doc(cfg(all())))]
2408pub mod alg {
2409    use super::*;
2410    use libc::{c_char, sockaddr_alg, AF_ALG};
2411    use std::ffi::CStr;
2412    use std::hash::{Hash, Hasher};
2413    use std::{fmt, mem, str};
2414
2415    /// Socket address for the Linux kernel crypto API
2416    #[derive(Copy, Clone)]
2417    #[repr(transparent)]
2418    pub struct AlgAddr(pub(in super::super) sockaddr_alg);
2419
2420    impl private::SockaddrLikePriv for AlgAddr {}
2421    impl SockaddrLike for AlgAddr {
2422        unsafe fn from_raw(
2423            addr: *const libc::sockaddr,
2424            l: Option<libc::socklen_t>,
2425        ) -> Option<Self>
2426        where
2427            Self: Sized,
2428        {
2429            if let Some(l) = l {
2430                if l != mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t
2431                {
2432                    return None;
2433                }
2434            }
2435            if (*addr).sa_family as i32 != libc::AF_ALG {
2436                return None;
2437            }
2438            Some(Self(ptr::read_unaligned(addr as *const _)))
2439        }
2440    }
2441
2442    impl AsRef<libc::sockaddr_alg> for AlgAddr {
2443        fn as_ref(&self) -> &libc::sockaddr_alg {
2444            &self.0
2445        }
2446    }
2447
2448    // , PartialEq, Eq, Debug, Hash
2449    impl PartialEq for AlgAddr {
2450        fn eq(&self, other: &Self) -> bool {
2451            let (inner, other) = (self.0, other.0);
2452            (
2453                inner.salg_family,
2454                &inner.salg_type[..],
2455                inner.salg_feat,
2456                inner.salg_mask,
2457                &inner.salg_name[..],
2458            ) == (
2459                other.salg_family,
2460                &other.salg_type[..],
2461                other.salg_feat,
2462                other.salg_mask,
2463                &other.salg_name[..],
2464            )
2465        }
2466    }
2467
2468    impl Eq for AlgAddr {}
2469
2470    impl Hash for AlgAddr {
2471        fn hash<H: Hasher>(&self, s: &mut H) {
2472            let inner = self.0;
2473            (
2474                inner.salg_family,
2475                &inner.salg_type[..],
2476                inner.salg_feat,
2477                inner.salg_mask,
2478                &inner.salg_name[..],
2479            )
2480                .hash(s);
2481        }
2482    }
2483
2484    impl AlgAddr {
2485        /// Construct an `AF_ALG` socket from its cipher name and type.
2486        pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr {
2487            let mut addr: sockaddr_alg = unsafe { mem::zeroed() };
2488            addr.salg_family = AF_ALG as u16;
2489            addr.salg_type[..alg_type.len()]
2490                .copy_from_slice(alg_type.to_string().as_bytes());
2491            addr.salg_name[..alg_name.len()]
2492                .copy_from_slice(alg_name.to_string().as_bytes());
2493
2494            AlgAddr(addr)
2495        }
2496
2497        /// Return the socket's cipher type, for example `hash` or `aead`.
2498        pub fn alg_type(&self) -> &CStr {
2499            unsafe {
2500                CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char)
2501            }
2502        }
2503
2504        /// Return the socket's cipher name, for example `sha1`.
2505        pub fn alg_name(&self) -> &CStr {
2506            unsafe {
2507                CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char)
2508            }
2509        }
2510    }
2511
2512    impl fmt::Display for AlgAddr {
2513        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2514            write!(
2515                f,
2516                "type: {} alg: {}",
2517                self.alg_name().to_string_lossy(),
2518                self.alg_type().to_string_lossy()
2519            )
2520        }
2521    }
2522
2523    impl fmt::Debug for AlgAddr {
2524        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2525            fmt::Display::fmt(self, f)
2526        }
2527    }
2528}
2529
2530feature! {
2531#![feature = "ioctl"]
2532#[cfg(any(target_os = "ios", target_os = "macos"))]
2533pub mod sys_control {
2534    use crate::sys::socket::addr::AddressFamily;
2535    use libc::{self, c_uchar};
2536    use std::{fmt, mem, ptr};
2537    use std::os::unix::io::RawFd;
2538    use crate::{Errno, Result};
2539    use super::{private, SockaddrLike};
2540
2541    // FIXME: Move type into `libc`
2542    #[repr(C)]
2543    #[derive(Clone, Copy)]
2544    #[allow(missing_debug_implementations)]
2545    pub struct ctl_ioc_info {
2546        pub ctl_id: u32,
2547        pub ctl_name: [c_uchar; MAX_KCTL_NAME],
2548    }
2549
2550    const CTL_IOC_MAGIC: u8 = b'N';
2551    const CTL_IOC_INFO: u8 = 3;
2552    const MAX_KCTL_NAME: usize = 96;
2553
2554    ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info);
2555
2556    /// Apple system control socket
2557    ///
2558    /// # References
2559    ///
2560    /// <https://developer.apple.com/documentation/kernel/sockaddr_ctl>
2561    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2562    #[repr(transparent)]
2563    pub struct SysControlAddr(pub(in super::super) libc::sockaddr_ctl);
2564
2565    impl private::SockaddrLikePriv for SysControlAddr {}
2566    impl SockaddrLike for SysControlAddr {
2567        unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>)
2568            -> Option<Self> where Self: Sized
2569        {
2570            if let Some(l) = len {
2571                if l != mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t {
2572                    return None;
2573                }
2574            }
2575            if (*addr).sa_family as i32 != libc::AF_SYSTEM {
2576                return None;
2577            }
2578            Some(Self(ptr::read_unaligned(addr as *const _)))
2579        }
2580    }
2581
2582    impl AsRef<libc::sockaddr_ctl> for SysControlAddr {
2583        fn as_ref(&self) -> &libc::sockaddr_ctl {
2584            &self.0
2585        }
2586    }
2587
2588    impl SysControlAddr {
2589        /// Construct a new `SysControlAddr` from its kernel unique identifier
2590        /// and unit number.
2591        pub const fn new(id: u32, unit: u32) -> SysControlAddr {
2592            let addr = libc::sockaddr_ctl {
2593                sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar,
2594                sc_family: AddressFamily::System as c_uchar,
2595                ss_sysaddr: libc::AF_SYS_CONTROL as u16,
2596                sc_id: id,
2597                sc_unit: unit,
2598                sc_reserved: [0; 5]
2599            };
2600
2601            SysControlAddr(addr)
2602        }
2603
2604        /// Construct a new `SysControlAddr` from its human readable name and
2605        /// unit number.
2606        pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> {
2607            if name.len() > MAX_KCTL_NAME {
2608                return Err(Errno::ENAMETOOLONG);
2609            }
2610
2611            let mut ctl_name = [0; MAX_KCTL_NAME];
2612            ctl_name[..name.len()].clone_from_slice(name.as_bytes());
2613            let mut info = ctl_ioc_info { ctl_id: 0, ctl_name };
2614
2615            unsafe { ctl_info(sockfd, &mut info)?; }
2616
2617            Ok(SysControlAddr::new(info.ctl_id, unit))
2618        }
2619
2620        /// Return the kernel unique identifier
2621        pub const fn id(&self) -> u32 {
2622            self.0.sc_id
2623        }
2624
2625        /// Return the kernel controller private unit number.
2626        pub const fn unit(&self) -> u32 {
2627            self.0.sc_unit
2628        }
2629    }
2630
2631    impl fmt::Display for SysControlAddr {
2632        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2633            fmt::Debug::fmt(self, f)
2634        }
2635    }
2636}
2637}
2638
2639#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))]
2640#[cfg_attr(docsrs, doc(cfg(all())))]
2641mod datalink {
2642    feature! {
2643    #![feature = "net"]
2644    use super::{fmt, mem, private, ptr, SockaddrLike};
2645
2646    /// Hardware Address
2647    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2648    #[repr(transparent)]
2649    pub struct LinkAddr(pub(in super::super) libc::sockaddr_ll);
2650
2651    impl LinkAddr {
2652        /// Physical-layer protocol
2653        pub fn protocol(&self) -> u16 {
2654            self.0.sll_protocol
2655        }
2656
2657        /// Interface number
2658        pub fn ifindex(&self) -> usize {
2659            self.0.sll_ifindex as usize
2660        }
2661
2662        /// ARP hardware type
2663        pub fn hatype(&self) -> u16 {
2664            self.0.sll_hatype
2665        }
2666
2667        /// Packet type
2668        pub fn pkttype(&self) -> u8 {
2669            self.0.sll_pkttype
2670        }
2671
2672        /// Length of MAC address
2673        pub fn halen(&self) -> usize {
2674            self.0.sll_halen as usize
2675        }
2676
2677        /// Physical-layer address (MAC)
2678        // Returns an Option just for cross-platform compatibility
2679        pub fn addr(&self) -> Option<[u8; 6]> {
2680            Some([
2681                self.0.sll_addr[0],
2682                self.0.sll_addr[1],
2683                self.0.sll_addr[2],
2684                self.0.sll_addr[3],
2685                self.0.sll_addr[4],
2686                self.0.sll_addr[5],
2687            ])
2688        }
2689    }
2690
2691    impl fmt::Display for LinkAddr {
2692        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2693            if let Some(addr) = self.addr() {
2694                write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
2695                    addr[0],
2696                    addr[1],
2697                    addr[2],
2698                    addr[3],
2699                    addr[4],
2700                    addr[5])
2701            } else {
2702                Ok(())
2703            }
2704        }
2705    }
2706    impl private::SockaddrLikePriv for LinkAddr {}
2707    impl SockaddrLike for LinkAddr {
2708        unsafe fn from_raw(addr: *const libc::sockaddr,
2709                           len: Option<libc::socklen_t>)
2710            -> Option<Self> where Self: Sized
2711        {
2712            if let Some(l) = len {
2713                if l != mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t {
2714                    return None;
2715                }
2716            }
2717            if (*addr).sa_family as i32 != libc::AF_PACKET {
2718                return None;
2719            }
2720            Some(Self(ptr::read_unaligned(addr as *const _)))
2721        }
2722    }
2723
2724    impl AsRef<libc::sockaddr_ll> for LinkAddr {
2725        fn as_ref(&self) -> &libc::sockaddr_ll {
2726            &self.0
2727        }
2728    }
2729
2730    }
2731}
2732
2733#[cfg(any(
2734    target_os = "dragonfly",
2735    target_os = "freebsd",
2736    target_os = "ios",
2737    target_os = "macos",
2738    target_os = "illumos",
2739    target_os = "netbsd",
2740    target_os = "haiku",
2741    target_os = "openbsd"
2742))]
2743#[cfg_attr(docsrs, doc(cfg(all())))]
2744mod datalink {
2745    feature! {
2746    #![feature = "net"]
2747    use super::{fmt, mem, private, ptr, SockaddrLike};
2748
2749    /// Hardware Address
2750    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2751    #[repr(transparent)]
2752    pub struct LinkAddr(pub(in super::super) libc::sockaddr_dl);
2753
2754    impl LinkAddr {
2755        /// interface index, if != 0, system given index for interface
2756        #[cfg(not(target_os = "haiku"))]
2757        pub fn ifindex(&self) -> usize {
2758            self.0.sdl_index as usize
2759        }
2760
2761        /// Datalink type
2762        #[cfg(not(target_os = "haiku"))]
2763        pub fn datalink_type(&self) -> u8 {
2764            self.0.sdl_type
2765        }
2766
2767        /// MAC address start position
2768        pub fn nlen(&self) -> usize {
2769            self.0.sdl_nlen as usize
2770        }
2771
2772        /// link level address length
2773        pub fn alen(&self) -> usize {
2774            self.0.sdl_alen as usize
2775        }
2776
2777        /// link layer selector length
2778        #[cfg(not(target_os = "haiku"))]
2779        pub fn slen(&self) -> usize {
2780            self.0.sdl_slen as usize
2781        }
2782
2783        /// if link level address length == 0,
2784        /// or `sdl_data` not be larger.
2785        pub fn is_empty(&self) -> bool {
2786            let nlen = self.nlen();
2787            let alen = self.alen();
2788            let data_len = self.0.sdl_data.len();
2789
2790            alen == 0 || nlen + alen >= data_len
2791        }
2792
2793        /// Physical-layer address (MAC)
2794        // The cast is not unnecessary on all platforms.
2795        #[allow(clippy::unnecessary_cast)]
2796        pub fn addr(&self) -> Option<[u8; 6]> {
2797            let nlen = self.nlen();
2798            let data = self.0.sdl_data;
2799
2800            if self.is_empty() {
2801                None
2802            } else {
2803                Some([
2804                    data[nlen] as u8,
2805                    data[nlen + 1] as u8,
2806                    data[nlen + 2] as u8,
2807                    data[nlen + 3] as u8,
2808                    data[nlen + 4] as u8,
2809                    data[nlen + 5] as u8,
2810                ])
2811            }
2812        }
2813    }
2814
2815    impl fmt::Display for LinkAddr {
2816        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2817            if let Some(addr) = self.addr() {
2818                write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
2819                    addr[0],
2820                    addr[1],
2821                    addr[2],
2822                    addr[3],
2823                    addr[4],
2824                    addr[5])
2825            } else {
2826                Ok(())
2827            }
2828        }
2829    }
2830    impl private::SockaddrLikePriv for LinkAddr {}
2831    impl SockaddrLike for LinkAddr {
2832        unsafe fn from_raw(addr: *const libc::sockaddr,
2833                           len: Option<libc::socklen_t>)
2834            -> Option<Self> where Self: Sized
2835        {
2836            if let Some(l) = len {
2837                if l != mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t {
2838                    return None;
2839                }
2840            }
2841            if (*addr).sa_family as i32 != libc::AF_LINK {
2842                return None;
2843            }
2844            Some(Self(ptr::read_unaligned(addr as *const _)))
2845        }
2846    }
2847
2848    impl AsRef<libc::sockaddr_dl> for LinkAddr {
2849        fn as_ref(&self) -> &libc::sockaddr_dl {
2850            &self.0
2851        }
2852    }
2853
2854    }
2855}
2856
2857#[cfg(any(target_os = "android", target_os = "linux"))]
2858#[cfg_attr(docsrs, doc(cfg(all())))]
2859pub mod vsock {
2860    use super::*;
2861    use crate::sys::socket::addr::AddressFamily;
2862    use libc::{sa_family_t, sockaddr_vm};
2863    use std::hash::{Hash, Hasher};
2864    use std::{fmt, mem};
2865
2866    /// Socket address for VMWare VSockets protocol
2867    ///
2868    /// # References
2869    ///
2870    /// [vsock(7)](https://man7.org/linux/man-pages/man7/vsock.7.html)
2871    #[derive(Copy, Clone)]
2872    #[repr(transparent)]
2873    pub struct VsockAddr(pub(in super::super) sockaddr_vm);
2874
2875    impl private::SockaddrLikePriv for VsockAddr {}
2876    impl SockaddrLike for VsockAddr {
2877        unsafe fn from_raw(
2878            addr: *const libc::sockaddr,
2879            len: Option<libc::socklen_t>,
2880        ) -> Option<Self>
2881        where
2882            Self: Sized,
2883        {
2884            if let Some(l) = len {
2885                if l != mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t {
2886                    return None;
2887                }
2888            }
2889            if (*addr).sa_family as i32 != libc::AF_VSOCK {
2890                return None;
2891            }
2892            Some(Self(ptr::read_unaligned(addr as *const _)))
2893        }
2894    }
2895
2896    impl AsRef<libc::sockaddr_vm> for VsockAddr {
2897        fn as_ref(&self) -> &libc::sockaddr_vm {
2898            &self.0
2899        }
2900    }
2901
2902    impl PartialEq for VsockAddr {
2903        fn eq(&self, other: &Self) -> bool {
2904            let (inner, other) = (self.0, other.0);
2905            (inner.svm_family, inner.svm_cid, inner.svm_port)
2906                == (other.svm_family, other.svm_cid, other.svm_port)
2907        }
2908    }
2909
2910    impl Eq for VsockAddr {}
2911
2912    impl Hash for VsockAddr {
2913        fn hash<H: Hasher>(&self, s: &mut H) {
2914            let inner = self.0;
2915            (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s);
2916        }
2917    }
2918
2919    /// VSOCK Address
2920    ///
2921    /// The address for AF_VSOCK socket is defined as a combination of a
2922    /// 32-bit Context Identifier (CID) and a 32-bit port number.
2923    impl VsockAddr {
2924        /// Construct a `VsockAddr` from its raw fields.
2925        pub fn new(cid: u32, port: u32) -> VsockAddr {
2926            let mut addr: sockaddr_vm = unsafe { mem::zeroed() };
2927            addr.svm_family = AddressFamily::Vsock as sa_family_t;
2928            addr.svm_cid = cid;
2929            addr.svm_port = port;
2930
2931            VsockAddr(addr)
2932        }
2933
2934        /// Context Identifier (CID)
2935        pub fn cid(&self) -> u32 {
2936            self.0.svm_cid
2937        }
2938
2939        /// Port number
2940        pub fn port(&self) -> u32 {
2941            self.0.svm_port
2942        }
2943    }
2944
2945    impl fmt::Display for VsockAddr {
2946        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2947            write!(f, "cid: {} port: {}", self.cid(), self.port())
2948        }
2949    }
2950
2951    impl fmt::Debug for VsockAddr {
2952        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2953            fmt::Display::fmt(self, f)
2954        }
2955    }
2956}
2957
2958#[cfg(test)]
2959mod tests {
2960    use super::*;
2961
2962    mod types {
2963        use super::*;
2964
2965        #[test]
2966        fn test_ipv4addr_to_libc() {
2967            let s = std::net::Ipv4Addr::new(1, 2, 3, 4);
2968            let l = ipv4addr_to_libc(s);
2969            assert_eq!(l.s_addr, u32::to_be(0x01020304));
2970        }
2971
2972        #[test]
2973        fn test_ipv6addr_to_libc() {
2974            let s = std::net::Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8);
2975            let l = ipv6addr_to_libc(&s);
2976            assert_eq!(
2977                l.s6_addr,
2978                [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8]
2979            );
2980        }
2981    }
2982
2983    mod link {
2984        #![allow(clippy::cast_ptr_alignment)]
2985
2986        #[cfg(any(
2987            target_os = "ios",
2988            target_os = "macos",
2989            target_os = "illumos"
2990        ))]
2991        use super::super::super::socklen_t;
2992        use super::*;
2993
2994        /// Don't panic when trying to display an empty datalink address
2995        #[cfg(any(
2996            target_os = "dragonfly",
2997            target_os = "freebsd",
2998            target_os = "ios",
2999            target_os = "macos",
3000            target_os = "netbsd",
3001            target_os = "openbsd"
3002        ))]
3003        #[test]
3004        fn test_datalink_display() {
3005            use super::super::LinkAddr;
3006            use std::mem;
3007
3008            let la = LinkAddr(libc::sockaddr_dl {
3009                sdl_len: 56,
3010                sdl_family: 18,
3011                sdl_index: 5,
3012                sdl_type: 24,
3013                sdl_nlen: 3,
3014                sdl_alen: 0,
3015                sdl_slen: 0,
3016                ..unsafe { mem::zeroed() }
3017            });
3018            format!("{}", la);
3019        }
3020
3021        #[cfg(all(
3022            any(
3023                target_os = "android",
3024                target_os = "fuchsia",
3025                target_os = "linux"
3026            ),
3027            target_endian = "little"
3028        ))]
3029        #[test]
3030        fn linux_loopback() {
3031            #[repr(align(2))]
3032            struct Raw([u8; 20]);
3033
3034            let bytes = Raw([
3035                17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0,
3036            ]);
3037            let sa = bytes.0.as_ptr() as *const libc::sockaddr;
3038            let len = None;
3039            let sock_addr =
3040                unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap();
3041            assert_eq!(sock_addr.family(), Some(AddressFamily::Packet));
3042            match sock_addr.as_link_addr() {
3043                Some(dl) => assert_eq!(dl.addr(), Some([1, 2, 3, 4, 5, 6])),
3044                None => panic!("Can't unwrap sockaddr storage"),
3045            }
3046        }
3047
3048        #[cfg(any(target_os = "ios", target_os = "macos"))]
3049        #[test]
3050        fn macos_loopback() {
3051            let bytes =
3052                [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0];
3053            let sa = bytes.as_ptr() as *const libc::sockaddr;
3054            let len = Some(bytes.len() as socklen_t);
3055            let sock_addr =
3056                unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap();
3057            assert_eq!(sock_addr.family(), Some(AddressFamily::Link));
3058            match sock_addr.as_link_addr() {
3059                Some(dl) => {
3060                    assert!(dl.addr().is_none());
3061                }
3062                None => panic!("Can't unwrap sockaddr storage"),
3063            }
3064        }
3065
3066        #[cfg(any(target_os = "ios", target_os = "macos"))]
3067        #[test]
3068        fn macos_tap() {
3069            let bytes = [
3070                20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35,
3071                76, -80,
3072            ];
3073            let ptr = bytes.as_ptr();
3074            let sa = ptr as *const libc::sockaddr;
3075            let len = Some(bytes.len() as socklen_t);
3076
3077            let sock_addr =
3078                unsafe { SockaddrStorage::from_raw(sa, len).unwrap() };
3079            assert_eq!(sock_addr.family(), Some(AddressFamily::Link));
3080            match sock_addr.as_link_addr() {
3081                Some(dl) => {
3082                    assert_eq!(dl.addr(), Some([24u8, 101, 144, 221, 76, 176]))
3083                }
3084                None => panic!("Can't unwrap sockaddr storage"),
3085            }
3086        }
3087
3088        #[cfg(target_os = "illumos")]
3089        #[test]
3090        fn illumos_tap() {
3091            let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176];
3092            let ptr = bytes.as_ptr();
3093            let sa = ptr as *const libc::sockaddr;
3094            let len = Some(bytes.len() as socklen_t);
3095            let _sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) };
3096
3097            assert!(_sock_addr.is_some());
3098
3099            let sock_addr = _sock_addr.unwrap();
3100
3101            assert_eq!(sock_addr.family().unwrap(), AddressFamily::Link);
3102
3103            assert_eq!(
3104                sock_addr.as_link_addr().unwrap().addr(),
3105                Some([24u8, 101, 144, 221, 76, 176])
3106            );
3107        }
3108
3109        #[test]
3110        fn size() {
3111            #[cfg(any(
3112                target_os = "dragonfly",
3113                target_os = "freebsd",
3114                target_os = "ios",
3115                target_os = "macos",
3116                target_os = "netbsd",
3117                target_os = "illumos",
3118                target_os = "openbsd",
3119                target_os = "haiku"
3120            ))]
3121            let l = mem::size_of::<libc::sockaddr_dl>();
3122            #[cfg(any(
3123                target_os = "android",
3124                target_os = "fuchsia",
3125                target_os = "linux"
3126            ))]
3127            let l = mem::size_of::<libc::sockaddr_ll>();
3128            assert_eq!(LinkAddr::size() as usize, l);
3129        }
3130    }
3131
3132    mod sockaddr_in {
3133        use super::*;
3134        use std::str::FromStr;
3135
3136        #[test]
3137        fn display() {
3138            let s = "127.0.0.1:8080";
3139            let addr = SockaddrIn::from_str(s).unwrap();
3140            assert_eq!(s, format!("{}", addr));
3141        }
3142
3143        #[test]
3144        fn size() {
3145            assert_eq!(
3146                mem::size_of::<libc::sockaddr_in>(),
3147                SockaddrIn::size() as usize
3148            );
3149        }
3150    }
3151
3152    mod sockaddr_in6 {
3153        use super::*;
3154        use std::str::FromStr;
3155
3156        #[test]
3157        fn display() {
3158            let s = "[1234:5678:90ab:cdef::1111:2222]:8080";
3159            let addr = SockaddrIn6::from_str(s).unwrap();
3160            assert_eq!(s, format!("{}", addr));
3161        }
3162
3163        #[test]
3164        fn size() {
3165            assert_eq!(
3166                mem::size_of::<libc::sockaddr_in6>(),
3167                SockaddrIn6::size() as usize
3168            );
3169        }
3170    }
3171
3172    mod sockaddr_storage {
3173        use super::*;
3174
3175        #[test]
3176        fn from_sockaddr_un_named() {
3177            let ua = UnixAddr::new("/var/run/mysock").unwrap();
3178            let ptr = ua.as_ptr() as *const libc::sockaddr;
3179            let ss = unsafe {
3180                SockaddrStorage::from_raw(ptr, Some(ua.len()))
3181            }.unwrap();
3182            assert_eq!(ss.len(), ua.len());
3183        }
3184
3185        #[cfg(any(target_os = "android", target_os = "linux"))]
3186        #[test]
3187        fn from_sockaddr_un_abstract_named() {
3188            let name = String::from("nix\0abstract\0test");
3189            let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap();
3190            let ptr = ua.as_ptr() as *const libc::sockaddr;
3191            let ss = unsafe {
3192                SockaddrStorage::from_raw(ptr, Some(ua.len()))
3193            }.unwrap();
3194            assert_eq!(ss.len(), ua.len());
3195        }
3196
3197        #[cfg(any(target_os = "android", target_os = "linux"))]
3198        #[test]
3199        fn from_sockaddr_un_abstract_unnamed() {
3200            let ua = UnixAddr::new_unnamed();
3201            let ptr = ua.as_ptr() as *const libc::sockaddr;
3202            let ss = unsafe {
3203                SockaddrStorage::from_raw(ptr, Some(ua.len()))
3204            }.unwrap();
3205            assert_eq!(ss.len(), ua.len());
3206        }
3207    }
3208
3209    mod unixaddr {
3210        use super::*;
3211
3212        #[cfg(any(target_os = "android", target_os = "linux"))]
3213        #[test]
3214        fn abstract_sun_path() {
3215            let name = String::from("nix\0abstract\0test");
3216            let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
3217
3218            let sun_path1 =
3219                unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] };
3220            let sun_path2 = [
3221                0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0,
3222                116, 101, 115, 116,
3223            ];
3224            assert_eq!(sun_path1, sun_path2);
3225        }
3226
3227        #[test]
3228        fn size() {
3229            assert_eq!(
3230                mem::size_of::<libc::sockaddr_un>(),
3231                UnixAddr::size() as usize
3232            );
3233        }
3234    }
3235}