Skip to main content

uds_fork/
addr.rs

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