1
1
//! Support for Unix domain socket clients and servers.
2
2
#![ warn( missing_docs) ]
3
- #![ doc( html_root_url="https://sfackler.github.io/rust-unix-socket/doc/v0.4.3 " ) ]
3
+ #![ doc( html_root_url="https://sfackler.github.io/rust-unix-socket/doc/v0.4.4 " ) ]
4
4
#![ cfg_attr( feature = "socket_timeout" , feature( duration) ) ]
5
5
#![ cfg_attr( all( test, feature = "socket_timeout" ) , feature( duration_span) ) ]
6
6
@@ -20,6 +20,7 @@ use std::os::unix::io::{RawFd, AsRawFd};
20
20
use std:: os:: unix:: ffi:: OsStrExt ;
21
21
use std:: fmt;
22
22
use std:: path:: Path ;
23
+ use std:: mem:: size_of;
23
24
24
25
extern "C" {
25
26
fn socketpair ( domain : libc:: c_int ,
@@ -202,7 +203,7 @@ unsafe fn sockaddr_un<P: AsRef<Path>>(path: P)
202
203
}
203
204
204
205
/// The kind of an address associated with a Unix socket.
205
- #[ derive( Debug , Clone , Copy ) ]
206
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
206
207
pub enum AddressKind < ' a > {
207
208
/// An unnamed address.
208
209
Unnamed ,
@@ -237,7 +238,13 @@ impl SocketAddr {
237
238
let mut len = mem:: size_of :: < libc:: sockaddr_un > ( ) as libc:: socklen_t ;
238
239
try!( cvt ( f ( & mut addr as * mut _ as * mut _ , & mut len) ) ) ;
239
240
240
- if addr. sun_family != libc:: AF_UNIX as libc:: sa_family_t {
241
+ if len == 0 {
242
+ // When there is a datagram from unnamed unix socket
243
+ // linux returns zero bytes of address
244
+ len = sun_path_offset ( ) as libc:: socklen_t ; // i.e. zero-length address
245
+ } else if ( len as usize ) < size_of :: < libc:: sa_family_t > ( ) ||
246
+ addr. sun_family != libc:: AF_UNIX as libc:: sa_family_t
247
+ {
241
248
return Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput ,
242
249
"file descriptor did not correspond to a Unix socket" ) ) ;
243
250
}
@@ -472,8 +479,8 @@ impl AsRawFd for UnixStream {
472
479
}
473
480
474
481
#[ cfg( feature = "from_raw_fd" ) ]
482
+ /// Requires the `from_raw_fd` feature.
475
483
impl std:: os:: unix:: io:: FromRawFd for UnixStream {
476
- /// Requires the `from_raw_fd` feature.
477
484
unsafe fn from_raw_fd ( fd : RawFd ) -> UnixStream {
478
485
UnixStream {
479
486
inner : Inner ( fd)
@@ -591,8 +598,8 @@ impl AsRawFd for UnixListener {
591
598
}
592
599
593
600
#[ cfg( feature = "from_raw_fd" ) ]
601
+ /// Requires the `from_raw_fd` feature.
594
602
impl std:: os:: unix:: io:: FromRawFd for UnixListener {
595
- /// Requires the `from_raw_fd` feature.
596
603
unsafe fn from_raw_fd ( fd : RawFd ) -> UnixListener {
597
604
UnixListener {
598
605
inner : Inner ( fd)
@@ -658,7 +665,7 @@ impl fmt::Debug for UnixDatagram {
658
665
}
659
666
660
667
impl UnixDatagram {
661
- /// Creates a Unix datagram socket from the given path.
668
+ /// Creates a Unix datagram socket bound to the given path.
662
669
pub fn bind < P : AsRef < Path > > ( path : P ) -> io:: Result < UnixDatagram > {
663
670
unsafe {
664
671
let inner = try!( Inner :: new ( libc:: SOCK_DGRAM ) ) ;
@@ -672,6 +679,30 @@ impl UnixDatagram {
672
679
}
673
680
}
674
681
682
+ /// Creates a Unix Datagram socket which is not bound to any address.
683
+ pub fn unbound ( ) -> io:: Result < UnixDatagram > {
684
+ let inner = try!( Inner :: new ( libc:: SOCK_DGRAM ) ) ;
685
+ Ok ( UnixDatagram {
686
+ inner : inner,
687
+ } )
688
+ }
689
+
690
+ /// Connect the socket to the specified address.
691
+ ///
692
+ /// The `send` method may be used to send data to the specified address.
693
+ /// `recv` and `recv_from` will only receive data from that address.
694
+ pub fn connect < P : AsRef < Path > > ( & self , path : P )
695
+ -> io:: Result < ( ) >
696
+ {
697
+ unsafe {
698
+ let ( addr, len) = try!( sockaddr_un ( path) ) ;
699
+
700
+ try!( cvt ( libc:: connect ( self . inner . 0 , & addr as * const _ as * const _ , len) ) ) ;
701
+
702
+ Ok ( ( ) )
703
+ }
704
+ }
705
+
675
706
/// Returns the address of this socket.
676
707
pub fn local_addr ( & self ) -> io:: Result < SocketAddr > {
677
708
SocketAddr :: new ( |addr, len| unsafe { libc:: getsockname ( self . inner . 0 , addr, len) } )
@@ -698,7 +729,20 @@ impl UnixDatagram {
698
729
Ok ( ( count as usize , addr) )
699
730
}
700
731
701
- /// Sends data on the socket to the given address.
732
+ /// Receives data from the socket.
733
+ ///
734
+ /// On success, returns the number of bytes read.
735
+ pub fn recv ( & self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
736
+ unsafe {
737
+ let count = try!( cvt_s ( libc:: recv ( self . inner . 0 ,
738
+ buf. as_mut_ptr ( ) as * mut _ ,
739
+ calc_len ( buf) ,
740
+ 0 ) ) ) ;
741
+ Ok ( count as usize )
742
+ }
743
+ }
744
+
745
+ /// Sends data on the socket to the specified address.
702
746
///
703
747
/// On success, returns the number of bytes written.
704
748
pub fn send_to < P : AsRef < Path > > ( & self , buf : & [ u8 ] , path : P ) -> io:: Result < usize > {
@@ -715,6 +759,22 @@ impl UnixDatagram {
715
759
}
716
760
}
717
761
762
+ /// Sends data on the socket to the socket's peer.
763
+ ///
764
+ /// The peer address may be set by the `connect` method, and this method
765
+ /// will return an error if the socket has not already been connected.
766
+ ///
767
+ /// On success, returns the number of bytes written.
768
+ pub fn send ( & self , buf : & [ u8 ] ) -> io:: Result < usize > {
769
+ unsafe {
770
+ let count = try!( cvt_s ( libc:: send ( self . inner . 0 ,
771
+ buf. as_ptr ( ) as * const _ ,
772
+ calc_len ( buf) ,
773
+ 0 ) ) ) ;
774
+ Ok ( count as usize )
775
+ }
776
+ }
777
+
718
778
/// Sets the read timeout for the socket.
719
779
///
720
780
/// If the provided value is `None`, then `recv_from` calls will block
@@ -772,8 +832,8 @@ impl AsRawFd for UnixDatagram {
772
832
}
773
833
774
834
#[ cfg( feature = "from_raw_fd" ) ]
835
+ /// Requires the `from_raw_fd` feature.
775
836
impl std:: os:: unix:: io:: FromRawFd for UnixDatagram {
776
- /// Requires the `from_raw_fd` feature.
777
837
unsafe fn from_raw_fd ( fd : RawFd ) -> UnixDatagram {
778
838
UnixDatagram {
779
839
inner : Inner ( fd)
@@ -790,7 +850,7 @@ mod test {
790
850
use std:: io:: prelude:: * ;
791
851
use self :: tempdir:: TempDir ;
792
852
793
- use { UnixListener , UnixStream , UnixDatagram } ;
853
+ use { UnixListener , UnixStream , UnixDatagram , AddressKind } ;
794
854
795
855
macro_rules! or_panic {
796
856
( $e: expr) => {
@@ -1037,4 +1097,71 @@ mod test {
1037
1097
or_panic ! ( sock2. recv_from( & mut buf) ) ;
1038
1098
assert_eq ! ( msg, & buf[ ..] ) ;
1039
1099
}
1100
+
1101
+ #[ test]
1102
+ fn test_unnamed_unix_datagram ( ) {
1103
+ let dir = or_panic ! ( TempDir :: new( "unix_socket" ) ) ;
1104
+ let path1 = dir. path ( ) . join ( "sock1" ) ;
1105
+
1106
+ let sock1 = or_panic ! ( UnixDatagram :: bind( & path1) ) ;
1107
+ let sock2 = or_panic ! ( UnixDatagram :: unbound( ) ) ;
1108
+
1109
+ let msg = b"hello world" ;
1110
+ or_panic ! ( sock2. send_to( msg, & path1) ) ;
1111
+ let mut buf = [ 0 ; 11 ] ;
1112
+ let ( usize, addr) = or_panic ! ( sock1. recv_from( & mut buf) ) ;
1113
+ assert_eq ! ( usize , 11 ) ;
1114
+ assert_eq ! ( addr. address( ) , AddressKind :: Unnamed ) ;
1115
+ assert_eq ! ( msg, & buf[ ..] ) ;
1116
+ }
1117
+
1118
+ #[ test]
1119
+ fn test_connect_unix_datagram ( ) {
1120
+ let dir = or_panic ! ( TempDir :: new( "unix_socket" ) ) ;
1121
+ let path1 = dir. path ( ) . join ( "sock1" ) ;
1122
+ let path2 = dir. path ( ) . join ( "sock2" ) ;
1123
+
1124
+ let bsock1 = or_panic ! ( UnixDatagram :: bind( & path1) ) ;
1125
+ let bsock2 = or_panic ! ( UnixDatagram :: bind( & path2) ) ;
1126
+ let sock = or_panic ! ( UnixDatagram :: unbound( ) ) ;
1127
+ or_panic ! ( sock. connect( & path1) ) ;
1128
+
1129
+ // Check send()
1130
+ let msg = b"hello there" ;
1131
+ or_panic ! ( sock. send( msg) ) ;
1132
+ let mut buf = [ 0 ; 11 ] ;
1133
+ let ( usize, addr) = or_panic ! ( bsock1. recv_from( & mut buf) ) ;
1134
+ assert_eq ! ( usize , 11 ) ;
1135
+ assert_eq ! ( addr. address( ) , AddressKind :: Unnamed ) ;
1136
+ assert_eq ! ( msg, & buf[ ..] ) ;
1137
+
1138
+
1139
+ // Send to should still work too
1140
+ let msg = b"hello world" ;
1141
+ or_panic ! ( sock. send_to( msg, & path2) ) ;
1142
+ or_panic ! ( bsock2. recv_from( & mut buf) ) ;
1143
+ assert_eq ! ( msg, & buf[ ..] ) ;
1144
+
1145
+ // Changing default socket works too
1146
+ or_panic ! ( sock. connect( & path2) ) ;
1147
+ or_panic ! ( sock. send( msg) ) ;
1148
+ or_panic ! ( bsock2. recv_from( & mut buf) ) ;
1149
+ }
1150
+
1151
+ #[ test]
1152
+ fn test_unix_datagram_recv ( ) {
1153
+ let dir = or_panic ! ( TempDir :: new( "unix_socket" ) ) ;
1154
+ let path1 = dir. path ( ) . join ( "sock1" ) ;
1155
+
1156
+ let sock1 = or_panic ! ( UnixDatagram :: bind( & path1) ) ;
1157
+ let sock2 = or_panic ! ( UnixDatagram :: unbound( ) ) ;
1158
+ or_panic ! ( sock2. connect( & path1) ) ;
1159
+
1160
+ let msg = b"hello world" ;
1161
+ or_panic ! ( sock2. send_to( msg, & path1) ) ;
1162
+ let mut buf = [ 0 ; 11 ] ;
1163
+ let size = or_panic ! ( sock1. recv( & mut buf) ) ;
1164
+ assert_eq ! ( size, 11 ) ;
1165
+ assert_eq ! ( msg, & buf[ ..] ) ;
1166
+ }
1040
1167
}
0 commit comments