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§ion=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}