11use super :: sa_family_t;
2+ use cfg_if:: cfg_if;
23use crate :: { Result , NixPath } ;
34use crate :: errno:: Errno ;
45use memoffset:: offset_of;
@@ -580,7 +581,13 @@ pub struct UnixAddr {
580581 sun : libc:: sockaddr_un ,
581582 /// The length of the valid part of `sun`, including the sun_family field
582583 /// but excluding any trailing nul.
583- sun_len : u8 ,
584+ // On the BSDs, this field is built into sun
585+ #[ cfg( any( target_os = "android" ,
586+ target_os = "fuchsia" ,
587+ target_os = "illumos" ,
588+ target_os = "linux"
589+ ) ) ]
590+ sun_len : u8
584591}
585592
586593// linux man page unix(7) says there are 3 kinds of unix socket:
@@ -611,7 +618,18 @@ impl<'a> UnixAddrKind<'a> {
611618 return Self :: Abstract ( name) ;
612619 }
613620 let pathname = slice:: from_raw_parts ( sun. sun_path . as_ptr ( ) as * const u8 , path_len) ;
614- Self :: Pathname ( Path :: new ( OsStr :: from_bytes ( pathname) ) )
621+ if pathname. last ( ) == Some ( & 0 ) {
622+ // A trailing NUL is not considered part of the path, and it does
623+ // not need to be included in the addrlen passed to functions like
624+ // bind(). However, Linux adds a trailing NUL, even if one was not
625+ // originally present, when returning addrs from functions like
626+ // getsockname() (the BSDs do not do that). So we need to filter
627+ // out any trailing NUL here, so sockaddrs can round-trip through
628+ // the kernel and still compare equal.
629+ Self :: Pathname ( Path :: new ( OsStr :: from_bytes ( & pathname[ 0 ..pathname. len ( ) - 1 ] ) ) )
630+ } else {
631+ Self :: Pathname ( Path :: new ( OsStr :: from_bytes ( pathname) ) )
632+ }
615633 }
616634}
617635
@@ -640,7 +658,6 @@ impl UnixAddr {
640658 target_os = "ios" ,
641659 target_os = "macos" ,
642660 target_os = "netbsd" ,
643- target_os = "illumos" ,
644661 target_os = "openbsd" ) ) ]
645662 {
646663 ret. sun_len = sun_len;
@@ -657,7 +674,7 @@ impl UnixAddr {
657674 /// Create a new `sockaddr_un` representing an address in the "abstract namespace".
658675 ///
659676 /// The leading nul byte for the abstract namespace is automatically added;
660- /// thus the input `path` is expected to be the bare name, not null -prefixed.
677+ /// thus the input `path` is expected to be the bare name, not NUL -prefixed.
661678 /// This is a Linux-specific extension, primarily used to allow chrooted
662679 /// processes to communicate with processes having a different filesystem view.
663680 #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
@@ -699,23 +716,24 @@ impl UnixAddr {
699716 /// - if this is a unix addr with a pathname, sun.sun_path is a
700717 /// fs path, not necessarily nul-terminated.
701718 pub ( crate ) unsafe fn from_raw_parts ( sun : libc:: sockaddr_un , sun_len : u8 ) -> UnixAddr {
702- #[ cfg( any( target_os = "dragonfly" ,
703- target_os = "freebsd" ,
704- target_os = "ios" ,
705- target_os = "macos" ,
706- target_os = "netbsd" ,
707- target_os = "illumos" ,
708- target_os = "openbsd" ) ) ]
709- {
710- assert_eq ! ( sun_len, sun. sun_len) ;
719+ cfg_if ! {
720+ if #[ cfg( any( target_os = "android" ,
721+ target_os = "fuchsia" ,
722+ target_os = "illumos" ,
723+ target_os = "linux"
724+ ) ) ]
725+ {
726+ UnixAddr { sun, sun_len }
727+ } else {
728+ assert_eq!( sun_len, sun. sun_len) ;
729+ UnixAddr { sun}
730+ }
711731 }
712-
713- UnixAddr { sun, sun_len }
714732 }
715733
716734 fn kind ( & self ) -> UnixAddrKind < ' _ > {
717735 // SAFETY: our sockaddr is always valid because of the invariant on the struct
718- unsafe { UnixAddrKind :: get ( & self . sun , self . sun_len ) }
736+ unsafe { UnixAddrKind :: get ( & self . sun , self . sun_len ( ) ) }
719737 }
720738
721739 /// If this address represents a filesystem path, return that path.
@@ -729,7 +747,7 @@ impl UnixAddr {
729747 /// If this address represents an abstract socket, return its name.
730748 ///
731749 /// For abstract sockets only the bare name is returned, without the
732- /// leading null byte. `None` is returned for unnamed or path-backed sockets.
750+ /// leading NUL byte. `None` is returned for unnamed or path-backed sockets.
733751 #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
734752 #[ cfg_attr( docsrs, doc( cfg( all( ) ) ) ) ]
735753 pub fn as_abstract ( & self ) -> Option < & [ u8 ] > {
@@ -742,7 +760,7 @@ impl UnixAddr {
742760 /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)`
743761 #[ inline]
744762 pub fn path_len ( & self ) -> usize {
745- self . sun_len as usize - offset_of ! ( libc:: sockaddr_un, sun_path)
763+ self . sun_len ( ) as usize - offset_of ! ( libc:: sockaddr_un, sun_path)
746764 }
747765 /// Returns a pointer to the raw `sockaddr_un` struct
748766 #[ inline]
@@ -754,6 +772,21 @@ impl UnixAddr {
754772 pub fn as_mut_ptr ( & mut self ) -> * mut libc:: sockaddr_un {
755773 & mut self . sun
756774 }
775+
776+ fn sun_len ( & self ) -> u8 {
777+ cfg_if ! {
778+ if #[ cfg( any( target_os = "android" ,
779+ target_os = "fuchsia" ,
780+ target_os = "illumos" ,
781+ target_os = "linux"
782+ ) ) ]
783+ {
784+ self . sun_len
785+ } else {
786+ self . sun. sun_len
787+ }
788+ }
789+ }
757790}
758791
759792#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
@@ -987,12 +1020,12 @@ impl SockAddr {
9871020 } ,
9881021 mem:: size_of_val ( addr) as libc:: socklen_t
9891022 ) ,
990- SockAddr :: Unix ( UnixAddr { ref sun , sun_len } ) => (
1023+ SockAddr :: Unix ( ref unix_addr ) => (
9911024 // This cast is always allowed in C
9921025 unsafe {
993- & * ( sun as * const libc:: sockaddr_un as * const libc:: sockaddr )
1026+ & * ( & unix_addr . sun as * const libc:: sockaddr_un as * const libc:: sockaddr )
9941027 } ,
995- sun_len as libc:: socklen_t
1028+ unix_addr . sun_len ( ) as libc:: socklen_t
9961029 ) ,
9971030 #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
9981031 SockAddr :: Netlink ( NetlinkAddr ( ref sa) ) => (
0 commit comments