@@ -92,14 +92,16 @@ general knowledge of ancillary data and the Unix sockets API?
92
92
Sending a file descriptor:
93
93
94
94
``` rust
95
- use std :: os :: unix :: net :: {AncillaryData , MessageSender , UnixStream };
95
+ use std :: fs :: File ;
96
+ use std :: os :: unix :: net :: {AncillaryDataBuf , MessageSender , UnixStream };
96
97
use std :: os :: fd :: AsFd ;
97
98
98
- fn send_file (stream : & UnixStream , file : std :: fs :: File ) -> std :: io :: Result <()> {
99
- let mut ancillary = AncillaryData :: new ();
100
- ancillary . add_file_descriptors (& [
99
+ fn send_file (stream : & UnixStream , file : File ) -> std :: io :: Result <()> {
100
+ let mut ancillary_buf = AncillaryDataBuf :: new ();
101
+ ancillary_buf . add_file_descriptors (& [
101
102
file . as_fd (),
102
103
]);
104
+ let mut ancillary = ancillary_buf . to_ancillary_data ();
103
105
104
106
MessageSender :: new (stream , b " \ x00 " )
105
107
. ancillary_data (& mut ancillary )
@@ -111,22 +113,28 @@ fn send_file(stream: &UnixStream, file: std::fs::File) -> std::io::Result<()> {
111
113
Receiving a file descriptor:
112
114
113
115
``` rust
114
- use std :: os :: unix :: net :: {AncillaryData , MessageReceiver , UnixStream };
116
+ use std :: fs :: File ;
117
+ use std :: os :: unix :: net :: {AncillaryDataBuf , MessageReceiver , UnixStream };
115
118
116
- fn recv_file (stream : & UnixStream ) -> std :: io :: Result <std :: fs :: File > {
119
+ fn recv_file (stream : & UnixStream ) -> std :: io :: Result <File > {
117
120
// TODO: expose CMSG_SPACE() in a user-friendly way.
118
121
const ANCILLARY_CAPACITY : usize = 100 ;
119
122
120
- let mut ancillary = AncillaryData :: with_capacity (ANCILLARY_CAPACITY );
123
+ let mut ancillary_buf = AncillaryDataBuf :: with_capacity (ANCILLARY_CAPACITY );
124
+ let mut ancillary = ancillary_buf . to_ancillary_data ();
125
+
121
126
let mut buf = [0u8 ; 1 ];
122
127
MessageReceiver :: new (stream , & mut buf )
123
128
. ancillary_data (& mut ancillary )
124
129
. recv ()? ;
125
130
126
- // TODO: error handling (std::io::Error if not enough FDs returned)
127
- let mut owned_fds = ancillary . take_owned_fds (). unwrap ();
128
- let sent_fd = owned_fds . swap_remove (0 );
129
- Ok (sent_fd . into ())
131
+ let mut received_fds : Vec <_ > = ancillary . received_fds (). collect ();
132
+ if received_fds . len () != 1 {
133
+ // TODO: error handling (std::io::Error if not enough FDs returned)
134
+ panic! (" didn't receive enough FDs" );
135
+ }
136
+ let received_fd = received_fds . pop (). unwrap ();
137
+ Ok (File :: from (received_fd ))
130
138
}
131
139
```
132
140
@@ -166,7 +174,7 @@ inspected and iterated over to obtain `ControlMessage` values.
166
174
167
175
168
176
``` rust
169
- struct ControlMessages { ... } ;
177
+ struct ControlMessages ;
170
178
171
179
impl ControlMessages {
172
180
fn from_bytes (bytes : & [u8 ]) -> & ControlMessages ;
@@ -180,7 +188,7 @@ impl<'a> IntoIterator for &'a ControlMessages {
180
188
type IntoIter = ControlMessagesIter <'a >;
181
189
}
182
190
183
- struct ControlMessagesIter <'a > { ... }
191
+ struct ControlMessagesIter <'a >;
184
192
185
193
impl <'a > Iterator for ControlMessagesIter <'a > {
186
194
type Item = ControlMessage <'a >;
@@ -192,106 +200,188 @@ impl ControlMessagesIter<'a> {
192
200
}
193
201
```
194
202
195
- A ` ControlMessagesBuf ` is the owned variant of ` ControlMessages ` . It exposes a
196
- subset of the ` Vec ` capacity management functions, with a public API that only
197
- allows operations that won't reduce its length (since that would risk losing
198
- information about received file descriptors).
203
+ ## Ancillary data
204
+
205
+ ### ` struct AncillaryData `
206
+
207
+ An ` AncillaryData ` is responsible for combining the serialized control messages
208
+ with a notion of file descriptor ownership, ensuring that (1) borrowed FDs live
209
+ long enough to be sent, and (2) received FDs aren't leaked.
199
210
200
211
``` rust
201
- struct ControlMessagesBuf ;
212
+ struct AncillaryData <' a , ' fd > ;
202
213
203
- impl ControlMessagesBuf {
204
- fn new () -> ControlMessagesBuf ;
205
- fn with_capacity (capacity : usize ) -> ControlMessagesBuf ;
214
+ impl Drop for AncillaryData ;
206
215
207
- fn capacity (& self ) -> usize ;
216
+ impl AncillaryData <'a , 'fd > {
217
+ fn new (
218
+ control_messages_buf : & 'a mut [MaybeUninit <u8 >],
219
+ ) -> AncillaryData <'a , 'fd >;
208
220
209
- fn push (& mut self , message : impl Into <ControlMessage <'_ >>);
221
+ // returns initialized portion of `control_messages_buf`.
222
+ fn control_messages (& self ) -> & ControlMessages ;
210
223
211
- fn reserve (& mut self , additional : usize );
224
+ // copy a control message into the ancillary data; error on out-of-capacity.
225
+ fn add_control_message (
226
+ & mut self ,
227
+ control_message : impl Into <ControlMessage <'_ >>,
228
+ ) -> Result <(), AncillaryDataNoCapacity >;
212
229
213
- fn try_reserve (
230
+ // Add an `SCM_RIGHTS` control message with given borrowed FDs.
231
+ fn add_file_descriptors (
214
232
& mut self ,
215
- additional : usize ,
216
- ) -> Result <(), TryReserveError >;
233
+ borrowed_fds : & [ BorrowedFd <' fd >] ,
234
+ ) -> Result <(), AncillaryDataNoCapacity >;
217
235
218
- fn reserve_exact (& mut self , additional : usize );
236
+ // Transfers ownership of received FDs to the iterator.
237
+ fn received_fds (& mut self ) -> AncillaryDataReceivedFds <'_ >;
219
238
220
- fn try_reserve_exact (
221
- & mut self ,
222
- additional : usize
223
- ) -> Result <(), TryReserveError >
224
- }
239
+ // Obtain a mutable buffer usable as the `msg_control` pointer in a call
240
+ // to `sendmsg()` or `recvmsg()`.
241
+ fn control_messages_buf (& mut self ) -> Option <& mut [u8 ]>;
225
242
226
- impl AsRef <ControlMessages > for ControlMessagesBuf ;
243
+ // Update the control messages buffer length according to the result of
244
+ // calling `sendmsg()` or `recvmsg()`.
245
+ fn set_control_messages_len (& mut self , len : usize );
227
246
228
- impl Deref for ControlMessagesBuf {
229
- type Target = ControlMessages ;
247
+ // Scan the control messages buffer for `SCM_RIGHTS` and take ownership of
248
+ // any file descriptors found within.
249
+ unsafe fn take_ownership_of_scm_rights (& mut self );
230
250
}
231
251
232
- impl <'a > IntoIterator for & 'a ControlMessagesBuf {
233
- type Item = ControlMessage <'a >;
234
- type IntoIter = ControlMessagesIter <'a >;
235
- }
252
+ struct AncillaryDataReceivedFds <'a >;
236
253
237
- impl Extend <ControlMessage <'_ >> for ControlMessagesBuf ;
238
- impl Extend <& ControlMessage <'_ >> for ControlMessagesBuf ;
254
+ impl <'a > Iterator for AncillaryDataReceivedFds <'a > {
255
+ type Item = OwnedFd ;
256
+ }
239
257
```
240
258
241
- ## Ancillary data
259
+ #### ` fn AncillaryData::received_fds `
260
+
261
+ By default an ` AncillaryData ` has no received FDs, and this method will
262
+ ignore FDs added via ` add_file_descriptors ` . The iterator holds a mutable
263
+ borrow on the ` AncillaryData ` , and will close any unclaimed FDs when
264
+ it's dropped.
265
+
266
+ Internally, the iteration works by scanning the control message buffer
267
+ for ` SCM_RIGHTS ` . As the iteration proceeds the buffer is mutated to set
268
+ the "taken" FDs to ` -1 ` (a sentinal value for Unix file descriptors).
269
+
270
+ #### ` fn AncillaryData::control_messages_buf `
271
+
272
+ The returned slice, if not ` None ` , will have the same length as
273
+ ` control_messages_buf ` passed to ` AncillaryData::new() ` . Any portion of the
274
+ buffer not initialized by ` add_control_message ` or ` add_file_descriptors ` will
275
+ be zeroed.
276
+
277
+ When this method is called the ` AncillaryData ` will have its control
278
+ messages length cleared, so a subsequent call to ` control_messages_buf() `
279
+ returns ` None ` . If the ` AncillaryData ` contains received FDs, they will
280
+ be closed.
281
+
282
+ #### ` fn AncillaryData::set_control_messages_len `
283
+
284
+ Does not take ownership of FDs in any ` SCM_RIGHTS ` control messages that
285
+ might exist within the new buffer length.
286
+
287
+ ** Panics** :
288
+ * if ` len > control_messages_buf.len() `
289
+ * if ` control_messages_buf() ` hasn't been called to clear the length.
290
+
291
+ The second panic condition means that creating an ` AncillaryData ` and then
292
+ immediately calling ` set_control_messages_len ` will panic to avoid potentially
293
+ reading uninitialized data.
242
294
243
- The ` AncillaryData ` struct is responsible for combining the serialized control
244
- messages with a notion of file descriptor ownership, ensuring that (1) borrowed
245
- FDs live long enough to be sent, and (2) received FDs aren't leaked.
295
+ Also, calling ` set_control_messages_len() ` twice without an intervening
296
+ ` control_messages_buf() ` will panic to avoid leaking received FDs.
297
+
298
+ #### ` fn AncillaryData::take_ownership_of_scm_rights `
299
+
300
+ ** Panics** :
301
+ * if ` set_control_messages_len() ` hasn't been called since the most
302
+ recent call to ` control_messages_buf() ` .
303
+ * That method is what keeps track of how much of the received buffer
304
+ contains owned FDs, and trying to take ownership of ` SCM_RIGHTS ` without
305
+ knowing how much to scan is almost certainly a programming error.
306
+
307
+ ** Safety** : contents of control messages become ` OwnedFd ` , so this has all
308
+ the safety requirements of ` OwnedFd::from_raw_fd() ` .
309
+
310
+ ### ` struct AncillaryDataBuf `
311
+
312
+ An ` AncillaryDataBuf ` is an owned variant of ` AncillaryData ` , using heap
313
+ allocation (an internal ` Vec<u8> ` ). It exposes a subset of the ` Vec ` capacity
314
+ management methods.
246
315
247
316
``` rust
248
- struct AncillaryData <'fd >;
317
+ struct AncillaryDataBuf <'fd >;
318
+
319
+ impl AncillaryDataBuf <'fd > {
320
+ fn new () -> AncillaryDataBuf <'static >;
321
+ fn with_capacity (capacity : usize ) -> AncillaryDataBuf <'static >;
249
322
250
- impl AncillaryData <'fd > {
251
- fn new () -> AncillaryData <'fd >;
252
- fn with_capacity (capacity : usize ) -> AncillaryData <'fd >;
323
+ fn capacity (& self ) -> usize ;
253
324
254
325
fn control_messages (& self ) -> & ControlMessages ;
255
- fn control_messages_mut (& mut self ) -> & mut ControlMessagesBuf ;
256
326
257
- // Helper for control_messages_mut().push(message.into())
258
- fn add_control_message <'b >(& mut self , message : impl Into <ControlMessage <'b >>);
327
+ // copy a control message into the ancillary data; panic on alloc failure.
328
+ fn add_control_message (
329
+ & mut self ,
330
+ control_message : impl Into <ControlMessage <'_ >>,
331
+ );
332
+
333
+ // Add an `SCM_RIGHTS` control message with given borrowed FDs; panic on
334
+ // alloc failure.
335
+ fn add_file_descriptors (& mut self , borrowed_fds : & [BorrowedFd <'fd >]);
259
336
260
- // Adds FDs to the control messages buffer so they can be sent .
261
- fn add_file_descriptors ( & mut self , borrowed_fds : & impl AsRef <[ BorrowedFd <' fd >]>) ;
337
+ // Used to obtain `AncillaryData` for passing to send/recv calls .
338
+ fn to_ancillary_data <' a >( & ' a mut self ) -> AncillaryData <' a , ' fd >;
262
339
263
- // Clears the control message buffer and drops owned FDs.
340
+ // Clears the control message buffer, without affecting capacity.
341
+ //
342
+ // This will not leak FDs because the `AncillaryData` type holds a mutable
343
+ // reference to the `AncillaryDataBuf`, so if `clear()` is called then there
344
+ // are no outstanding `AncillaryData`s and thus no received FDs.
264
345
fn clear (& mut self );
265
346
266
- // Takes ownership of FDs received from the socket. After the FDs are
267
- // taken, returns `None` until the next call to `finish_recvmsg`.
268
- fn take_owned_fds (& mut self ) -> Option <Vec <OwnedFd >>;
347
+ // as in Vec
348
+ fn reserve (& mut self , capacity : usize );
349
+ // as in Vec
350
+ fn reserve_exact (& mut self , capacity : usize );
269
351
270
- // API for sockets performing `recvmsg`:
271
- //
272
- // 1. Call `start_recvmsg` to obtain a mutable buffer to pass into the
273
- // `cmsghdr`. The buffer len equals `control_messages().capacity()`.
274
- //
275
- // 2. Call `finish_recvmsg` to update the control messages buffer length
276
- // according to the new `cmsghdr` length. This function will also take
277
- // ownership of FDs received from the socket.
278
- //
279
- // The caller is responsible for ensuring that the control messages buffer
280
- // content and length are provided by a successful call to `recvmsg`.
281
- fn start_recvmsg (& mut self ) -> Option <& mut [u8 ]>;
282
- unsafe fn finish_recvmsg (& mut self , control_messages_len : usize );
283
-
284
- // API for sockets performing `sendmsg` -- basically the same as the
285
- // `recvmsg` version, but doesn't scan the message buffer for `SCM_RIGHTS`
286
- // to take ownership of.
287
- //
288
- // The caller is responsible for ensuring that the control messages buffer
289
- // content and length are provided by a successful call to `sendmsg`.
290
- fn start_sendmsg (& mut self ) -> Option <& mut [u8 ]>;
291
- unsafe fn finish_sendmsg (& mut self , control_messages_len : usize );
352
+ // as in Vec
353
+ fn try_reserve (
354
+ & mut self ,
355
+ capacity : usize ,
356
+ ) -> Result <(), TryReserveError >;
357
+
358
+ // as in Vec
359
+ fn try_reserve_exact (
360
+ & mut self ,
361
+ capacity : usize ,
362
+ ) -> Result <(), TryReserveError >;
292
363
}
364
+
365
+ impl Extend <ControlMessage <'_ >> for AncillaryDataBuf ;
366
+ impl Extend <& ControlMessage <'_ >> for AncillaryDataBuf ;
293
367
```
294
368
369
+ #### ` fn AncillaryDataBuf::to_ancillary_data `
370
+
371
+ The returned ` AncillaryData ` will be initialized with the same control messages,
372
+ capacity, and borrowed FDs as the ` AncillaryDataBuf ` . Specifically, it's as if
373
+ the entire capacity of the internal ` Vec ` is passed to ` AncillaryData::new() ` .
374
+
375
+ When the ` AncillaryData ` is dropped its received FDs will be closed. The
376
+ ` AncillaryDataBuf ` does not retain ownership of received FDs. Otherwise the
377
+ API to reuse an ` AncillaryDataBuf ` between calls gets really complicated.
378
+
379
+ The only subtle part of ` to_ancillary_data ` is that it transfers logical
380
+ ownership of the control messages, but not the control messages * buffer* . So
381
+ after calling this function the ` AncillaryDataBuf::control_messages() ` method
382
+ returns an empty ` &ControlMessages ` , and any calls to ` add_control_message ` or
383
+ ` add_file_descriptors ` . It's basically an implicit ` clear() ` .
384
+
295
385
## Sending messages
296
386
297
387
### The ` SendMessage ` and ` SendMessageTo ` traits
@@ -306,7 +396,7 @@ trait SendMessage {
306
396
fn send_message (
307
397
& self ,
308
398
bufs : & [IoSlice <'_ >],
309
- ancillary_data : & mut AncillaryData <'_ >,
399
+ ancillary_data : & mut AncillaryData <'_ , ' _ >,
310
400
options : SendOptions ,
311
401
) -> io :: Result <usize >;
312
402
}
@@ -318,7 +408,7 @@ trait SendMessageTo {
318
408
& self ,
319
409
addr : & Self :: SocketAddr ,
320
410
bufs : & [IoSlice <'_ >],
321
- ancillary_data : & mut AncillaryData <'_ >,
411
+ ancillary_data : & mut AncillaryData <'_ , ' _ >,
322
412
options : SendOptions ,
323
413
) -> io :: Result <usize >;
324
414
}
@@ -389,7 +479,7 @@ impl<S, 'a> MessageSender<S, 'a> {
389
479
390
480
fn ancillary_data (
391
481
& mut self ,
392
- ancillary_data : & 'a mut AncillaryData <'a >,
482
+ ancillary_data : & 'a mut AncillaryData <'_ , ' _ >,
393
483
) -> & mut MessageSender <S , 'a >;
394
484
395
485
fn options (
@@ -421,7 +511,7 @@ trait RecvMessage {
421
511
fn recv_message (
422
512
& self ,
423
513
bufs : & mut [IoSliceMut <'_ >],
424
- ancillary_data : & mut AncillaryData <'_ >,
514
+ ancillary_data : & mut AncillaryData <'_ , ' _ >,
425
515
options : RecvOptions ,
426
516
) -> io :: Result <(usize , RecvResult )>;
427
517
}
@@ -432,7 +522,7 @@ trait RecvMessageFrom {
432
522
fn recv_message_from (
433
523
& self ,
434
524
bufs : & mut [IoSliceMut <'_ >],
435
- ancillary_data : & mut AncillaryData <'_ >,
525
+ ancillary_data : & mut AncillaryData <'_ , ' _ >,
436
526
options : RecvOptions ,
437
527
) -> io :: Result <(usize , RecvResult , Self :: SocketAddr )>;
438
528
}
@@ -534,7 +624,7 @@ impl<S, 'a> MessageReceiver<S, 'a> {
534
624
535
625
fn ancillary_data (
536
626
& mut self ,
537
- ancillary_data : & 'a mut AncillaryData <'a >,
627
+ ancillary_data : & 'a mut AncillaryData <'_ , ' _ >,
538
628
) -> & mut MessageReceiver <S , 'a >;
539
629
540
630
fn options (
@@ -740,10 +830,8 @@ This RFC would significantly expand the public API surface of `os::unix::net`.
740
830
The handling of file descriptor ownership is more complex than the current
741
831
implementation, which uses ` RawFd ` . There may be soundness issues in the
742
832
conversion of ` SCM_RIGHTS ` into a ` Vec<OwnedFd> ` , for example if a way is
743
- found to call ` finish_recvmsg ` on a user-defined buffer from safe code.
744
-
745
- The API described in this RFC doesn't provide a way for a stack-allocated
746
- buffer to be used as ` AncillaryData ` capacity.
833
+ found to call ` take_ownership_of_scm_rights ` on a user-defined buffer from
834
+ safe code.
747
835
748
836
# Rationale and alternatives
749
837
[ rationale-and-alternatives ] : #rationale-and-alternatives
0 commit comments