@@ -2,8 +2,8 @@ use {Result, Error, NixPath};
2
2
use super :: { consts, sa_family_t} ;
3
3
use errno:: Errno ;
4
4
use libc;
5
- use std:: { fmt, hash, mem, net} ;
6
- use std:: ffi:: { CStr , OsStr } ;
5
+ use std:: { fmt, hash, mem, net, ptr } ;
6
+ use std:: ffi:: OsStr ;
7
7
use std:: path:: Path ;
8
8
use std:: os:: unix:: ffi:: OsStrExt ;
9
9
@@ -329,45 +329,82 @@ impl fmt::Display for Ipv6Addr {
329
329
*
330
330
*/
331
331
332
+ /// A wrapper around sockaddr_un. We track the length of sun_path,
333
+ /// because it may not be null-terminated (unconnected and abstract
334
+ /// sockets). Note that the actual sockaddr length is greater by
335
+ /// size_of::<sa_family_t>().
332
336
#[ derive( Copy ) ]
333
- pub struct UnixAddr ( pub libc:: sockaddr_un ) ;
337
+ pub struct UnixAddr ( pub libc:: sockaddr_un , pub usize ) ;
334
338
335
339
impl UnixAddr {
340
+ /// Create a new sockaddr_un representing a filesystem path.
336
341
pub fn new < P : ?Sized + NixPath > ( path : & P ) -> Result < UnixAddr > {
337
- use libc:: strcpy;
338
-
339
342
try!( path. with_nix_path ( |cstr| {
340
343
unsafe {
341
344
let mut ret = libc:: sockaddr_un {
342
345
sun_family : AddressFamily :: Unix as sa_family_t ,
343
346
.. mem:: zeroed ( )
344
347
} ;
345
348
346
- // Must be smaller to account for the null byte
347
- if path. len ( ) >= ret. sun_path . len ( ) {
349
+ let bytes = cstr. to_bytes_with_nul ( ) ;
350
+
351
+ if bytes. len ( ) > ret. sun_path . len ( ) {
348
352
return Err ( Error :: Sys ( Errno :: ENAMETOOLONG ) ) ;
349
353
}
350
354
351
- strcpy ( ret. sun_path . as_mut_ptr ( ) , cstr. as_ptr ( ) ) ;
355
+ ptr:: copy_nonoverlapping ( bytes. as_ptr ( ) ,
356
+ ret. sun_path . as_mut_ptr ( ) as * mut u8 ,
357
+ bytes. len ( ) ) ;
352
358
353
- Ok ( UnixAddr ( ret) )
359
+ Ok ( UnixAddr ( ret, bytes . len ( ) ) )
354
360
}
355
361
} ) )
356
362
}
357
363
358
- pub fn path ( & self ) -> & Path {
364
+ /// Create a new sockaddr_un representing an address in the
365
+ /// "abstract namespace". This is a Linux-specific extension,
366
+ /// primarily used to allow chrooted processes to communicate with
367
+ /// specific daemons.
368
+ pub fn new_abstract ( path : & [ u8 ] ) -> Result < UnixAddr > {
359
369
unsafe {
360
- let bytes = CStr :: from_ptr ( self . 0 . sun_path . as_ptr ( ) ) . to_bytes ( ) ;
361
- Path :: new ( <OsStr as OsStrExt >:: from_bytes ( bytes) )
370
+ let mut ret = libc:: sockaddr_un {
371
+ sun_family : AddressFamily :: Unix as sa_family_t ,
372
+ .. mem:: zeroed ( )
373
+ } ;
374
+
375
+ if path. len ( ) > ret. sun_path . len ( ) {
376
+ return Err ( Error :: Sys ( Errno :: ENAMETOOLONG ) ) ;
377
+ }
378
+
379
+ // Abstract addresses are represented by sun_path[0] ==
380
+ // b'\0', so copy starting one byte in.
381
+ ptr:: copy_nonoverlapping ( path. as_ptr ( ) ,
382
+ ret. sun_path . as_mut_ptr ( ) . offset ( 1 ) as * mut u8 ,
383
+ path. len ( ) ) ;
384
+
385
+ Ok ( UnixAddr ( ret, path. len ( ) ) )
386
+ }
387
+ }
388
+
389
+ fn sun_path ( & self ) -> & [ u8 ] {
390
+ unsafe { mem:: transmute ( & self . 0 . sun_path [ ..self . 1 ] ) }
391
+ }
392
+
393
+ /// If this address represents a filesystem path, return that path.
394
+ pub fn path ( & self ) -> Option < & Path > {
395
+ if self . 1 == 0 || self . 0 . sun_path [ 0 ] == 0 {
396
+ // unbound or abstract
397
+ None
398
+ } else {
399
+ let p = self . sun_path ( ) ;
400
+ Some ( Path :: new ( <OsStr as OsStrExt >:: from_bytes ( & p[ ..p. len ( ) -1 ] ) ) )
362
401
}
363
402
}
364
403
}
365
404
366
405
impl PartialEq for UnixAddr {
367
406
fn eq ( & self , other : & UnixAddr ) -> bool {
368
- unsafe {
369
- 0 == libc:: strcmp ( self . 0 . sun_path . as_ptr ( ) , other. 0 . sun_path . as_ptr ( ) )
370
- }
407
+ self . sun_path ( ) == other. sun_path ( )
371
408
}
372
409
}
373
410
@@ -376,7 +413,7 @@ impl Eq for UnixAddr {
376
413
377
414
impl hash:: Hash for UnixAddr {
378
415
fn hash < H : hash:: Hasher > ( & self , s : & mut H ) {
379
- ( self . 0 . sun_family , self . path ( ) ) . hash ( s)
416
+ ( self . 0 . sun_family , self . sun_path ( ) ) . hash ( s)
380
417
}
381
418
}
382
419
@@ -388,7 +425,14 @@ impl Clone for UnixAddr {
388
425
389
426
impl fmt:: Display for UnixAddr {
390
427
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
391
- self . path ( ) . display ( ) . fmt ( f)
428
+ if self . 1 == 0 {
429
+ f. write_str ( "<unbound UNIX socket>" )
430
+ } else if let Some ( path) = self . path ( ) {
431
+ path. display ( ) . fmt ( f)
432
+ } else {
433
+ let display = String :: from_utf8_lossy ( & self . sun_path ( ) [ 1 ..] ) ;
434
+ write ! ( f, "@{}" , display)
435
+ }
392
436
}
393
437
}
394
438
@@ -430,7 +474,7 @@ impl SockAddr {
430
474
match * self {
431
475
SockAddr :: Inet ( InetAddr :: V4 ( ref addr) ) => ( mem:: transmute ( addr) , mem:: size_of :: < libc:: sockaddr_in > ( ) as libc:: socklen_t ) ,
432
476
SockAddr :: Inet ( InetAddr :: V6 ( ref addr) ) => ( mem:: transmute ( addr) , mem:: size_of :: < libc:: sockaddr_in6 > ( ) as libc:: socklen_t ) ,
433
- SockAddr :: Unix ( UnixAddr ( ref addr) ) => ( mem:: transmute ( addr) , mem:: size_of :: < libc:: sockaddr_un > ( ) as libc:: socklen_t ) ,
477
+ SockAddr :: Unix ( UnixAddr ( ref addr, len ) ) => ( mem:: transmute ( addr) , ( len + mem:: size_of :: < libc:: sa_family_t > ( ) ) as libc:: socklen_t ) ,
434
478
}
435
479
}
436
480
}
0 commit comments