@@ -8,7 +8,7 @@ mod utils;
88
99use std:: io:: ErrorKind ;
1010use std:: time:: { Duration , Instant } ;
11- use std:: { ptr, thread} ;
11+ use std:: { ptr, slice , thread} ;
1212
1313use libc_utils:: * ;
1414
@@ -121,11 +121,26 @@ fn test_set_reuseaddr_invalid_len() {
121121 let sockfd =
122122 unsafe { errno_result ( libc:: socket ( libc:: AF_INET , libc:: SOCK_STREAM , 0 ) ) . unwrap ( ) } ;
123123 // Value should be of type `libc::c_int` which has size 4 bytes.
124- // By providing a u64 of size 8 bytes we trigger an invalid length error.
125- let err = net:: setsockopt ( sockfd, libc:: SOL_SOCKET , libc:: SO_REUSEADDR , 1u64 ) . unwrap_err ( ) ;
124+ // By providing an u16 of size 2 bytes we trigger an invalid length error.
125+ let err = net:: setsockopt ( sockfd, libc:: SOL_SOCKET , libc:: SO_REUSEADDR , 1u16 ) . unwrap_err ( ) ;
126126 assert_eq ! ( err. kind( ) , ErrorKind :: InvalidInput ) ;
127127 // Check that it is the right kind of `InvalidInput`.
128128 assert_eq ! ( err. raw_os_error( ) , Some ( libc:: EINVAL ) ) ;
129+
130+ // By providing an u64 of size 8 bytes the behavior differs between native hosts and Miri.
131+ let result = net:: setsockopt ( sockfd, libc:: SOL_SOCKET , libc:: SO_REUSEADDR , 1u64 ) ;
132+ match result {
133+ Err ( err) => {
134+ // Check that this is the right error.
135+ assert_eq ! ( err. kind( ) , ErrorKind :: InvalidInput ) ;
136+ assert_eq ! ( err. raw_os_error( ) , Some ( libc:: EINVAL ) ) ;
137+ }
138+ Ok ( _) => {
139+ // Some native hosts just ignore too large inputs and only look at a prefix.
140+ // On Miri we require an exact size.
141+ assert ! ( !cfg!( miri) ) ;
142+ }
143+ }
129144}
130145
131146#[ cfg( any(
@@ -174,18 +189,35 @@ fn test_bind_ipv4_invalid_addr_len() {
174189 let sockfd =
175190 unsafe { errno_result ( libc:: socket ( libc:: AF_INET , libc:: SOCK_STREAM , 0 ) ) . unwrap ( ) } ;
176191 let addr = net:: sock_addr_ipv4 ( net:: IPV4_LOCALHOST , 0 ) ;
192+ // A too small size is invalid.
177193 let err = unsafe {
178194 errno_result ( libc:: bind (
179195 sockfd,
180196 ( & addr as * const libc:: sockaddr_in ) . cast :: < libc:: sockaddr > ( ) ,
181- // Add 1 to the address to make the size invalid.
182- ( size_of :: < libc:: sockaddr_in > ( ) + 1 ) as libc:: socklen_t ,
197+ ( size_of :: < libc:: sockaddr_in > ( ) - 1 ) as libc:: socklen_t ,
183198 ) )
184199 . unwrap_err ( )
185200 } ;
186201 assert_eq ! ( err. kind( ) , ErrorKind :: InvalidInput ) ;
187202 // Check that it is the right kind of `InvalidInput`.
188203 assert_eq ! ( err. raw_os_error( ) , Some ( libc:: EINVAL ) ) ;
204+
205+ if cfg ! ( miri) {
206+ // A too big size is also invalid. Some native hosts (e.g. Linux)
207+ // allow too big sizes, so we skip this test on native hosts:
208+ // <https://github.com/rust-lang/miri/pull/5059#discussion_r3305439221>
209+ let err = unsafe {
210+ errno_result ( libc:: bind (
211+ sockfd,
212+ ( & addr as * const libc:: sockaddr_in ) . cast :: < libc:: sockaddr > ( ) ,
213+ ( size_of :: < libc:: sockaddr_in > ( ) + 1 ) as libc:: socklen_t ,
214+ ) )
215+ . unwrap_err ( )
216+ } ;
217+ assert_eq ! ( err. kind( ) , ErrorKind :: InvalidInput ) ;
218+ // Check that it is the right kind of `InvalidInput`.
219+ assert_eq ! ( err. raw_os_error( ) , Some ( libc:: EINVAL ) ) ;
220+ }
189221}
190222
191223fn test_bind_ipv6 ( ) {
@@ -719,48 +751,62 @@ fn test_shutdown_writable_after_read_close() {
719751fn test_getsockopt_truncate ( ) {
720752 let ( sockfd, _) = net:: make_listener_ipv4 ( ) . unwrap ( ) ;
721753
722- // The actual TTL with a correctly sized buffer.
723- let ttl = net:: getsockopt :: < libc:: c_uint > ( sockfd, libc:: IPPROTO_IP , libc:: IP_TTL ) . unwrap ( ) ;
754+ // Set the read timeout for the socket.
755+ // We use a multiple of 4ms for the `usec` since Linux seems to do rounding.
756+ let new_timeout = libc:: timeval { tv_sec : 123 , tv_usec : 40_000 } ;
757+ net:: setsockopt ( sockfd, libc:: SOL_SOCKET , libc:: SO_RCVTIMEO , new_timeout) . unwrap ( ) ;
758+
759+ let mut option_value = std:: mem:: MaybeUninit :: < [ u8 ; 5 ] > :: zeroed ( ) ;
760+ // The actual `timeval` length is more than 5 bytes.
761+ let mut short_option_len = 5 as libc:: socklen_t ;
762+ assert ! ( short_option_len < size_of:: <libc:: timeval>( ) as libc:: socklen_t) ;
724763
725- let mut option_value = std:: mem:: MaybeUninit :: < u32 > :: zeroed ( ) ;
726- // The actual length is 4 bytes.
727- let mut short_option_len = 2 as libc:: socklen_t ;
764+ let timeout =
765+ net:: getsockopt :: < libc:: timeval > ( sockfd, libc:: SOL_SOCKET , libc:: SO_RCVTIMEO ) . unwrap ( ) ;
766+ // Ensure that we get the same value back as we just set.
767+ assert_eq ! ( timeout. tv_sec, new_timeout. tv_sec) ;
768+ assert_eq ! ( timeout. tv_usec, new_timeout. tv_usec) ;
728769
729770 errno_result ( unsafe {
730771 libc:: getsockopt (
731772 sockfd,
732- libc:: IPPROTO_IP ,
733- libc:: IP_TTL ,
773+ libc:: SOL_SOCKET ,
774+ libc:: SO_RCVTIMEO ,
734775 option_value. as_mut_ptr ( ) . cast ( ) ,
735776 & mut short_option_len,
736777 )
737778 } )
738779 . unwrap ( ) ;
739780 // Ensure that the size wasn't changed.
740- assert_eq ! ( short_option_len, 2 ) ;
741- let short_ttl = unsafe { option_value. assume_init ( ) } ;
781+ assert_eq ! ( short_option_len, 5 ) ;
782+ let truncated_timeout = unsafe { option_value. assume_init ( ) } ;
742783
743- // Assert that the value was silently truncated.
744- assert_eq ! ( short_ttl. to_ne_bytes( ) [ 0 ..2 ] , ttl. to_ne_bytes( ) [ 0 ..2 ] ) ;
784+ unsafe {
785+ let timeout_ptr = ( & new_timeout) as * const libc:: timeval as * const u8 ;
786+ // Assert that the value was silently truncated.
787+ assert_eq ! ( & truncated_timeout, slice:: from_raw_parts( timeout_ptr, 5 ) ) ;
788+ }
745789
746- let mut option_value = std:: mem:: MaybeUninit :: < u32 > :: zeroed ( ) ;
747- // The actual length is 4 bytes .
748- let mut long_option_len = 6 as libc:: socklen_t ;
790+ let mut option_value = std:: mem:: MaybeUninit :: < libc :: timeval > :: zeroed ( ) ;
791+ // The actual length is smaller than this .
792+ let mut long_option_len = ( size_of :: < libc :: timeval > ( ) + 2 ) as libc:: socklen_t ;
749793
750794 errno_result ( unsafe {
751795 libc:: getsockopt (
752796 sockfd,
753- libc:: IPPROTO_IP ,
754- libc:: IP_TTL ,
797+ libc:: SOL_SOCKET ,
798+ libc:: SO_RCVTIMEO ,
755799 option_value. as_mut_ptr ( ) . cast ( ) ,
756800 & mut long_option_len,
757801 )
758802 } )
759803 . unwrap ( ) ;
760804 // Ensure that the size was shortened to the actual length.
761- assert_eq ! ( long_option_len, 4 ) ;
762- let long_ttl = unsafe { option_value. assume_init ( ) } ;
763- assert_eq ! ( long_ttl, ttl) ;
805+ assert_eq ! ( long_option_len, size_of:: <libc:: timeval>( ) as libc:: socklen_t) ;
806+ // The returned timeout should be the same value as we just set.
807+ let untruncated_timeout = unsafe { option_value. assume_init ( ) } ;
808+ assert_eq ! ( untruncated_timeout. tv_sec, new_timeout. tv_sec) ;
809+ assert_eq ! ( untruncated_timeout. tv_usec, new_timeout. tv_usec) ;
764810}
765811
766812/// Test setting and getting the SO_SNDTIMEO socket option.
@@ -781,8 +827,8 @@ fn test_sockopt_sndtimeo() {
781827 assert_eq ! ( timeout. tv_sec, 0 ) ;
782828 assert_eq ! ( timeout. tv_usec, 0 ) ;
783829
784- // A 50 millisecond timeout.
785- let short_timeout = libc:: timeval { tv_sec : 0 , tv_usec : 50_000 } ;
830+ // A 40 millisecond timeout.
831+ let short_timeout = libc:: timeval { tv_sec : 0 , tv_usec : 40_000 } ;
786832 net:: setsockopt ( client_sockfd, libc:: SOL_SOCKET , libc:: SO_SNDTIMEO , short_timeout) . unwrap ( ) ;
787833
788834 let timeout =
@@ -804,9 +850,9 @@ fn test_sockopt_sndtimeo() {
804850 // it's because of the write timeout exceeding because the write buffer
805851 // is full.
806852 Err ( err) if err. kind ( ) == ErrorKind :: WouldBlock => {
807- // The last write should return an EAGAIN/EWOULDBLOCK after ~50ms instead
853+ // The last write should return an EAGAIN/EWOULDBLOCK after ~40ms instead
808854 // of blocking indefinitely.
809- assert ! ( Instant :: now( ) . duration_since( before) >= Duration :: from_millis( 50 ) ) ;
855+ assert ! ( Instant :: now( ) . duration_since( before) >= Duration :: from_millis( 40 ) ) ;
810856 break ;
811857 }
812858 Err ( err) => panic ! ( "unexpected error whilst filling up buffer: {err}" ) ,
@@ -832,8 +878,8 @@ fn test_sockopt_rcvtimeo() {
832878 assert_eq ! ( timeout. tv_sec, 0 ) ;
833879 assert_eq ! ( timeout. tv_usec, 0 ) ;
834880
835- // A 50 millisecond timeout.
836- let short_timeout = libc:: timeval { tv_sec : 0 , tv_usec : 50_000 } ;
881+ // A 40 millisecond timeout.
882+ let short_timeout = libc:: timeval { tv_sec : 0 , tv_usec : 40_000 } ;
837883 net:: setsockopt ( client_sockfd, libc:: SOL_SOCKET , libc:: SO_RCVTIMEO , short_timeout) . unwrap ( ) ;
838884
839885 let timeout =
@@ -851,6 +897,6 @@ fn test_sockopt_rcvtimeo() {
851897 . unwrap_err ( )
852898 } ;
853899 assert_eq ! ( err. kind( ) , ErrorKind :: WouldBlock ) ;
854- // Ensure that we blocked for at least 50 milliseconds.
855- assert ! ( Instant :: now( ) . duration_since( before) >= Duration :: from_millis( 50 ) )
900+ // Ensure that we blocked for at least 40 milliseconds.
901+ assert ! ( Instant :: now( ) . duration_since( before) >= Duration :: from_millis( 40 ) )
856902}
0 commit comments