44//! the message headers may reference stack-local data.
55
66use crate :: backend:: c;
7- use crate :: backend:: conv:: { msg_control_len, msg_iov_len} ;
87
98use crate :: io:: { self , IoSlice , IoSliceMut } ;
109use crate :: net:: SocketAddrBuf ;
1110use crate :: net:: { addr:: SocketAddrArg , RecvAncillaryBuffer , SendAncillaryBuffer } ;
1211
1312use core:: mem:: zeroed;
1413
14+ /// Convert the value to the `msg_iovlen` field of a `msghdr` struct.
15+ #[ cfg( all(
16+ not( any( windows, target_os = "espidf" , target_os = "wasi" ) ) ,
17+ any(
18+ target_os = "android" ,
19+ all(
20+ target_os = "linux" ,
21+ not( target_env = "musl" ) ,
22+ not( all( target_env = "uclibc" , any( target_arch = "arm" , target_arch = "mips" ) ) )
23+ )
24+ )
25+ ) ) ]
26+ #[ inline]
27+ fn msg_iov_len ( len : usize ) -> c:: size_t {
28+ len
29+ }
30+
31+ /// Convert the value to the `msg_iovlen` field of a `msghdr` struct.
32+ #[ cfg( all(
33+ not( any(
34+ windows,
35+ target_os = "espidf" ,
36+ target_os = "redox" ,
37+ target_os = "vita" ,
38+ target_os = "wasi"
39+ ) ) ,
40+ not( any(
41+ target_os = "android" ,
42+ all(
43+ target_os = "linux" ,
44+ not( target_env = "musl" ) ,
45+ not( all( target_env = "uclibc" , any( target_arch = "arm" , target_arch = "mips" ) ) )
46+ )
47+ ) )
48+ ) ) ]
49+ #[ inline]
50+ fn msg_iov_len ( len : usize ) -> c:: c_int {
51+ len. try_into ( ) . unwrap_or ( c:: c_int:: MAX )
52+ }
53+
54+ /// Convert the value to a `socklen_t`.
55+ #[ cfg( any(
56+ bsd,
57+ solarish,
58+ target_env = "musl" ,
59+ target_os = "aix" ,
60+ target_os = "emscripten" ,
61+ target_os = "fuchsia" ,
62+ target_os = "haiku" ,
63+ target_os = "hurd" ,
64+ target_os = "nto" ,
65+ ) ) ]
66+ #[ inline]
67+ fn msg_control_len ( len : usize ) -> c:: socklen_t {
68+ len. try_into ( ) . unwrap_or ( c:: socklen_t:: MAX )
69+ }
70+
71+ /// Convert the value to a `size_t`.
72+ #[ cfg( not( any(
73+ bsd,
74+ solarish,
75+ windows,
76+ target_env = "musl" ,
77+ target_os = "aix" ,
78+ target_os = "emscripten" ,
79+ target_os = "espidf" ,
80+ target_os = "fuchsia" ,
81+ target_os = "haiku" ,
82+ target_os = "hurd" ,
83+ target_os = "nto" ,
84+ target_os = "redox" ,
85+ target_os = "vita" ,
86+ target_os = "wasi" ,
87+ ) ) ) ]
88+ #[ inline]
89+ fn msg_control_len ( len : usize ) -> c:: size_t {
90+ len
91+ }
92+
1593/// Create a message header intended to receive a datagram.
16- pub ( crate ) fn with_recv_msghdr < R > (
94+ ///
95+ /// # Safety
96+ ///
97+ /// If `f` dereferences the pointers in the `msghdr`, it must do so only within
98+ /// the bounds indicated by the associated lengths in the `msghdr`.
99+ ///
100+ /// And, if `f` returns `Ok`, it must have updated the `msg_controllen` field
101+ /// of the `msghdr` to indicate how many bytes it initialized.
102+ pub ( crate ) unsafe fn with_recv_msghdr < R > (
17103 name : & mut SocketAddrBuf ,
18104 iov : & mut [ IoSliceMut < ' _ > ] ,
19105 control : & mut RecvAncillaryBuffer < ' _ > ,
20106 f : impl FnOnce ( & mut c:: msghdr ) -> io:: Result < R > ,
21107) -> io:: Result < R > {
22108 control. clear ( ) ;
23109
24- let mut msghdr = {
25- let mut h = zero_msghdr ( ) ;
26- h. msg_name = name. storage . as_mut_ptr ( ) . cast ( ) ;
27- h. msg_namelen = name. len ;
28- h. msg_iov = iov. as_mut_ptr ( ) . cast ( ) ;
29- h. msg_iovlen = msg_iov_len ( iov. len ( ) ) ;
30- h. msg_control = control. as_control_ptr ( ) . cast ( ) ;
31- h. msg_controllen = msg_control_len ( control. control_len ( ) ) ;
32- h
33- } ;
110+ let mut msghdr = zero_msghdr ( ) ;
111+ msghdr. msg_name = name. storage . as_mut_ptr ( ) . cast ( ) ;
112+ msghdr. msg_namelen = name. len ;
113+ msghdr. msg_iov = iov. as_mut_ptr ( ) . cast ( ) ;
114+ msghdr. msg_iovlen = msg_iov_len ( iov. len ( ) ) ;
115+ msghdr. msg_control = control. as_control_ptr ( ) . cast ( ) ;
116+ msghdr. msg_controllen = msg_control_len ( control. control_len ( ) ) ;
34117
35118 let res = f ( & mut msghdr) ;
36119
37120 // Reset the control length.
38121 if res. is_ok ( ) {
39- unsafe {
40- control . set_control_len ( msghdr . msg_controllen . try_into ( ) . unwrap_or ( usize :: MAX ) ) ;
41- }
122+ // SAFETY: `f` returned `Ok`, so our safety condition requires `f` to
123+ // have initialized `msg_controllen` bytes.
124+ control . set_control_len ( msghdr . msg_controllen as usize ) ;
42125 }
43126
44127 name. len = msghdr. msg_namelen ;
@@ -47,39 +130,49 @@ pub(crate) fn with_recv_msghdr<R>(
47130}
48131
49132/// Create a message header intended to send without an address.
50- pub ( crate ) fn with_noaddr_msghdr < R > (
133+ ///
134+ /// The returned `msghdr` will contain raw pointers to the memory
135+ /// referenced by `iov` and `control`.
136+ pub ( crate ) fn noaddr_msghdr (
51137 iov : & [ IoSlice < ' _ > ] ,
52138 control : & mut SendAncillaryBuffer < ' _ , ' _ , ' _ > ,
53- f : impl FnOnce ( c:: msghdr ) -> R ,
54- ) -> R {
55- f ( {
56- let mut h = zero_msghdr ( ) ;
57- h. msg_iov = iov. as_ptr ( ) as _ ;
58- h. msg_iovlen = msg_iov_len ( iov. len ( ) ) ;
59- h. msg_control = control. as_control_ptr ( ) . cast ( ) ;
60- h. msg_controllen = msg_control_len ( control. control_len ( ) ) ;
61- h
62- } )
139+ ) -> c:: msghdr {
140+ let mut h = zero_msghdr ( ) ;
141+ h. msg_iov = iov. as_ptr ( ) as _ ;
142+ h. msg_iovlen = msg_iov_len ( iov. len ( ) ) ;
143+ h. msg_control = control. as_control_ptr ( ) . cast ( ) ;
144+ h. msg_controllen = msg_control_len ( control. control_len ( ) ) ;
145+ h
63146}
64147
65148/// Create a message header intended to send with the specified address.
66- pub ( crate ) fn with_msghdr < R > (
149+ ///
150+ /// This creates a `c::msghdr` and calls a function `f` on it. The `msghdr`'s
151+ /// raw pointers may point to temporaries, so this function should avoid
152+ /// storing the pointers anywhere that would outlive the function call.
153+ ///
154+ /// # Safety
155+ ///
156+ /// If `f` dereferences the pointers in the `msghdr`, it must do so only within
157+ /// the bounds indicated by the associated lengths in the `msghdr`.
158+ pub ( crate ) unsafe fn with_msghdr < R > (
67159 addr : & impl SocketAddrArg ,
68160 iov : & [ IoSlice < ' _ > ] ,
69161 control : & mut SendAncillaryBuffer < ' _ , ' _ , ' _ > ,
70- f : impl FnOnce ( c:: msghdr ) -> R ,
162+ f : impl FnOnce ( & c:: msghdr ) -> R ,
71163) -> R {
72164 addr. with_sockaddr ( |addr_ptr, addr_len| {
73- f ( {
74- let mut h = zero_msghdr ( ) ;
75- h. msg_name = addr_ptr as * mut _ ;
76- h. msg_namelen = addr_len as _ ;
77- h. msg_iov = iov. as_ptr ( ) as _ ;
78- h. msg_iovlen = msg_iov_len ( iov. len ( ) ) ;
79- h. msg_control = control. as_control_ptr ( ) . cast ( ) ;
80- h. msg_controllen = msg_control_len ( control. control_len ( ) ) ;
81- h
82- } )
165+ let mut h = zero_msghdr ( ) ;
166+ h. msg_name = addr_ptr as * mut _ ;
167+ h. msg_namelen = addr_len as _ ;
168+ h. msg_iov = iov. as_ptr ( ) as _ ;
169+ h. msg_iovlen = msg_iov_len ( iov. len ( ) ) ;
170+ h. msg_control = control. as_control_ptr ( ) . cast ( ) ;
171+ h. msg_controllen = msg_control_len ( control. control_len ( ) ) ;
172+ // Pass a reference to the `c::msghdr` instead of passing it by value
173+ // because it may contain pointers to temporary objects that won't
174+ // live beyond the call to `with_sockaddr`.
175+ f ( & h)
83176 } )
84177}
85178
0 commit comments