@@ -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,187 @@ 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 ` . Any portion of the buffer not initialized by
274
+ ` add_control_message ` or ` add_file_descriptors ` will be zeroed.
275
+
276
+ When this method is called the ` AncillaryData ` will have its control
277
+ messages length cleared, so a subsequent call to ` control_messages_buf() `
278
+ returns ` None ` . If the ` AncillaryData ` contains received FDs, they will
279
+ be closed.
280
+
281
+ #### ` fn AncillaryData::set_control_messages_len `
282
+
283
+ Does not take ownership of FDs in any ` SCM_RIGHTS ` control messages that
284
+ might exist within the new buffer length.
285
+
286
+ ** Panics** :
287
+ * if ` len > control_messages_buf.len() `
288
+ * if ` control_messages_buf() ` hasn't been called to clear the length.
289
+
290
+ The second panic condition means that creating an ` AncillaryData ` and then
291
+ immediately calling ` set_control_messages_len ` will panic to avoid potentially
292
+ reading uninitialized data.
242
293
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.
294
+ Also, calling ` set_control_messages_len() ` twice without an intervening
295
+ ` control_messages_buf() ` will panic to avoid leaking received FDs.
296
+
297
+ #### ` fn AncillaryData::take_ownership_of_scm_rights `
298
+
299
+ ** Panics** :
300
+ * if ` set_control_messages_len() ` hasn't been called since the most
301
+ recent call to ` control_messages_buf() ` .
302
+ * That method is what keeps track of how much of the received buffer
303
+ contains owned FDs, and trying to take ownership of ` SCM_RIGHTS ` without
304
+ knowing how much to scan is almost certainly a programming error.
305
+
306
+ ** Safety** : contents of control messages become ` OwnedFd ` , so this has all
307
+ the safety requirements of ` OwnedFd::from_raw_fd() ` .
308
+
309
+ ### ` struct AncillaryDataBuf `
310
+
311
+ An ` AncillaryDataBuf ` is an owned variant of ` AncillaryData ` , using heap
312
+ allocation (an internal ` Vec<u8> ` ). It exposes a subset of the ` Vec ` capacity
313
+ management methods.
246
314
247
315
``` rust
248
- struct AncillaryData <'fd >;
316
+ struct AncillaryDataBuf <'fd >;
317
+
318
+ impl AncillaryDataBuf <'fd > {
319
+ fn new () -> AncillaryDataBuf <'static >;
320
+ fn with_capacity (capacity : usize ) -> AncillaryDataBuf <'static >;
249
321
250
- impl AncillaryData <'fd > {
251
- fn new () -> AncillaryData <'fd >;
252
- fn with_capacity (capacity : usize ) -> AncillaryData <'fd >;
322
+ fn capacity (& self ) -> usize ;
253
323
254
324
fn control_messages (& self ) -> & ControlMessages ;
255
- fn control_messages_mut (& mut self ) -> & mut ControlMessagesBuf ;
256
325
257
- // Helper for control_messages_mut().push(message.into())
258
- fn add_control_message <'b >(& mut self , message : impl Into <ControlMessage <'b >>);
326
+ // copy a control message into the ancillary data; panic on alloc failure.
327
+ fn add_control_message (
328
+ & mut self ,
329
+ control_message : impl Into <ControlMessage <'_ >>,
330
+ );
331
+
332
+ // Add an `SCM_RIGHTS` control message with given borrowed FDs; panic on
333
+ // alloc failure.
334
+ fn add_file_descriptors (& mut self , borrowed_fds : & [BorrowedFd <'fd >]);
259
335
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 >]>) ;
336
+ // Used to obtain `AncillaryData` for passing to send/recv calls .
337
+ fn to_ancillary_data <' a >( & ' a mut self ) -> AncillaryData <' a , ' fd >;
262
338
263
- // Clears the control message buffer and drops owned FDs.
339
+ // Clears the control message buffer, without affecting capacity.
340
+ //
341
+ // This will not leak FDs because the `AncillaryData` type holds a mutable
342
+ // reference to the `AncillaryDataBuf`, so if `clear()` is called then there
343
+ // are no outstanding `AncillaryData`s and thus no received FDs.
264
344
fn clear (& mut self );
265
345
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 >>;
346
+ // as in Vec
347
+ fn reserve (& mut self , capacity : usize );
348
+ // as in Vec
349
+ fn reserve_exact (& mut self , capacity : usize );
269
350
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 );
351
+ // as in Vec
352
+ fn try_reserve (
353
+ & mut self ,
354
+ capacity : usize ,
355
+ ) -> Result <(), TryReserveError >;
356
+
357
+ // as in Vec
358
+ fn try_reserve_exact (
359
+ & mut self ,
360
+ capacity : usize ,
361
+ ) -> Result <(), TryReserveError >;
292
362
}
363
+
364
+ impl Extend <ControlMessage <'_ >> for AncillaryDataBuf ;
365
+ impl Extend <& ControlMessage <'_ >> for AncillaryDataBuf ;
293
366
```
294
367
368
+ #### ` fn AncillaryDataBuf::to_ancillary_data `
369
+
370
+ The returned ` AncillaryData ` will be initialized with the same control messages,
371
+ capacity, and borrowed FDs as the ` AncillaryDataBuf ` . Specifically, it's as if
372
+ the entire capacity of the internal ` Vec ` is passed to ` AncillaryData::new() ` .
373
+
374
+ When the ` AncillaryData ` is dropped its received FDs will be closed. The
375
+ ` AncillaryDataBuf ` does not retain ownership of received FDs. Otherwise the
376
+ API to reuse an ` AncillaryDataBuf ` between calls gets really complicated.
377
+
378
+ The only subtle part of ` to_ancillary_data ` is that it transfers logical
379
+ ownership of the control messages, but not the control messages * buffer* . So
380
+ after calling this function the ` AncillaryDataBuf::control_messages() ` method
381
+ returns an empty ` &ControlMessages ` , and any calls to ` add_control_message ` or
382
+ ` add_file_descriptors ` . It's basically an implicit ` clear() ` .
383
+
295
384
## Sending messages
296
385
297
386
### The ` SendMessage ` and ` SendMessageTo ` traits
@@ -306,7 +395,7 @@ trait SendMessage {
306
395
fn send_message (
307
396
& self ,
308
397
bufs : & [IoSlice <'_ >],
309
- ancillary_data : & mut AncillaryData <'_ >,
398
+ ancillary_data : & mut AncillaryData <'_ , ' _ >,
310
399
options : SendOptions ,
311
400
) -> io :: Result <usize >;
312
401
}
@@ -318,7 +407,7 @@ trait SendMessageTo {
318
407
& self ,
319
408
addr : & Self :: SocketAddr ,
320
409
bufs : & [IoSlice <'_ >],
321
- ancillary_data : & mut AncillaryData <'_ >,
410
+ ancillary_data : & mut AncillaryData <'_ , ' _ >,
322
411
options : SendOptions ,
323
412
) -> io :: Result <usize >;
324
413
}
@@ -389,7 +478,7 @@ impl<S, 'a> MessageSender<S, 'a> {
389
478
390
479
fn ancillary_data (
391
480
& mut self ,
392
- ancillary_data : & 'a mut AncillaryData <'a >,
481
+ ancillary_data : & 'a mut AncillaryData <'_ , ' _ >,
393
482
) -> & mut MessageSender <S , 'a >;
394
483
395
484
fn options (
@@ -421,7 +510,7 @@ trait RecvMessage {
421
510
fn recv_message (
422
511
& self ,
423
512
bufs : & mut [IoSliceMut <'_ >],
424
- ancillary_data : & mut AncillaryData <'_ >,
513
+ ancillary_data : & mut AncillaryData <'_ , ' _ >,
425
514
options : RecvOptions ,
426
515
) -> io :: Result <(usize , RecvResult )>;
427
516
}
@@ -432,7 +521,7 @@ trait RecvMessageFrom {
432
521
fn recv_message_from (
433
522
& self ,
434
523
bufs : & mut [IoSliceMut <'_ >],
435
- ancillary_data : & mut AncillaryData <'_ >,
524
+ ancillary_data : & mut AncillaryData <'_ , ' _ >,
436
525
options : RecvOptions ,
437
526
) -> io :: Result <(usize , RecvResult , Self :: SocketAddr )>;
438
527
}
@@ -534,7 +623,7 @@ impl<S, 'a> MessageReceiver<S, 'a> {
534
623
535
624
fn ancillary_data (
536
625
& mut self ,
537
- ancillary_data : & 'a mut AncillaryData <'a >,
626
+ ancillary_data : & 'a mut AncillaryData <'_ , ' _ >,
538
627
) -> & mut MessageReceiver <S , 'a >;
539
628
540
629
fn options (
@@ -740,10 +829,8 @@ This RFC would significantly expand the public API surface of `os::unix::net`.
740
829
The handling of file descriptor ownership is more complex than the current
741
830
implementation, which uses ` RawFd ` . There may be soundness issues in the
742
831
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.
832
+ found to call ` take_ownership_of_scm_rights ` on a user-defined buffer from
833
+ safe code.
747
834
748
835
# Rationale and alternatives
749
836
[ rationale-and-alternatives ] : #rationale-and-alternatives
0 commit comments