2 use crate::os
::unix
::ffi
::OsStrExt
;
5 use crate::{ascii, fmt, io, iter, mem}
;
7 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
9 #[allow(non_camel_case_types)]
12 pub type socklen_t
= u32;
15 pub struct sockaddr_un
;
18 fn sun_path_offset(addr
: &libc
::sockaddr_un
) -> usize {
19 // Work with an actual instance of the type since using a null pointer is UB
20 let base
= addr
as *const _
as usize;
21 let path
= &addr
.sun_path
as *const _
as usize;
25 pub(super) unsafe fn sockaddr_un(path
: &Path
) -> io
::Result
<(libc
::sockaddr_un
, libc
::socklen_t
)> {
26 let mut addr
: libc
::sockaddr_un
= mem
::zeroed();
27 addr
.sun_family
= libc
::AF_UNIX
as libc
::sa_family_t
;
29 let bytes
= path
.as_os_str().as_bytes();
31 if bytes
.contains(&0) {
32 return Err(io
::Error
::new_const(
33 io
::ErrorKind
::InvalidInput
,
34 &"paths must not contain interior null bytes",
38 if bytes
.len() >= addr
.sun_path
.len() {
39 return Err(io
::Error
::new_const(
40 io
::ErrorKind
::InvalidInput
,
41 &"path must be shorter than SUN_LEN",
44 for (dst
, src
) in iter
::zip(&mut addr
.sun_path
, bytes
) {
45 *dst
= *src
as libc
::c_char
;
47 // null byte for pathname addresses is already there because we zeroed the
50 let mut len
= sun_path_offset(&addr
) + bytes
.len();
55 Ok((addr
, len
as libc
::socklen_t
))
58 enum AddressKind
<'a
> {
64 struct AsciiEscaped
<'a
>(&'a
[u8]);
66 impl<'a
> fmt
::Display
for AsciiEscaped
<'a
> {
67 fn fmt(&self, fmt
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
69 for byte
in self.0.iter
().cloned().flat_map(ascii
::escape_default
) {
70 write
!(fmt
, "{}", byte
as char)?
;
76 /// An address associated with a Unix socket.
81 /// use std::os::unix::net::UnixListener;
83 /// let socket = match UnixListener::bind("/tmp/sock") {
86 /// println!("Couldn't bind: {:?}", e);
90 /// let addr = socket.local_addr().expect("Couldn't get local address");
93 #[stable(feature = "unix_socket", since = "1.10.0")]
94 pub struct SocketAddr
{
95 addr
: libc
::sockaddr_un
,
100 pub(super) fn new
<F
>(f
: F
) -> io
::Result
<SocketAddr
>
102 F
: FnOnce(*mut libc
::sockaddr
, *mut libc
::socklen_t
) -> libc
::c_int
,
105 let mut addr
: libc
::sockaddr_un
= mem
::zeroed();
106 let mut len
= mem
::size_of
::<libc
::sockaddr_un
>() as libc
::socklen_t
;
107 cvt(f(&mut addr
as *mut _
as *mut _
, &mut len
))?
;
108 SocketAddr
::from_parts(addr
, len
)
112 pub(super) fn from_parts(
113 addr
: libc
::sockaddr_un
,
114 mut len
: libc
::socklen_t
,
115 ) -> io
::Result
<SocketAddr
> {
117 // When there is a datagram from unnamed unix socket
118 // linux returns zero bytes of address
119 len
= sun_path_offset(&addr
) as libc
::socklen_t
; // i.e., zero-length address
120 } else if addr
.sun_family
!= libc
::AF_UNIX
as libc
::sa_family_t
{
121 return Err(io
::Error
::new_const(
122 io
::ErrorKind
::InvalidInput
,
123 &"file descriptor did not correspond to a Unix socket",
127 Ok(SocketAddr { addr, len }
)
130 /// Returns `true` if the address is unnamed.
137 /// use std::os::unix::net::UnixListener;
139 /// fn main() -> std::io::Result<()> {
140 /// let socket = UnixListener::bind("/tmp/sock")?;
141 /// let addr = socket.local_addr().expect("Couldn't get local address");
142 /// assert_eq!(addr.is_unnamed(), false);
147 /// An unnamed address:
150 /// use std::os::unix::net::UnixDatagram;
152 /// fn main() -> std::io::Result<()> {
153 /// let socket = UnixDatagram::unbound()?;
154 /// let addr = socket.local_addr().expect("Couldn't get local address");
155 /// assert_eq!(addr.is_unnamed(), true);
159 #[stable(feature = "unix_socket", since = "1.10.0")]
160 pub fn is_unnamed(&self) -> bool
{
161 if let AddressKind
::Unnamed
= self.address() { true }
else { false }
164 /// Returns the contents of this address if it is a `pathname` address.
171 /// use std::os::unix::net::UnixListener;
172 /// use std::path::Path;
174 /// fn main() -> std::io::Result<()> {
175 /// let socket = UnixListener::bind("/tmp/sock")?;
176 /// let addr = socket.local_addr().expect("Couldn't get local address");
177 /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
182 /// Without a pathname:
185 /// use std::os::unix::net::UnixDatagram;
187 /// fn main() -> std::io::Result<()> {
188 /// let socket = UnixDatagram::unbound()?;
189 /// let addr = socket.local_addr().expect("Couldn't get local address");
190 /// assert_eq!(addr.as_pathname(), None);
194 #[stable(feature = "unix_socket", since = "1.10.0")]
195 pub fn as_pathname(&self) -> Option
<&Path
> {
196 if let AddressKind
::Pathname(path
) = self.address() { Some(path) }
else { None }
199 fn address(&self) -> AddressKind
<'_
> {
200 let len
= self.len
as usize - sun_path_offset(&self.addr
);
201 let path
= unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }
;
203 // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
205 || (cfg
!(not(any(target_os
= "linux", target_os
= "android")))
206 && self.addr
.sun_path
[0] == 0)
209 } else if self.addr
.sun_path
[0] == 0 {
210 AddressKind
::Abstract(&path
[1..len
])
212 AddressKind
::Pathname(OsStr
::from_bytes(&path
[..len
- 1]).as_ref())
217 #[stable(feature = "unix_socket", since = "1.10.0")]
218 impl fmt
::Debug
for SocketAddr
{
219 fn fmt(&self, fmt
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
220 match self.address() {
221 AddressKind
::Unnamed
=> write
!(fmt
, "(unnamed)"),
222 AddressKind
::Abstract(name
) => write
!(fmt
, "{} (abstract)", AsciiEscaped(name
)),
223 AddressKind
::Pathname(path
) => write
!(fmt
, "{:?} (pathname)", path
),