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