@@ -515,15 +515,42 @@ impl fmt::Display for Ipv6Addr {
515
515
}
516
516
517
517
/// A wrapper around `sockaddr_un`.
518
- ///
519
- /// This also tracks the length of `sun_path` address (excluding
520
- /// a terminating null), because it may not be null-terminated. For example,
521
- /// unconnected and Linux abstract sockets are never null-terminated, and POSIX
522
- /// does not require that `sun_len` include the terminating null even for normal
523
- /// sockets. Note that the actual sockaddr length is greater by
524
- /// `offset_of!(libc::sockaddr_un, sun_path)`
525
518
#[ derive( Clone , Copy , Debug ) ]
526
- pub struct UnixAddr ( pub libc:: sockaddr_un , pub usize ) ;
519
+ pub struct UnixAddr {
520
+ // INVARIANT: sun & path_len are valid as defined by docs for from_raw_parts
521
+ sun : libc:: sockaddr_un ,
522
+ path_len : usize
523
+ }
524
+
525
+ // linux man page unix(7) says there are 3 kinds of unix socket:
526
+ // pathname: addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1
527
+ // unnamed: addrlen = sizeof(sa_family_t)
528
+ // abstract: addren > sizeof(sa_family_t), name = sun_path[..(addrlen - sizeof(sa_family_t))]
529
+ //
530
+ // what we call path_len = addrlen - offsetof(struct sockaddr_un, sun_path)
531
+ #[ derive( PartialEq , Eq , Hash ) ]
532
+ enum UnixAddrKind < ' a > {
533
+ Pathname ( & ' a Path ) ,
534
+ Unnamed ,
535
+ #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
536
+ Abstract ( & ' a [ u8 ] ) ,
537
+ }
538
+ impl < ' a > UnixAddrKind < ' a > {
539
+ /// Safety: sun & path_len must be valid
540
+ unsafe fn get ( sun : & ' a libc:: sockaddr_un , path_len : usize ) -> Self {
541
+ if path_len == 0 {
542
+ return Self :: Unnamed ;
543
+ }
544
+ #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
545
+ if sun. sun_path [ 0 ] == 0 {
546
+ let name = slice:: from_raw_parts ( sun. sun_path . as_ptr ( ) . add ( 1 ) as * const u8 , path_len - 1 ) ;
547
+ return Self :: Abstract ( name) ;
548
+ }
549
+ let pathname = slice:: from_raw_parts ( sun. sun_path . as_ptr ( ) as * const u8 , path_len - 1 ) ;
550
+ Self :: Pathname ( Path :: new ( OsStr :: from_bytes ( pathname) ) )
551
+ }
552
+ }
553
+
527
554
528
555
impl UnixAddr {
529
556
/// Create a new sockaddr_un representing a filesystem path.
@@ -537,15 +564,15 @@ impl UnixAddr {
537
564
538
565
let bytes = cstr. to_bytes ( ) ;
539
566
540
- if bytes. len ( ) > ret. sun_path . len ( ) {
567
+ if bytes. len ( ) >= ret. sun_path . len ( ) {
541
568
return Err ( Error :: from ( Errno :: ENAMETOOLONG ) ) ;
542
569
}
543
570
544
571
ptr:: copy_nonoverlapping ( bytes. as_ptr ( ) ,
545
572
ret. sun_path . as_mut_ptr ( ) as * mut u8 ,
546
573
bytes. len ( ) ) ;
547
574
548
- Ok ( UnixAddr ( ret, bytes. len ( ) ) )
575
+ Ok ( UnixAddr :: from_raw_parts ( ret, bytes. len ( ) + 1 ) )
549
576
}
550
577
} ) ?
551
578
}
@@ -564,7 +591,7 @@ impl UnixAddr {
564
591
.. mem:: zeroed ( )
565
592
} ;
566
593
567
- if path. len ( ) + 1 > ret. sun_path . len ( ) {
594
+ if path. len ( ) >= ret. sun_path . len ( ) {
568
595
return Err ( Error :: from ( Errno :: ENAMETOOLONG ) ) ;
569
596
}
570
597
@@ -574,28 +601,33 @@ impl UnixAddr {
574
601
ret. sun_path . as_mut_ptr ( ) . offset ( 1 ) as * mut u8 ,
575
602
path. len ( ) ) ;
576
603
577
- Ok ( UnixAddr ( ret, path. len ( ) + 1 ) )
604
+ Ok ( UnixAddr :: from_raw_parts ( ret, path. len ( ) + 1 ) )
578
605
}
579
606
}
580
607
581
- fn sun_path ( & self ) -> & [ u8 ] {
582
- unsafe { slice:: from_raw_parts ( self . 0 . sun_path . as_ptr ( ) as * const u8 , self . 1 ) }
608
+ /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `path_len` is the "addrlen"
609
+ /// of this address, but minus `offsetof(struct sockaddr_un, sun_path)`. Basically the length
610
+ /// of the data in `sun_path`.
611
+ ///
612
+ /// # Safety
613
+ /// This pair of sockaddr_un & path_len must be a valid unix addr, which means:
614
+ /// - path_len <= sockaddr_un.sun_path.len()
615
+ /// - if this is a unix addr with a pathname, sun.sun_path is a nul-terminated fs path and
616
+ /// sun.sun_path[path_len - 1] == 0
617
+ pub unsafe fn from_raw_parts ( sun : libc:: sockaddr_un , path_len : usize ) -> UnixAddr {
618
+ UnixAddr { sun, path_len }
619
+ }
620
+
621
+ fn kind ( & self ) -> UnixAddrKind < ' _ > {
622
+ // SAFETY: our sockaddr is always valid because of the invariant on the struct
623
+ unsafe { UnixAddrKind :: get ( & self . sun , self . path_len ) }
583
624
}
584
625
585
626
/// If this address represents a filesystem path, return that path.
586
627
pub fn path ( & self ) -> Option < & Path > {
587
- if self . 1 == 0 || self . 0 . sun_path [ 0 ] == 0 {
588
- // unnamed or abstract
589
- None
590
- } else {
591
- let p = self . sun_path ( ) ;
592
- // POSIX only requires that `sun_len` be at least long enough to
593
- // contain the pathname, and it need not be null-terminated. So we
594
- // need to create a string that is the shorter of the
595
- // null-terminated length or the full length.
596
- let ptr = & self . 0 . sun_path as * const libc:: c_char ;
597
- let reallen = unsafe { libc:: strnlen ( ptr, p. len ( ) ) } ;
598
- Some ( Path :: new ( <OsStr as OsStrExt >:: from_bytes ( & p[ ..reallen] ) ) )
628
+ match self . kind ( ) {
629
+ UnixAddrKind :: Pathname ( path) => Some ( path) ,
630
+ _ => None
599
631
}
600
632
}
601
633
@@ -605,39 +637,53 @@ impl UnixAddr {
605
637
/// leading null byte. `None` is returned for unnamed or path-backed sockets.
606
638
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
607
639
pub fn as_abstract ( & self ) -> Option < & [ u8 ] > {
608
- if self . 1 >= 1 && self . 0 . sun_path [ 0 ] == 0 {
609
- Some ( & self . sun_path ( ) [ 1 ..] )
610
- } else {
611
- // unnamed or filesystem path
612
- None
640
+ match self . kind ( ) {
641
+ UnixAddrKind :: Abstract ( name) => Some ( name) ,
642
+ _ => None
613
643
}
614
644
}
645
+
646
+ /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)`
647
+ #[ inline]
648
+ pub fn path_len ( & self ) -> usize {
649
+ self . path_len
650
+ }
651
+ /// Returns a pointer to the raw `sockaddr_un` struct
652
+ #[ inline]
653
+ pub fn as_ptr ( & self ) -> * const libc:: sockaddr_un {
654
+ & self . sun
655
+ }
656
+ /// Returns a mutable pointer to the raw `sockaddr_un` struct
657
+ #[ inline]
658
+ pub fn as_mut_ptr ( & mut self ) -> * mut libc:: sockaddr_un {
659
+ & mut self . sun
660
+ }
615
661
}
616
662
617
663
impl fmt:: Display for UnixAddr {
618
664
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
619
- if self . 1 == 0 {
620
- f . write_str ( "<unbound UNIX socket>" )
621
- } else if let Some ( path ) = self . path ( ) {
622
- path . display ( ) . fmt ( f )
623
- } else {
624
- let display = String :: from_utf8_lossy ( & self . sun_path ( ) [ 1 .. ] ) ;
625
- write ! ( f , "@{}" , display )
665
+ match self . kind ( ) {
666
+ UnixAddrKind :: Pathname ( path ) => path . display ( ) . fmt ( f ) ,
667
+ UnixAddrKind :: Unnamed => f . pad ( "<unbound UNIX socket>" ) ,
668
+ # [ cfg ( any ( target_os = "android" , target_os = "linux" ) ) ]
669
+ UnixAddrKind :: Abstract ( name ) => {
670
+ write ! ( f , "@{}" , String :: from_utf8_lossy( name ) )
671
+ }
626
672
}
627
673
}
628
674
}
629
675
630
676
impl PartialEq for UnixAddr {
631
677
fn eq ( & self , other : & UnixAddr ) -> bool {
632
- self . sun_path ( ) == other. sun_path ( )
678
+ self . kind ( ) == other. kind ( )
633
679
}
634
680
}
635
681
636
682
impl Eq for UnixAddr { }
637
683
638
684
impl Hash for UnixAddr {
639
685
fn hash < H : Hasher > ( & self , s : & mut H ) {
640
- ( self . 0 . sun_family , self . sun_path ( ) ) . hash ( s)
686
+ self . kind ( ) . hash ( s)
641
687
}
642
688
}
643
689
@@ -805,12 +851,12 @@ impl SockAddr {
805
851
} ,
806
852
mem:: size_of_val ( addr) as libc:: socklen_t
807
853
) ,
808
- SockAddr :: Unix ( UnixAddr ( ref addr , len ) ) => (
854
+ SockAddr :: Unix ( UnixAddr { ref sun , path_len } ) => (
809
855
// This cast is always allowed in C
810
856
unsafe {
811
- & * ( addr as * const libc:: sockaddr_un as * const libc:: sockaddr )
857
+ & * ( sun as * const libc:: sockaddr_un as * const libc:: sockaddr )
812
858
} ,
813
- ( len + offset_of ! ( libc:: sockaddr_un, sun_path) ) as libc:: socklen_t
859
+ ( path_len + offset_of ! ( libc:: sockaddr_un, sun_path) ) as libc:: socklen_t
814
860
) ,
815
861
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
816
862
SockAddr :: Netlink ( NetlinkAddr ( ref sa) ) => (
@@ -1376,11 +1422,8 @@ mod tests {
1376
1422
let name = String :: from ( "nix\0 abstract\0 test" ) ;
1377
1423
let addr = UnixAddr :: new_abstract ( name. as_bytes ( ) ) . unwrap ( ) ;
1378
1424
1379
- let sun_path1 = addr. sun_path ( ) ;
1380
- let sun_path2 = [ 0u8 , 110 , 105 , 120 , 0 , 97 , 98 , 115 , 116 , 114 , 97 , 99 , 116 , 0 , 116 , 101 , 115 , 116 ] ;
1381
- assert_eq ! ( sun_path1. len( ) , sun_path2. len( ) ) ;
1382
- for i in 0 ..sun_path1. len ( ) {
1383
- assert_eq ! ( sun_path1[ i] , sun_path2[ i] ) ;
1384
- }
1425
+ let sun_path1 = unsafe { & ( * addr. as_ptr ( ) ) . sun_path [ ..addr. path_len ( ) ] } ;
1426
+ let sun_path2 = [ 0 , 110 , 105 , 120 , 0 , 97 , 98 , 115 , 116 , 114 , 97 , 99 , 116 , 0 , 116 , 101 , 115 , 116 ] ;
1427
+ assert_eq ! ( sun_path1, sun_path2) ;
1385
1428
}
1386
1429
}
0 commit comments