Skip to main content

uds_fork/
addr.rs

1
2#[cfg(windows)]
3use std::borrow::Cow;
4use std::
5{
6    ffi::{CStr, OsStr, c_char}, 
7    fmt::{self, Debug, Display}, 
8    hash::{Hash, Hasher}, 
9    io::{self, ErrorKind}, 
10    mem, 
11    path::Path, 
12    ptr, 
13    slice
14};
15
16#[cfg(unix)]
17use std::os::unix::{ffi::OsStrExt, net};
18
19#[cfg(unix)]
20use libc::{AF_UNIX, sa_family_t, sockaddr, sockaddr_storage, sockaddr_un, socklen_t};
21
22#[cfg(windows)]
23pub use windows_sys::Win32::Networking::WinSock::{AF_UNIX, SOCKADDR_STORAGE as sockaddr_storage, socklen_t, SOCKADDR as sockaddr, SOCKADDR_UN as sockaddr_un, ADDRESS_FAMILY as sa_family_t};
24
25/// Offset of `.sun_path` in `sockaddr_un`.
26///
27/// This is not always identical to `mem::size_of::<sa_family_t>()`,
28/// as there can be other fields before or after `.sun_family`.
29fn path_offset() -> socklen_t 
30{
31    unsafe 
32    {
33        let total_size = mem::size_of::<sockaddr_un>();
34        let name_size = mem::size_of_val(&mem::zeroed::<sockaddr_un>().sun_path);
35
36        (total_size - name_size) as socklen_t
37    }
38}
39
40const 
41fn as_u8(slice: &[c_char]) -> &[u8] 
42{
43    unsafe { &*(slice as *const[c_char] as *const[u8]) }
44}
45
46const 
47fn as_char(slice: &[u8]) -> &[c_char] 
48{
49    unsafe { &*(slice as *const[u8] as *const[c_char]) }
50}
51
52const TOO_LONG_DESC: &str = "address is too long";
53
54
55/// A unix domain socket address.
56///
57/// # Differences from `std`'s `unix::net::SocketAddr`
58///
59/// This type fully supports Linux's abstract socket addresses,
60/// and can be created by user code instead of just returned by `accept()`
61/// and similar.
62///
63/// # Examples
64///
65/// Creating an abstract address (fails if the OS doesn't support them):
66///
67#[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
68#[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
69/// use uds_fork::UnixSocketAddr;
70///
71/// let addr = UnixSocketAddr::new("@abstract").unwrap();
72/// assert!(addr.is_abstract());
73/// assert_eq!(addr.to_string(), "@abstract");
74/// ```
75#[derive(Clone, Copy)]
76pub struct UnixSocketAddr 
77{
78    addr: sockaddr_un,
79
80    /// How many bytes of addr are in use.
81    ///
82    /// Must never be greater than `size_of::<sockaddr_un>()`.
83    ///
84    /// On BSDs and macOS, `sockaddr_un` has a (non-standard) `.sun_len` field
85    /// that *could* be used to store the length instead, but doing that is
86    /// not a very good idea:  
87    /// At least [NetBSD ignores it](http://mail-index.netbsd.org/tech-net/2006/10/11/0008.html)
88    /// so we would still need to pass a correctly set `socklen_t`,
89    /// in some cases by referece.
90    /// Because it's rarely used and some BSDs aren't afraid to break stuff,
91    /// it could even dissappear in the future.  
92    /// The size this extra field is also rather minor compared to the size of
93    /// `sockaddr_un`, so the possible benefit is tiny.
94    len: socklen_t,
95}
96
97
98
99/// An enum representation of an unix socket address.
100///
101/// Useful for pattern matching an [`UnixSocketAddr`](struct.UnixSocketAddr.html)
102/// via [`UnixSocketAddr.name()`](struct.UnixSocketAddr.html#method.name).
103///
104/// It cannot be used to bind or connect a socket directly as it
105/// doesn't contain a `sockaddr_un`, but a `UnixSocketAddr` can be created
106/// from it.
107///
108/// # Examples
109///
110/// Cleaning up pathname socket files after ourselves:
111///
112/// ```no_run
113/// # use uds_fork::{UnixSocketAddr, AddrName};
114/// let addr = UnixSocketAddr::from_path("/var/run/socket.sock").unwrap();
115/// if let AddrName::Path(path) = addr.name() {
116///     let _ = std::fs::remove_file(path);
117/// }
118/// ```
119#[derive(Clone,Copy, PartialEq,Eq,Hash, Debug)]
120pub enum AddrName<'a> 
121{
122    /// Unnamed / anonymous address.
123    Unnamed,
124    /// Regular file path based address.
125    ///
126    /// Can be both relative and absolute.
127    Path(&'a Path),
128    /// Address in the abstract namespace.
129    Abstract(&'a [u8]),
130}
131
132impl<'a> From<&'a UnixSocketAddr> for AddrName<'a> 
133{
134    fn from(addr: &'a UnixSocketAddr) -> AddrName<'a> 
135    {
136        let name_len = addr.len as isize - path_offset() as isize;
137
138        if addr.is_unnamed() == true
139        {
140            AddrName::Unnamed
141        } 
142        else if addr.is_abstract() == true
143        {
144            let slice = &addr.addr.sun_path[1..name_len as usize];
145            AddrName::Abstract(as_u8(slice))
146        } 
147        else 
148        {
149            let mut slice = &addr.addr.sun_path[..name_len as usize];
150
151            // remove trailing NUL if present (and multiple NULs on OpenBSD)
152            while let Some(&0) = slice.last() 
153            {
154                slice = &slice[..slice.len()-1];
155            }
156
157            #[cfg(unix)]
158            return 
159                AddrName::Path(Path::new(OsStr::from_bytes(as_u8(slice))));
160
161            // sun_path is UTF-8
162            #[cfg(windows)]
163            {
164                //let utf8_valid = str::from_utf8(as_u8(slice)).unwrap();
165
166                return 
167                    AddrName::Path(Path::new(unsafe{ OsStr::from_encoded_bytes_unchecked(as_u8(slice)) } ))
168            }
169        }
170    }
171}
172
173pub type UnixSocketAddrRef<'a> = AddrName<'a>;
174
175impl Debug for UnixSocketAddr 
176{
177    fn fmt(&self,  fmtr: &mut fmt::Formatter) -> fmt::Result 
178    {
179        #[derive(Debug)]
180        struct Unnamed;
181        #[derive(Debug)]
182        struct Path<'a>(&'a std::path::Path);
183        #[cfg(unix)]
184        #[derive(Debug)]
185        struct Abstract<'a>(&'a OsStr);
186
187        #[cfg(windows)]
188        #[derive(Debug)]
189        struct Abstract<'a>(Cow<'a, str>);
190
191        // doesn't live long enough if created inside match
192        let mut path_type = Path("".as_ref());
193        #[cfg(unix)]
194        let mut abstract_type = Abstract(OsStr::new(""));
195
196        #[cfg(windows)]
197        let mut abstract_type = Abstract(Cow::Borrowed(""));
198
199        let variant: &dyn Debug = 
200            match self.into() 
201            {
202                UnixSocketAddrRef::Unnamed => 
203                    &Unnamed,
204                UnixSocketAddrRef::Path(path) => 
205                {
206                    path_type.0 = path;
207                    &path_type
208                },
209                UnixSocketAddrRef::Abstract(name) => 
210                {
211                    #[cfg(unix)]
212                    {
213                        abstract_type.0 = OsStr::from_bytes(name);
214                    }
215
216                    #[cfg(windows)]
217                    {
218                        let utf8_valid = String::from_utf8_lossy(name);
219                        abstract_type.0 = utf8_valid;
220                    }
221                    
222                    &abstract_type
223                },
224            };
225        fmtr.debug_tuple("UnixSocketAddr").field(variant).finish()
226    }
227}
228
229impl Display for UnixSocketAddr 
230{
231    fn fmt(&self,  fmtr: &mut fmt::Formatter) -> fmt::Result 
232    {
233        match self.into() 
234        {
235            UnixSocketAddrRef::Unnamed => 
236                fmtr.write_str("unnamed"),
237            UnixSocketAddrRef::Path(path) => 
238                write!(fmtr, "{}", path.display()), // TODO check that display() doesn't print \n as-is
239            #[cfg(unix)]
240            UnixSocketAddrRef::Abstract(name) => 
241                {
242                    write!(fmtr, "@{}", OsStr::from_bytes(name).to_string_lossy()) // FIXME escape to sane characters
243                }
244            #[cfg(windows)]
245            UnixSocketAddrRef::Abstract(name) =>     
246                {
247                    let utf8_valid = String::from_utf8_lossy(name);
248
249                    write!(fmtr, "@{}", utf8_valid) // FIXME escape to sane characters
250                }
251        }
252    }
253}
254
255impl UnixSocketAddr 
256{
257    /// Allows creating abstract, path or unspecified address based on an
258    /// user-supplied string.
259    ///
260    /// A leading `'@'` or `'\0'` signifies an abstract address,
261    /// an empty slice is taken as the unnamed address, and anything else is a
262    /// path address.  
263    /// If a relative path address starts with `@`, escape it by prepending
264    /// `"./"`.
265    /// To avoid surprises, abstract addresses will be detected regargsless of
266    /// wheither the OS supports them, and result in an error if it doesn't.
267    ///
268    /// # Errors
269    ///
270    /// * A path or abstract address is too long.
271    /// * A path address contains `'\0'`.
272    /// * An abstract name was supplied on an OS that doesn't support them.
273    ///
274    /// # Examples
275    ///
276    /// Abstract address:
277    ///
278    /// ```
279    /// # use uds_fork::UnixSocketAddr;
280    /// if UnixSocketAddr::has_abstract_addresses() {
281    ///     assert!(UnixSocketAddr::new("@abstract").unwrap().is_abstract());
282    ///     assert!(UnixSocketAddr::new("\0abstract").unwrap().is_abstract());
283    /// } else {
284    ///     assert!(UnixSocketAddr::new("@abstract").is_err());
285    ///     assert!(UnixSocketAddr::new("\0abstract").is_err());
286    /// }
287    /// ```
288    ///
289    /// Escaped path address:
290    ///
291    /// ```
292    /// # use uds_fork::UnixSocketAddr;
293    /// assert!(UnixSocketAddr::new("./@path").unwrap().is_relative_path());
294    /// ```
295    ///
296    /// Unnamed address:
297    ///
298    /// ```
299    /// # use uds_fork::UnixSocketAddr;
300    /// assert!(UnixSocketAddr::new("").unwrap().is_unnamed());
301    /// ```
302    pub 
303    fn new<A: AsRef<[u8]>+?Sized>(addr: &A) -> Result<Self, io::Error> 
304    {
305        fn parse(addr: &[u8]) -> Result<UnixSocketAddr, io::Error> 
306        {
307            match addr.first() 
308            {
309                Some(&b'@') | Some(&b'\0') => 
310                    UnixSocketAddr::from_abstract(&addr[1..]),
311                #[cfg(unix)]
312                Some(_) => 
313                    UnixSocketAddr::from_path(Path::new(OsStr::from_bytes(addr))),
314                #[cfg(windows)]
315                Some(_) => 
316                {
317                    let utf8_valid = 
318                        str::from_utf8(addr)
319                            .map_err(|e| io::Error::new(ErrorKind::InvalidInput, e)
320                        )?;
321
322                    UnixSocketAddr::from_path(Path::new(utf8_valid))
323                },
324                None => 
325                    Ok(UnixSocketAddr::new_unspecified()),
326            }
327        }
328
329        return parse(addr.as_ref());
330    }
331
332    #[cfg(windows)]
333    /// Allows creating abstract, path or unspecified address based on an
334    /// user-supplied string for Windows UTF-16 path.
335    ///
336    /// A leading `'@'` or `'\0'` signifies an abstract address,
337    /// an empty slice is taken as the unnamed address, and anything else is a
338    /// path address.  
339    /// If a relative path address starts with `@`, escape it by prepending
340    /// `"./"`.
341    /// To avoid surprises, abstract addresses will be detected regargsless of
342    /// wheither the OS supports them, and result in an error if it doesn't.
343    ///
344    /// # Errors
345    ///
346    /// * A path or abstract address is too long.
347    /// * A path address contains `'\0'`.
348    /// * An abstract name was supplied on an OS that doesn't support them.
349    pub 
350    fn new_windows<A: AsRef<[u16]>+?Sized>(addr_v: &A) -> Result<Self, io::Error> 
351    {
352        use std::{ffi::OsString, os::windows::ffi::OsStringExt};
353        let addr = addr_v.as_ref();
354       
355        let first = 
356            if addr.len() > 0
357            {
358                Some(OsString::from_wide(&addr[0..1]))
359            }
360            else
361            {
362                None
363            };
364
365        match first.as_ref().map(|v| v.as_encoded_bytes())
366        {
367            Some(b"@") | Some(b"\0") => 
368            {
369                let osstr = OsString::from_wide(addr);
370
371                UnixSocketAddr::from_abstract(&osstr.as_encoded_bytes()[1..])
372            },
373            Some(_) => 
374            {
375                
376                let osstr = OsString::from_wide(addr);
377
378                UnixSocketAddr::from_path(Path::new( &osstr ))
379            },
380            None => 
381                Ok(UnixSocketAddr::new_unspecified()),
382        }
383    }
384
385    /// Creates an unnamed address, which on Linux can be used for auto-bind.
386    ///
387    /// Binding a socket to the unnamed address is different from not binding
388    /// at all:
389    ///
390    /// On Linux doing so binds the socket to a random abstract address
391    /// determined by the OS.
392    ///
393    /// # Examples
394    ///
395    #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
396    #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```ignore")]
397    /// # use uds_fork::{UnixSocketAddr, UnixDatagramExt};
398    /// # use std::os::unix::net::UnixDatagram;
399    /// let addr = UnixSocketAddr::new_unspecified();
400    /// assert!(addr.is_unnamed());
401    /// let socket = UnixDatagram::unbound().unwrap();
402    /// socket.bind_to_unix_addr(&addr).unwrap();
403    /// assert!(socket.local_unix_addr().unwrap().is_abstract());
404    /// ```
405    pub 
406    fn new_unspecified() -> Self 
407    {
408        let mut addr: sockaddr_un = unsafe { mem::zeroed() };
409        addr.sun_family = AF_UNIX as sa_family_t;
410
411        return 
412            UnixSocketAddr 
413            {
414                len: path_offset(),
415                addr,
416            };
417    }
418
419    /// Returns the maximum size of pathname addresses supported by `UnixSocketAddr`.
420    ///
421    /// Is the size of the underlying `sun_path` field, minus 1 if the OS
422    /// is known to either require a trailing NUL (`'\0'`) byte,
423    /// or supports longer paths that go past the end of `sun_path`.
424    ///
425    /// These OSes are:
426    ///
427    /// * OpenBSD: Enforces that `sun_path`` is NUL-terminated.
428    /// * macOS / iOS / anything else Apple: I haven't found a manpage,
429    ///   but it supports longer paths.
430    /// * Illumos: [The manpage](https://illumos.org/man/3SOCKET/sockaddr_un)
431    ///   says it must be NUL-terminated (and that it cannot be longer),
432    ///   but when I tested on an older version, neither of these constraints seem to be the case.
433    /// * Solaris: Assumed to be identical to Illumos.
434    ///
435    /// OSes that have been tested that they allow using the full `sun_path`
436    /// without NUL and no longer paths, and whose manpages don't state the opposite:
437    ///
438    /// * [Linux](https://www.man7.org/linux/man-pages/man7/unix.7.html)
439    /// * [FreeBSD](https://man.freebsd.org/cgi/man.cgi?query=unix&sektion=4)
440    /// * [NetBSD](https://man.netbsd.org/unix.4)
441    /// * [Dragonfly BSD](https://man.dragonflybsd.org/?command=unix&section=4)
442    pub 
443    fn max_path_len() -> usize 
444    {
445        let always_nul_terminate = 
446            cfg!(any(
447                target_os="openbsd",
448                target_vendor="apple",
449                target_os="illumos",
450                target_os="solaris",
451            ));
452
453        return
454            if always_nul_terminate == true 
455            {
456                mem::size_of_val(&Self::new_unspecified().addr.sun_path) - 1
457            } 
458            else 
459            {
460                mem::size_of_val(&Self::new_unspecified().addr.sun_path)
461            };
462    }
463
464    /// Creates a pathname unix socket address.
465    ///
466    /// # Errors
467    ///
468    /// This function will return an error if the path is too long for the
469    /// underlying `sockaddr_un` type, or contains NUL (`'\0'`) bytes.
470    pub 
471    fn from_path<P: AsRef<Path>+?Sized>(path: &P) -> Result<Self, io::Error> 
472    {
473        fn from_path_inner(path: &[u8]) -> Result<UnixSocketAddr, io::Error> 
474        {
475            let mut addr = UnixSocketAddr::new_unspecified();
476            let capacity = UnixSocketAddr::max_path_len();
477
478            if path.is_empty() == true 
479            {
480                return Err(io::Error::new(ErrorKind::NotFound, "path is empty"));
481            } 
482            else if path.len() > capacity 
483            {
484                let message = "path is too long for an unix socket address";
485
486                return Err(io::Error::new(ErrorKind::InvalidInput, message));
487            } 
488            else if path.iter().any(|&b| b == b'\0' ) == true
489            {
490                return Err(io::Error::new(ErrorKind::InvalidInput, "path cannot contain nul bytes"));
491            } 
492            else 
493            {
494                addr.addr.sun_path[..path.len()].copy_from_slice(as_char(path));
495                addr.len = path_offset() + path.len() as socklen_t;
496                
497                if path.len() < capacity 
498                {
499                    addr.len += 1; // for increased portability
500                }
501                
502                return Ok(addr);
503            }
504        }
505
506        #[cfg(unix)]
507        return from_path_inner(path.as_ref().as_os_str().as_bytes());
508
509        #[cfg(windows)]
510        return from_path_inner(path.as_ref().as_os_str().as_encoded_bytes());
511    }
512
513    /// Returns maximum size of abstract addesses supported by `UnixSocketAddr`.
514    ///
515    /// Is the size of the underlying `sun_path` field minus 1 for the
516    /// leading `'\0'` byte.
517    ///
518    /// This value is also returned on operating systems that doesn't support
519    /// abstract addresses.
520    pub 
521    fn max_abstract_len() -> usize 
522    {
523        mem::size_of_val(&Self::new_unspecified().addr.sun_path) - 1
524    }
525
526    /// Returns whether the operating system is known to support
527    /// abstract unix domain socket addresses.
528    ///
529    /// Is `true` for Linux & Android, and `false` for all other OSes.
530    pub const 
531    fn has_abstract_addresses() -> bool 
532    {
533        cfg!(any(target_os="linux", target_os="android"))
534    }
535
536    /// Creates an abstract unix domain socket address.
537    ///
538    /// Abstract addresses use a namespace separate from the file system,
539    /// that doesn't have directories (ie. is flat) or permissions.
540    /// The advandage of it is that the address disappear when the socket bound
541    /// to it is closed, which frees one from dealing with removing it when
542    /// shutting down cleanly.
543    ///
544    /// They are a Linux-only feature though, and this function will fail
545    /// if abstract addresses are not supported.
546    ///
547    /// # Errors
548    ///
549    /// This function will return an error if the name is too long.
550    /// Call [`max_abstract_len()`](#method.max_abstract_len)
551    /// get the limit.
552    ///
553    /// It will also fail on operating systems that don't support abstract
554    /// addresses. (ie. anything other than Linux and Android)
555    pub 
556    fn from_abstract<N: AsRef<[u8]>+?Sized>(name: &N) -> Result<Self, io::Error> 
557    {
558        fn from_abstract_inner(name: &[u8]) -> Result<UnixSocketAddr, io::Error> 
559        {
560            let mut addr = UnixSocketAddr::new_unspecified();
561
562            if UnixSocketAddr::has_abstract_addresses() == false
563            {
564                return 
565                    Err(
566                        io::Error::new(
567                            ErrorKind::AddrNotAvailable, 
568                            format!( "abstract unix domain socket addresses are not available on {}",
569                                std::env::consts::OS)
570                        )
571                    );
572            } 
573            else if name.len() > UnixSocketAddr::max_abstract_len() 
574            {
575                return 
576                    Err(io::Error::new(ErrorKind::InvalidInput, "abstract name is too long"));
577            } 
578            else 
579            {
580                addr.addr.sun_path[1..1+name.len()].copy_from_slice(as_char(name));
581                addr.len = path_offset() + 1 + name.len() as socklen_t;
582                return Ok(addr);
583            }
584        }
585
586        return from_abstract_inner(name.as_ref());
587    }
588
589    /// Tries to convert a `std::os::unix::net::SocketAddr` into an `UnixSocketAddr`.
590    ///
591    /// This can fail (produce `None`) on Linux and Android
592    /// if the `std` `SocketAddr` represents an abstract address,
593    /// as it provides no method for viewing abstract addresses.
594    /// (other than parsing its `Debug` output, anyway.)
595    #[cfg(unix)]
596    pub 
597    fn from_std(addr: net::SocketAddr) -> Option<Self> 
598    {
599        return 
600            if let Some(path) = addr.as_pathname() 
601            {
602                Some(Self::from_path(path).expect("pathname addr cannot be converted"))
603            } 
604            else if addr.is_unnamed() 
605            {
606                Some(Self::new_unspecified())
607            } 
608            else 
609            {
610                None
611            };
612    }
613
614    /// Returns unnamed addres for empty strings, and path addresses otherwise.
615    ///
616    /// # Errors
617    ///
618    /// Returns ENAMETOOLONG if path (without the trailing `'\0'`) is too long
619    /// for `sockaddr_un.sun_path`.
620    pub 
621    fn from_c_str(path: &CStr) -> Result<Self, io::Error> 
622    {
623        let path = path.to_bytes();
624        let mut addr = Self::new_unspecified();
625
626        if path.is_empty() 
627        {
628            return Ok(addr);
629        } 
630        else if path.len() > mem::size_of_val(&addr.addr.sun_path) 
631        {
632            let message = "path is too long for unix socket address";
633
634            return Err(io::Error::new(ErrorKind::InvalidInput, message));
635        } 
636        else 
637        {
638            addr.addr.sun_path[..path.len()].copy_from_slice(as_char(path));
639            addr.len = path_offset() + path.len() as socklen_t;
640
641            if path.len() < mem::size_of_val(&addr.addr.sun_path) 
642            {
643                addr.len += 1;
644            }
645
646            return Ok(addr);
647        }
648    }
649
650    /// Checks whether the address is unnamed.
651    #[inline]
652    pub 
653    fn is_unnamed(&self) -> bool 
654    {
655        if Self::has_abstract_addresses() 
656        {
657            return self.len <= path_offset();
658        } 
659        else 
660        {
661            // MacOS can apparently return non-empty addresses but with
662            // all-zeroes path for unnamed addresses.
663            return self.len <= path_offset()  ||  self.addr.sun_path[0] as u8 == b'\0';
664        }
665    }
666
667    /// Checks whether the address is a name in the abstract namespace.
668    ///
669    /// Always returns `false` on operating systems that don't support abstract
670    /// addresses.
671    pub 
672    fn is_abstract(&self) -> bool 
673    {
674        if Self::has_abstract_addresses() == true
675        {
676            return self.len > path_offset()  &&  self.addr.sun_path[0] as u8 == b'\0';
677        } 
678        else 
679        {
680            return false;
681        }
682    }
683
684    /// Checks whether the address is a path that begins with '/'.
685    #[cfg(unix)]
686    #[inline]
687    pub 
688    fn is_absolute_path(&self) -> bool 
689    {
690        self.len > path_offset()  &&  self.addr.sun_path[0] as u8 == b'/'
691    }
692
693    /// Checks whether the address is a path that begins with '/' or "C:\".
694    #[cfg(windows)]
695    #[inline]
696    pub 
697    fn is_absolute_path(&self) -> bool 
698    {
699        self.len > path_offset()  &&  
700            (
701                self.addr.sun_path[0] as u8 == b'/' || 
702                (self.addr.sun_path[0] as u8 as char).is_ascii_alphabetic() == true
703            )
704    }
705
706    /// Checks whether the address is a path that doesn't begin with '/'.
707    #[inline]
708    pub 
709    fn is_relative_path(&self) -> bool 
710    {
711        self.len > path_offset()
712            &&  self.addr.sun_path[0] as u8 != b'\0'
713            &&  self.addr.sun_path[0] as u8 != b'/'
714    }
715    /// Checks whether the address is a path.
716    #[inline]
717    pub 
718    fn is_path(&self) -> bool 
719    {
720        self.len > path_offset()  &&  self.addr.sun_path[0] as u8 != b'\0'
721    }
722
723    /// Returns a view of the address that can be pattern matched
724    /// to the differnt types of addresses.
725    ///
726    /// # Examples
727    ///
728    /// ```
729    /// use uds_fork::{UnixSocketAddr, AddrName};
730    /// use std::path::Path;
731    ///
732    /// assert_eq!(
733    ///     UnixSocketAddr::new_unspecified().name(),
734    ///     AddrName::Unnamed
735    /// );
736    /// assert_eq!(
737    ///     UnixSocketAddr::from_path("/var/run/socket.sock").unwrap().name(),
738    ///     AddrName::Path(Path::new("/var/run/socket.sock"))
739    /// );
740    /// if UnixSocketAddr::has_abstract_addresses() {
741    ///     assert_eq!(
742    ///         UnixSocketAddr::from_abstract("tcartsba").unwrap().name(),
743    ///         AddrName::Abstract(b"tcartsba")
744    ///     );
745    /// }
746    /// ```
747    pub 
748    fn name(&self) -> AddrName<'_>
749    {
750        AddrName::from(self)
751    }
752
753    /// Returns the path of a path-based address.
754    pub 
755    fn as_pathname(&self) -> Option<&Path> 
756    {
757        let UnixSocketAddrRef::Path(path) = UnixSocketAddrRef::from(self)
758        else { return None };
759
760        return Some(path);
761    }
762
763    /// Returns the name of an address which is in the abstract namespace.
764    pub 
765    fn as_abstract(&self) -> Option<&[u8]> 
766    {
767        let UnixSocketAddrRef::Abstract(name) = UnixSocketAddrRef::from(self) 
768        else {return None};
769
770        return Some(name);
771    }
772
773    /// Returns a view that can be pattern matched to the differnt types of
774    /// addresses.
775    ///
776    /// # Examples
777    ///
778    #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
779    #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```ignore")]
780    /// use uds_fork::{UnixDatagramExt, UnixSocketAddr, UnixSocketAddrRef};
781    /// use std::os::unix::net::UnixDatagram;
782    /// use std::path::Path;
783    ///
784    /// # let _ = std::fs::remove_file("/tmp/dgram.socket");
785    /// let receiver = UnixDatagram::bind("/tmp/dgram.socket").expect("create datagram socket");
786    /// assert_eq!(
787    ///     receiver.local_unix_addr().unwrap().as_ref(),
788    ///     UnixSocketAddrRef::Path(Path::new("/tmp/dgram.socket"))
789    /// );
790    ///
791    /// let sender = UnixDatagram::unbound().expect("create unbound datagram socket");
792    /// sender.send_to(b"I can't hear you", "/tmp/dgram.socket").expect("send");
793    ///
794    /// let mut buf = [0; 100];
795    /// let (len, addr) = receiver.recv_from_unix_addr(&mut buf).unwrap();
796    /// assert_eq!(addr.as_ref(), UnixSocketAddrRef::Unnamed);
797    /// # std::fs::remove_file("/tmp/dgram.socket").expect("clean up socket file");
798    /// ```
799    pub 
800    fn as_ref(&self) -> UnixSocketAddrRef<'_>
801    {
802        UnixSocketAddrRef::from(self)
803    }
804
805    /// Creates an address from a slice of bytes to place in `sun_path`.
806    ///
807    /// This is a low-level but simple interface for creating addresses by
808    /// other unix socket wrappers without exposing any libc types.  
809    /// The meaning of a slice can vary between operating systems.
810    ///
811    /// `addr` should point to thes start of the "path" part of a socket
812    /// address, with length being the number of valid bytes of the path.
813    /// (Trailing NULs are not stripped by this function.)
814    ///
815    /// # Errors
816    ///
817    /// If the slice is longer than `sun_path`, an error of kind `Other` is
818    /// returned. No other validation of the bytes is performed.
819    ///
820    /// # Examples
821    ///
822    /// A normal path-based address
823    ///
824    /// ```
825    /// # use std::path::Path;
826    /// # use uds_fork::UnixSocketAddr;
827    /// let addr = UnixSocketAddr::from_raw_bytes(b"/tmp/a.sock\0").unwrap();
828    /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/a.sock")));
829    /// assert_eq!(addr.as_raw_bytes(), b"/tmp/a.sock\0");
830    /// ```
831    ///
832    /// On Linux:
833    ///
834    #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
835    #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
836    /// # use uds_fork::UnixSocketAddr;
837    /// let addr = UnixSocketAddr::from_raw_bytes(b"\0a").unwrap();
838    /// assert_eq!(addr.as_abstract(), Some(&b"a"[..]));
839    /// assert_eq!(addr.as_raw_bytes(), b"\0a");
840    /// ```
841    ///
842    /// Elsewhere:
843    ///
844    #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```")]
845    #[cfg_attr(any(target_os="linux", target_os="android"), doc="```no_run")]
846    /// # use uds_fork::UnixSocketAddr;
847    /// let addr = UnixSocketAddr::from_raw_bytes(b"\0a").unwrap();
848    /// assert!(addr.is_unnamed());
849    /// assert_eq!(addr.as_raw_bytes().len(), 2);
850    /// ```
851    ///
852    /// A portable unnamed address:
853    ///
854    /// ```
855    /// # use uds_fork::UnixSocketAddr;
856    /// let addr = UnixSocketAddr::from_raw_bytes(&[]).expect("not too long");
857    /// assert!(addr.is_unnamed());
858    /// assert!(addr.as_raw_bytes().is_empty());
859    /// ```
860    pub 
861    fn from_raw_bytes(addr: &[u8]) -> Result<Self, io::Error> 
862    {
863        if addr.len() <= Self::max_path_len() 
864        {
865            let name = addr;
866            let mut addr = Self::default();
867            addr.addr.sun_path[..name.len()].copy_from_slice(as_char(name));
868            addr.len = path_offset() + name.len() as socklen_t;
869            
870            return Ok(addr);
871        } 
872        else 
873        {
874            return Err(io::Error::new(ErrorKind::InvalidInput, TOO_LONG_DESC));
875        }
876    }
877    /// Returns a low-level view of the address without using any libc types.
878    ///
879    /// The returned slice points to the start of `sun_addr` of the contained
880    /// `sockaddr_un`, and the length is the number of bytes of `sun_addr`
881    /// that were filled out by the OS. Any trailing NUL(s) will be preserved.
882    ///
883    /// # Examples
884    ///
885    /// A normal path-based address:
886    ///
887    #[cfg_attr(any(target_vendor="apple", target_os="openbsd"), doc="```")]
888    #[cfg_attr(not(any(target_vendor="apple", target_os="openbsd")), doc="```ignore")]
889    /// # use std::path::Path;
890    /// # use std::os::unix::net::UnixDatagram;
891    /// # use uds_fork::{UnixSocketAddr, UnixDatagramExt};
892    /// let pathname = "/tmp/a_file";
893    /// let socket = UnixDatagram::bind(pathname).expect("create datagram socket");
894    /// # let _ = std::fs::remove_file(pathname);
895    /// let addr = socket.local_unix_addr().expect("get its address");
896    /// assert!(addr.as_raw_bytes().starts_with(pathname.as_bytes()));
897    /// assert!(addr.as_raw_bytes()[pathname.len()..].iter().all(|&b| b == b'\0' ));
898    /// assert_eq!(addr.as_pathname(), Some(Path::new(pathname)));
899    /// ```
900    ///
901    /// Abstract address:
902    ///
903    #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
904    #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
905    /// # use uds_fork::UnixSocketAddr;
906    /// let addr = UnixSocketAddr::new("@someone@").unwrap();
907    /// assert_eq!(addr.as_raw_bytes(), b"\0someone@");
908    /// ```
909    ///
910    /// Unnamed address on macOS, OpenBSD and maybe others:
911    ///
912    #[cfg_attr(any(target_vendor="apple", target_os="openbsd"), doc="```")]
913    #[cfg_attr(not(any(target_vendor="apple", target_os="openbsd")), doc="```ignore")]
914    /// # use std::os::unix::net::UnixDatagram;
915    /// # use uds_fork::{UnixSocketAddr, UnixDatagramExt};
916    /// let socket = UnixDatagram::unbound().expect("create datagram socket");
917    /// let addr = socket.local_unix_addr().expect("get its unbound address");
918    /// let bytes = addr.as_raw_bytes();
919    /// assert!(bytes.len() > 0);
920    /// assert!(bytes.iter().all(|&b| b == b'\0' ));
921    /// assert!(addr.is_unnamed());
922    /// ```
923    pub 
924    fn as_raw_bytes(&self) -> &[u8] 
925    {
926        as_u8(&self.addr.sun_path[..(self.len-path_offset()) as usize])
927    }
928
929    /// Prepares a `struct sockaddr*` and `socklen_t*` for passing to FFI
930    /// (such as `getsockname()`, `getpeername()`, or `accept()`),
931    /// and validate and normalize the produced address afterwards.
932    ///
933    /// Validation:
934    ///
935    /// * Check that the address family is `AF_UNIX`.
936    /// * Check that the address wasn't truncated (the `socklen_t` is too big).
937    ///
938    /// Normalization:
939    ///
940    /// * Ensure path addresses have a trailing NUL byte if there is space.
941    pub 
942    fn new_from_ffi<R, F>(call: F) -> Result<(R, Self), io::Error>
943    where 
944        F: FnOnce(&mut sockaddr, &mut socklen_t) -> Result<R, io::Error> 
945    {
946        let mut addr = Self::new_unspecified();
947        let capacity = mem::size_of_val(&addr.addr) as socklen_t;
948        addr.len = capacity;
949
950        unsafe 
951        {
952            let (addr_ptr, addr_len_ptr) = addr.as_raw_mut_general();
953            let ret = call(addr_ptr, addr_len_ptr)?;
954
955            if addr.addr.sun_family != AF_UNIX as sa_family_t 
956            {
957                return Err(
958                    io::Error::new(
959                        ErrorKind::InvalidData,
960                        "file descriptor did not correspond to a Unix socket" // identical to std's
961                    )
962                );
963            }
964
965            if addr.is_abstract() == true
966            {
967                if addr.len > capacity 
968                {
969                    return Err(
970                        io::Error::new(ErrorKind::InvalidData, "abstract name was too long")
971                    );
972                }
973            } 
974            else if addr.is_path() == true 
975            {
976                if addr.len > capacity+1 
977                {
978                    return Err(io::Error::new(ErrorKind::InvalidData, "path was too long"));
979                    // accept lengths one too big; assume the truncated byte was NUL
980                } 
981                else 
982                {
983                    // normalize addr.len to include terminating NUL byte if possible
984                    // and not be greater than capacity
985                    if addr.len >= capacity 
986                    {
987                        addr.len = capacity;
988                    } 
989                    else if addr.addr.sun_path[(addr.len-1-path_offset()) as usize] != 0 
990                    {
991                        addr.len += 1;
992                        addr.addr.sun_path[(addr.len-1-path_offset()) as usize] = 0;
993                    }
994                }
995            }
996            
997            return Ok((ret, addr));
998        }
999    }
1000
1001    pub unsafe 
1002    fn from_ref(addr: &sockaddr,  len: socklen_t) -> Result<Self, io::Error> 
1003    {
1004        let mut copy = Self::new_unspecified();
1005
1006        if len < path_offset() 
1007        {
1008            return Err(io::Error::new(ErrorKind::InvalidInput, "address length is too short"));
1009        } 
1010        else if len > mem::size_of::<sockaddr_un>() as socklen_t 
1011        {
1012            return Err(io::Error::new(ErrorKind::InvalidInput, TOO_LONG_DESC));
1013        } 
1014        else if addr.sa_family != AF_UNIX as sa_family_t 
1015        {
1016            return Err(io::Error::new(ErrorKind::InvalidData, "not an unix socket address"));
1017        } 
1018        else 
1019        {
1020            let addr = addr as *const sockaddr  as *const sockaddr_un;
1021            let sun_path_ptr = unsafe { (&*addr).sun_path.as_ptr() };
1022            let path_len = (len - path_offset()) as usize;
1023            let sun_path = unsafe { slice::from_raw_parts(sun_path_ptr, path_len) };
1024            
1025            copy.addr.sun_path[..path_len].copy_from_slice(sun_path);
1026            copy.len = len;
1027            
1028            return Ok(copy);
1029        }
1030    }
1031
1032    /// Creates an `UnixSocketAddr` from a pointer to a generic [libc::sockaddr_storage] and
1033    /// a length.
1034    ///
1035    /// # Safety
1036    ///
1037    /// * `len` must not be greater than the size of the memory `addr` points to.
1038    /// * `addr` must point to valid memory if `len` is greater than zero, or be NULL.
1039    pub unsafe 
1040    fn from_sockaddr_storage(addr: &sockaddr_storage,  len: socklen_t) -> Result<Self, io::Error> 
1041    {
1042        let mut copy = Self::new_unspecified();
1043
1044        if len < path_offset() 
1045        {
1046            return Err(io::Error::new(ErrorKind::InvalidInput, "address length is too short"));
1047        } 
1048        else if len > mem::size_of::<sockaddr_un>() as socklen_t 
1049        {
1050            return Err(io::Error::new(ErrorKind::InvalidInput, TOO_LONG_DESC));
1051        } 
1052        else if addr.ss_family != AF_UNIX as sa_family_t 
1053        {
1054            return Err(io::Error::new(ErrorKind::InvalidData, "not an unix socket address"));
1055        } 
1056        else 
1057        {
1058            let addr = addr as *const sockaddr_storage as *const sockaddr_un;
1059            let sun_path_ptr = unsafe { (&*addr).sun_path.as_ptr() };
1060            let path_len = (len - path_offset()) as usize;
1061            let sun_path = unsafe { slice::from_raw_parts(sun_path_ptr, path_len) };
1062            
1063            copy.addr.sun_path[..path_len].copy_from_slice(sun_path);
1064            copy.len = len;
1065            
1066            return Ok(copy);
1067        }
1068    }
1069
1070    /// Creates an `UnixSocketAddr` from a pointer to a generic `sockaddr` and
1071    /// a length.
1072    ///
1073    /// # Safety
1074    ///
1075    /// * `len` must not be greater than the size of the memory `addr` points to.
1076    /// * `addr` must point to valid memory if `len` is greater than zero, or be NULL.
1077    pub unsafe 
1078    fn from_raw(addr: *const sockaddr,  len: socklen_t) -> Result<Self, io::Error> 
1079    {
1080        let mut copy = Self::new_unspecified();
1081
1082        if addr.is_null() == true && len == 0 
1083        {
1084            return Ok(Self::new_unspecified());
1085        } 
1086        else if addr.is_null() == true
1087        {
1088            return Err(io::Error::new(ErrorKind::InvalidInput, "addr is NULL"));
1089        } 
1090        else if len < path_offset() 
1091        {
1092            return Err(io::Error::new(ErrorKind::InvalidInput, "address length is too short"));
1093        } 
1094        else if len > mem::size_of::<sockaddr_un>() as socklen_t 
1095        {
1096            return Err(io::Error::new(ErrorKind::InvalidInput, TOO_LONG_DESC));
1097        } 
1098        else if unsafe { (&*addr).sa_family } != AF_UNIX as sa_family_t 
1099        {
1100            return Err(io::Error::new(ErrorKind::InvalidData, "not an unix socket address"));
1101        } 
1102        else 
1103        {
1104            let addr = addr as *const sockaddr_un;
1105            let sun_path_ptr = unsafe { (&*addr).sun_path.as_ptr() };
1106            let path_len = (len - path_offset()) as usize;
1107            let sun_path = unsafe { slice::from_raw_parts(sun_path_ptr, path_len) };
1108            
1109            copy.addr.sun_path[..path_len].copy_from_slice(sun_path);
1110            copy.len = len;
1111            
1112            return Ok(copy);
1113        }
1114    }
1115
1116    /// Creates an `UnixSocketAddr` without any validation.
1117    ///
1118    /// # Safety
1119    ///
1120    /// * `len` must be `<= size_of::<sockaddr_un>()`.
1121    /// * `addr.sun_family` should be `AF_UNIX` or strange things might happen.
1122    /// * `addr.sun_len`, if it exists, should be zero (but is probably ignored).
1123    pub unsafe 
1124    fn from_raw_unchecked(addr: sockaddr_un,  len: socklen_t) -> Self 
1125    {
1126        Self{addr, len}
1127    }
1128
1129    /// Splits the address into its inner, raw parts.
1130    pub 
1131    fn into_raw(self) -> (sockaddr_un, socklen_t) 
1132    {
1133        (self.addr, self.len)
1134    }
1135
1136    /// Returns a general `sockaddr` reference to the address and its length.
1137    ///
1138    /// Useful for passing to `bind()`, `connect()`, `sendto()` or other FFI.
1139    ///
1140    /// Pathname addresses are not guaranteed to be NUL-terminated on most OSes:
1141    /// Most paths will be NUL-terminated, but paths that just fit within `sockaddr_un.sun_len`
1142    /// (iow their length is equal to `addr.sun_len[..].len()`) will not have one.  
1143    /// Therefore do not call `SUN_LEN()` on unknown addresses.  
1144    /// See [`max_path_len()`](#tymethod.max_path_len) for which OSes this affects.
1145    pub 
1146    fn as_raw_general(&self) -> (&sockaddr, socklen_t) 
1147    {
1148        // SAFETY: sockaddr is a super-type of sockaddr_un.
1149        (unsafe { &*(&self.addr as *const sockaddr_un as *const sockaddr) }, self.len)
1150    }
1151
1152    /// Returns a reference to the inner `struct sockaddr_un`, and length.
1153    ///
1154    /// Pathname addresses are not guaranteed to be NUL-terminated on most OSes:
1155    /// Most paths will be NUL-terminated, but paths that just fit within `sockaddr_un.sun_len`
1156    /// (iow their length is equal to `addr.sun_len[..].len()`) will not have one.  
1157    /// Therefore do not call `SUN_LEN()` on unknown addresses.  
1158    /// See [`max_path_len()`](#tymethod.max_path_len) for which OSes this affects.
1159    pub 
1160    fn as_raw(&self) -> (&sockaddr_un, socklen_t) 
1161    {
1162        (&self.addr, self.len)
1163    }
1164
1165    /// Returns mutable references to a general `struct sockaddr` and `socklen_t`.
1166    ///
1167    /// If passing to `getpeername()`, `accept()` or similar, remember to set
1168    /// the length to the capacity,
1169    /// and consider using [`new_from_ffi()`](#method.new_from_ffi) instead.
1170    ///
1171    /// Pathname addresses are not guaranteed to be NUL-terminated on most OSes:
1172    /// Most paths will be NUL-terminated, but paths that just fit within `sockaddr_un.sun_len`
1173    /// (iow their length is equal to `addr.sun_len[..].len()`) will not have one.  
1174    /// Therefore do not call `SUN_LEN()` on unknown addresses.  
1175    /// See [`max_path_len()`](#tymethod.max_path_len) for which OSes this affects.
1176    ///
1177    /// # Safety
1178    ///
1179    /// Assigning a value > `sizeof(struct sockaddr_un)` to the `socklen_t`
1180    /// reference might lead to out-of-bounds reads later.
1181    pub unsafe 
1182    fn as_raw_mut_general(&mut self) -> (&mut sockaddr, &mut socklen_t) 
1183    {
1184        // SAFETY: sockaddr is a super-type of sockaddr_un.
1185        (unsafe { &mut*(&mut self.addr as *mut sockaddr_un as *mut sockaddr) }, &mut self.len)
1186    }
1187
1188    pub unsafe 
1189    fn as_raw_ptr_general(&self) -> (*const sockaddr, socklen_t) 
1190    {
1191        // SAFETY: sockaddr is a super-type of sockaddr_un.
1192        (&self.addr as *const sockaddr_un as *const sockaddr, self.len)
1193    }
1194
1195    /// Returns mutable references to the inner `struct sockaddr_un` and length.
1196    ///
1197    /// Pathname addresses are not guaranteed to be NUL-terminated on most OSes:
1198    /// Most paths will be NUL-terminated, but paths that just fit within `sockaddr_un.sun_len`
1199    /// (iow their length is equal to `addr.sun_len[..].len()`) will not have one.  
1200    /// Therefore do not call `SUN_LEN()` on unknown addresses.  
1201    /// See [`max_path_len()`](#tymethod.max_path_len) for which OSes this affects
1202    ///
1203    /// # Safety
1204    ///
1205    /// Assigning a value > `sizeof(struct sockaddr_un)` to the `socklen_t`
1206    /// reference might lead to out-of-bounds reads later.
1207    pub unsafe 
1208    fn as_raw_mut(&mut self) -> (&mut sockaddr_un, &mut socklen_t) 
1209    {
1210        (&mut self.addr, &mut self.len)
1211    }
1212}
1213
1214impl Default for UnixSocketAddr 
1215{
1216    fn default() -> Self 
1217    {
1218        Self::new_unspecified()
1219    }
1220}
1221
1222impl PartialEq for UnixSocketAddr 
1223{
1224    fn eq(&self, other: &Self) -> bool 
1225    {
1226        self.as_ref() == other.as_ref()
1227    }
1228}
1229
1230impl Eq for UnixSocketAddr {}
1231
1232impl Hash for UnixSocketAddr 
1233{
1234    fn hash<H: Hasher>(&self,  hasher: &mut H) 
1235    {
1236        self.as_ref().hash(hasher)
1237    }
1238}
1239
1240impl PartialEq<[u8]> for UnixSocketAddr 
1241{
1242    fn eq(&self,  unescaped: &[u8]) -> bool 
1243    {
1244        match (self.as_ref(), unescaped.first()) 
1245        {
1246            #[cfg(unix)]
1247            (UnixSocketAddrRef::Path(path), Some(_)) => 
1248                path.as_os_str().as_bytes() == unescaped,
1249            #[cfg(windows)]
1250            (UnixSocketAddrRef::Path(path), Some(_)) => 
1251                path.as_os_str().as_encoded_bytes() == unescaped,
1252            (UnixSocketAddrRef::Abstract(name), Some(b'\0')) => 
1253                name == &unescaped[1..],
1254            (UnixSocketAddrRef::Unnamed, None) => 
1255                true,
1256            (_, _) => 
1257                false,
1258        }
1259    }
1260}
1261impl PartialEq<UnixSocketAddr> for [u8]  
1262{
1263    fn eq(&self,  addr: &UnixSocketAddr) -> bool 
1264    {
1265        addr == self
1266    }
1267}
1268