• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
2 // SPDX-License-Identifier: Apache-2.0
3 
4 //! Common data structures for listener and endpoint.
5 
6 cfg_if::cfg_if! {
7     if #[cfg(unix)] {
8         pub mod socket;
9         #[cfg(feature = "vfio-device")]
10         pub mod vfio;
11         mod unix;
12     } else if #[cfg(windows)] {
13         mod tube;
14         pub use tube::TubeEndpoint;
15         mod windows;
16     }
17 }
18 
19 use std::fs::File;
20 use std::io::IoSlice;
21 use std::io::IoSliceMut;
22 use std::mem;
23 use std::path::Path;
24 
25 use base::RawDescriptor;
26 use data_model::DataInit;
27 
28 use crate::connection::Req;
29 use crate::message::*;
30 use crate::Error;
31 use crate::Result;
32 
33 /// Listener for accepting connections.
34 pub trait Listener: Sized {
35     /// Type of an object created when a connection is accepted.
36     type Connection;
37     /// Type of endpoint created when a connection is accepted.
38     type Endpoint;
39 
40     /// Accept an incoming connection.
accept(&mut self) -> Result<Option<Self::Endpoint>>41     fn accept(&mut self) -> Result<Option<Self::Endpoint>>;
42 
43     /// Change blocking status on the listener.
set_nonblocking(&self, block: bool) -> Result<()>44     fn set_nonblocking(&self, block: bool) -> Result<()>;
45 }
46 
47 /// Abstracts a vhost-user connection and related operations.
48 pub trait Endpoint<R: Req>: Send {
49     /// Create a new stream by connecting to server at `str`.
connect<P: AsRef<Path>>(path: P) -> Result<Self> where Self: Sized50     fn connect<P: AsRef<Path>>(path: P) -> Result<Self>
51     where
52         Self: Sized;
53 
54     /// Sends bytes from scatter-gather vectors with optional attached file descriptors.
55     ///
56     /// # Return:
57     /// * - number of bytes sent on success
send_iovec(&mut self, iovs: &[IoSlice], fds: Option<&[RawDescriptor]>) -> Result<usize>58     fn send_iovec(&mut self, iovs: &[IoSlice], fds: Option<&[RawDescriptor]>) -> Result<usize>;
59 
60     /// Reads bytes into the given scatter/gather vectors with optional attached file.
61     ///
62     /// # Arguements
63     /// * `bufs` - A slice of buffers to store received data.
64     /// * `allow_fd` - Indicates whether we can receive FDs.
65     ///
66     /// # Return:
67     /// * - (number of bytes received, [received files]) on success.
68     /// * - `Error::Disconnect` if the client closed.
recv_into_bufs( &mut self, bufs: &mut [IoSliceMut], allow_fd: bool, ) -> Result<(usize, Option<Vec<File>>)>69     fn recv_into_bufs(
70         &mut self,
71         bufs: &mut [IoSliceMut],
72         allow_fd: bool,
73     ) -> Result<(usize, Option<Vec<File>>)>;
74 
75     /// Constructs the slave request endpoint for self.
76     ///
77     /// # Arguments
78     /// * `files` - Files from which to create the endpoint
create_slave_request_endpoint( &mut self, files: Option<Vec<File>>, ) -> Result<Box<dyn Endpoint<SlaveReq>>>79     fn create_slave_request_endpoint(
80         &mut self,
81         files: Option<Vec<File>>,
82     ) -> Result<Box<dyn Endpoint<SlaveReq>>>;
83 }
84 
85 // Advance the internal cursor of the slices.
86 // This is same with a nightly API `IoSlice::advance_slices` but for `&[u8]`.
advance_slices(bufs: &mut &mut [&[u8]], mut count: usize)87 fn advance_slices(bufs: &mut &mut [&[u8]], mut count: usize) {
88     use std::mem::take;
89 
90     let mut idx = 0;
91     for b in bufs.iter() {
92         if count < b.len() {
93             break;
94         }
95         count -= b.len();
96         idx += 1;
97     }
98     *bufs = &mut take(bufs)[idx..];
99     if !bufs.is_empty() {
100         bufs[0] = &bufs[0][count..];
101     }
102 }
103 
104 // Advance the internal cursor of the slices.
105 // This is same with a nightly API `IoSliceMut::advance_slices` but for `&mut [u8]`.
advance_slices_mut(bufs: &mut &mut [&mut [u8]], mut count: usize)106 fn advance_slices_mut(bufs: &mut &mut [&mut [u8]], mut count: usize) {
107     use std::mem::take;
108 
109     let mut idx = 0;
110     for b in bufs.iter() {
111         if count < b.len() {
112             break;
113         }
114         count -= b.len();
115         idx += 1;
116     }
117     *bufs = &mut take(bufs)[idx..];
118     if !bufs.is_empty() {
119         let slice = take(&mut bufs[0]);
120         let (_, remaining) = slice.split_at_mut(count);
121         bufs[0] = remaining;
122     }
123 }
124 
125 /// Abstracts VVU message parsing, sending and receiving.
126 pub trait EndpointExt<R: Req>: Endpoint<R> {
127     /// Sends all bytes from scatter-gather vectors with optional attached file descriptors. Will
128     /// loop until all data has been transfered.
129     ///
130     /// # Return:
131     /// * - number of bytes sent on success
132     ///
133     /// # TODO
134     /// This function takes a slice of `&[u8]` instead of `IoSlice` because the internal
135     /// cursor needs to be moved by `advance_slices()`.
136     /// Once `IoSlice::advance_slices()` becomes stable, this should be updated.
137     /// <https://github.com/rust-lang/rust/issues/62726>.
send_iovec_all( &mut self, mut iovs: &mut [&[u8]], mut fds: Option<&[RawDescriptor]>, ) -> Result<usize>138     fn send_iovec_all(
139         &mut self,
140         mut iovs: &mut [&[u8]],
141         mut fds: Option<&[RawDescriptor]>,
142     ) -> Result<usize> {
143         // Guarantee that `iovs` becomes empty if it doesn't contain any data.
144         advance_slices(&mut iovs, 0);
145 
146         let mut data_sent = 0;
147         while !iovs.is_empty() {
148             let iovec: Vec<_> = iovs.iter_mut().map(|i| IoSlice::new(i)).collect();
149             match self.send_iovec(&iovec, fds) {
150                 Ok(0) => {
151                     break;
152                 }
153                 Ok(n) => {
154                     data_sent += n;
155                     fds = None;
156                     advance_slices(&mut iovs, n);
157                 }
158                 Err(e) => match e {
159                     Error::SocketRetry(_) => {}
160                     _ => return Err(e),
161                 },
162             }
163         }
164         Ok(data_sent)
165     }
166 
167     /// Sends bytes from a slice with optional attached file descriptors.
168     ///
169     /// # Return:
170     /// * - number of bytes sent on success
171     #[cfg(test)]
send_slice(&mut self, data: IoSlice, fds: Option<&[RawDescriptor]>) -> Result<usize>172     fn send_slice(&mut self, data: IoSlice, fds: Option<&[RawDescriptor]>) -> Result<usize> {
173         self.send_iovec(&[data], fds)
174     }
175 
176     /// Sends a header-only message with optional attached file descriptors.
177     ///
178     /// # Return:
179     /// * - number of bytes sent on success
180     /// * - PartialMessage: received a partial message.
181     /// * - backend specific errors
send_header( &mut self, hdr: &VhostUserMsgHeader<R>, fds: Option<&[RawDescriptor]>, ) -> Result<()>182     fn send_header(
183         &mut self,
184         hdr: &VhostUserMsgHeader<R>,
185         fds: Option<&[RawDescriptor]>,
186     ) -> Result<()> {
187         let mut iovs = [hdr.as_slice()];
188         let bytes = self.send_iovec_all(&mut iovs[..], fds)?;
189         if bytes != mem::size_of::<VhostUserMsgHeader<R>>() {
190             return Err(Error::PartialMessage);
191         }
192         Ok(())
193     }
194 
195     /// Send a message with header and body. Optional file descriptors may be attached to
196     /// the message.
197     ///
198     /// # Return:
199     /// * - number of bytes sent on success
200     /// * - OversizedMsg: message size is too big.
201     /// * - PartialMessage: received a partial message.
202     /// * - backend specific errors
send_message<T: Sized + DataInit>( &mut self, hdr: &VhostUserMsgHeader<R>, body: &T, fds: Option<&[RawDescriptor]>, ) -> Result<()>203     fn send_message<T: Sized + DataInit>(
204         &mut self,
205         hdr: &VhostUserMsgHeader<R>,
206         body: &T,
207         fds: Option<&[RawDescriptor]>,
208     ) -> Result<()> {
209         if mem::size_of::<T>() > MAX_MSG_SIZE {
210             return Err(Error::OversizedMsg);
211         }
212 
213         // We send the header and the body separately here. This is necessary on Windows. Otherwise
214         // the recv side cannot read the header independently (the transport is message oriented).
215         let mut bytes = self.send_iovec_all(&mut [hdr.as_slice()], fds)?;
216         bytes += self.send_iovec_all(&mut [body.as_slice()], None)?;
217         if bytes != mem::size_of::<VhostUserMsgHeader<R>>() + mem::size_of::<T>() {
218             return Err(Error::PartialMessage);
219         }
220         Ok(())
221     }
222 
223     /// Send a message with header, body and payload. Optional file descriptors
224     /// may also be attached to the message.
225     ///
226     /// # Return:
227     /// * - number of bytes sent on success
228     /// * - OversizedMsg: message size is too big.
229     /// * - PartialMessage: received a partial message.
230     /// * - IncorrectFds: wrong number of attached fds.
231     /// * - backend specific errors
send_message_with_payload<T: Sized + DataInit>( &mut self, hdr: &VhostUserMsgHeader<R>, body: &T, payload: &[u8], fds: Option<&[RawDescriptor]>, ) -> Result<()>232     fn send_message_with_payload<T: Sized + DataInit>(
233         &mut self,
234         hdr: &VhostUserMsgHeader<R>,
235         body: &T,
236         payload: &[u8],
237         fds: Option<&[RawDescriptor]>,
238     ) -> Result<()> {
239         let len = payload.len();
240         if mem::size_of::<T>() > MAX_MSG_SIZE {
241             return Err(Error::OversizedMsg);
242         }
243         if len > MAX_MSG_SIZE - mem::size_of::<T>() {
244             return Err(Error::OversizedMsg);
245         }
246         if let Some(fd_arr) = fds {
247             if fd_arr.len() > MAX_ATTACHED_FD_ENTRIES {
248                 return Err(Error::IncorrectFds);
249             }
250         }
251 
252         let total = mem::size_of::<VhostUserMsgHeader<R>>() + mem::size_of::<T>() + len;
253 
254         // We send the header and the body separately here. This is necessary on Windows. Otherwise
255         // the recv side cannot read the header independently (the transport is message oriented).
256         let mut len = self.send_iovec_all(&mut [hdr.as_slice()], fds)?;
257         len += self.send_iovec_all(&mut [body.as_slice(), payload], None)?;
258 
259         if len != total {
260             return Err(Error::PartialMessage);
261         }
262         Ok(())
263     }
264 
265     /// Reads `len` bytes at most.
266     ///
267     /// # Return:
268     /// * - (number of bytes received, buf) on success
recv_data(&mut self, len: usize) -> Result<Vec<u8>>269     fn recv_data(&mut self, len: usize) -> Result<Vec<u8>> {
270         let mut buf = vec![0u8; len];
271         let (data_len, _) =
272             self.recv_into_bufs(&mut [IoSliceMut::new(&mut buf)], false /* allow_fd */)?;
273         buf.truncate(data_len);
274         Ok(buf)
275     }
276 
277     /// Reads all bytes into the given scatter/gather vectors with optional attached files. Will
278     /// loop until all data has been transferred.
279     ///
280     /// # Return:
281     /// * - (number of bytes received, [received fds]) on success
282     /// * - `Disconnect` - client is closed
283     ///
284     /// # TODO
285     /// This function takes a slice of `&mut [u8]` instead of `IoSliceMut` because the internal
286     /// cursor needs to be moved by `advance_slices_mut()`.
287     /// Once `IoSliceMut::advance_slices()` becomes stable, this should be updated.
288     /// <https://github.com/rust-lang/rust/issues/62726>.
recv_into_bufs_all( &mut self, mut bufs: &mut [&mut [u8]], ) -> Result<(usize, Option<Vec<File>>)>289     fn recv_into_bufs_all(
290         &mut self,
291         mut bufs: &mut [&mut [u8]],
292     ) -> Result<(usize, Option<Vec<File>>)> {
293         let data_total: usize = bufs.iter().map(|b| b.len()).sum();
294         let mut data_read = 0;
295         let mut rfds = None;
296 
297         while (data_total - data_read) > 0 {
298             let mut slices: Vec<IoSliceMut> = bufs.iter_mut().map(|b| IoSliceMut::new(b)).collect();
299             let res = self.recv_into_bufs(&mut slices, true);
300             match res {
301                 Ok((0, _)) => return Ok((data_read, rfds)),
302                 Ok((n, fds)) => {
303                     if data_read == 0 {
304                         rfds = fds;
305                     }
306                     data_read += n;
307                     advance_slices_mut(&mut bufs, n);
308                 }
309                 Err(e) => match e {
310                     Error::SocketRetry(_) => {}
311                     _ => return Err(e),
312                 },
313             }
314         }
315         Ok((data_read, rfds))
316     }
317 
318     /// Reads bytes into a new buffer with optional attached files. Received file descriptors are
319     /// set close-on-exec and converted to `File`.
320     ///
321     /// # Return:
322     /// * - (number of bytes received, buf, [received files]) on success.
323     /// * - backend specific errors
324     #[cfg(test)]
recv_into_buf(&mut self, buf_size: usize) -> Result<(usize, Vec<u8>, Option<Vec<File>>)>325     fn recv_into_buf(&mut self, buf_size: usize) -> Result<(usize, Vec<u8>, Option<Vec<File>>)> {
326         let mut buf = vec![0u8; buf_size];
327         let mut slices = [IoSliceMut::new(buf.as_mut_slice())];
328         let (bytes, files) = self.recv_into_bufs(&mut slices, true /* allow_fd */)?;
329         Ok((bytes, buf, files))
330     }
331 
332     /// Receive a header-only message with optional attached files.
333     /// Note, only the first MAX_ATTACHED_FD_ENTRIES file descriptors will be
334     /// accepted and all other file descriptor will be discard silently.
335     ///
336     /// # Return:
337     /// * - (message header, [received files]) on success.
338     /// * - Disconnect: the client closed the connection.
339     /// * - PartialMessage: received a partial message.
340     /// * - InvalidMessage: received a invalid message.
341     /// * - backend specific errors
recv_header(&mut self) -> Result<(VhostUserMsgHeader<R>, Option<Vec<File>>)>342     fn recv_header(&mut self) -> Result<(VhostUserMsgHeader<R>, Option<Vec<File>>)> {
343         let mut hdr = VhostUserMsgHeader::default();
344         let (bytes, files) = self.recv_into_bufs(
345             &mut [IoSliceMut::new(hdr.as_mut_slice())],
346             true, /* allow_fd */
347         )?;
348 
349         if bytes != mem::size_of::<VhostUserMsgHeader<R>>() {
350             return Err(Error::PartialMessage);
351         } else if !hdr.is_valid() {
352             return Err(Error::InvalidMessage);
353         }
354 
355         Ok((hdr, files))
356     }
357 
358     /// Receive a message with optional attached file descriptors.
359     /// Note, only the first MAX_ATTACHED_FD_ENTRIES file descriptors will be
360     /// accepted and all other file descriptor will be discard silently.
361     ///
362     /// # Return:
363     /// * - (message header, message body, [received files]) on success.
364     /// * - PartialMessage: received a partial message.
365     /// * - InvalidMessage: received a invalid message.
366     /// * - backend specific errors
recv_body<T: Sized + DataInit + Default + VhostUserMsgValidator>( &mut self, ) -> Result<(VhostUserMsgHeader<R>, T, Option<Vec<File>>)>367     fn recv_body<T: Sized + DataInit + Default + VhostUserMsgValidator>(
368         &mut self,
369     ) -> Result<(VhostUserMsgHeader<R>, T, Option<Vec<File>>)> {
370         let mut hdr = VhostUserMsgHeader::default();
371         let mut body: T = Default::default();
372         let mut slices = [hdr.as_mut_slice(), body.as_mut_slice()];
373         let (bytes, files) = self.recv_into_bufs_all(&mut slices)?;
374 
375         let total = mem::size_of::<VhostUserMsgHeader<R>>() + mem::size_of::<T>();
376         if bytes != total {
377             return Err(Error::PartialMessage);
378         } else if !hdr.is_valid() || !body.is_valid() {
379             return Err(Error::InvalidMessage);
380         }
381 
382         Ok((hdr, body, files))
383     }
384 
385     /// Receive a message with header and optional content. Callers need to
386     /// pre-allocate a big enough buffer to receive the message body and
387     /// optional payload. If there are attached file descriptor associated
388     /// with the message, the first MAX_ATTACHED_FD_ENTRIES file descriptors
389     /// will be accepted and all other file descriptor will be discard
390     /// silently.
391     ///
392     /// # Return:
393     /// * - (message header, message size, [received files]) on success.
394     /// * - PartialMessage: received a partial message.
395     /// * - InvalidMessage: received a invalid message.
396     /// * - backend specific errors
397     #[cfg(test)]
recv_body_into_buf( &mut self, buf: &mut [u8], ) -> Result<(VhostUserMsgHeader<R>, usize, Option<Vec<File>>)>398     fn recv_body_into_buf(
399         &mut self,
400         buf: &mut [u8],
401     ) -> Result<(VhostUserMsgHeader<R>, usize, Option<Vec<File>>)> {
402         let mut hdr = VhostUserMsgHeader::default();
403         let mut slices = [hdr.as_mut_slice(), buf];
404         let (bytes, files) = self.recv_into_bufs_all(&mut slices)?;
405 
406         if bytes < mem::size_of::<VhostUserMsgHeader<R>>() {
407             return Err(Error::PartialMessage);
408         } else if !hdr.is_valid() {
409             return Err(Error::InvalidMessage);
410         }
411 
412         Ok((hdr, bytes - mem::size_of::<VhostUserMsgHeader<R>>(), files))
413     }
414 
415     /// Receive a message with optional payload and attached file descriptors.
416     /// Note, only the first MAX_ATTACHED_FD_ENTRIES file descriptors will be
417     /// accepted and all other file descriptor will be discard silently.
418     ///
419     /// # Return:
420     /// * - (message header, message body, payload, [received files]) on success.
421     /// * - PartialMessage: received a partial message.
422     /// * - InvalidMessage: received a invalid message.
423     /// * - backend specific errors
424     #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))]
recv_payload_into_buf<T: Sized + DataInit + Default + VhostUserMsgValidator>( &mut self, ) -> Result<(VhostUserMsgHeader<R>, T, Vec<u8>, Option<Vec<File>>)>425     fn recv_payload_into_buf<T: Sized + DataInit + Default + VhostUserMsgValidator>(
426         &mut self,
427     ) -> Result<(VhostUserMsgHeader<R>, T, Vec<u8>, Option<Vec<File>>)> {
428         let mut hdr = VhostUserMsgHeader::default();
429         let mut body: T = Default::default();
430         let mut slices = [hdr.as_mut_slice()];
431         let (bytes, files) = self.recv_into_bufs_all(&mut slices)?;
432 
433         if bytes < mem::size_of::<VhostUserMsgHeader<R>>() {
434             return Err(Error::PartialMessage);
435         } else if !hdr.is_valid() {
436             return Err(Error::InvalidMessage);
437         }
438 
439         let payload_size = hdr.get_size() as usize - mem::size_of::<T>();
440         let mut buf: Vec<u8> = vec![0; payload_size];
441         let mut slices = [body.as_mut_slice(), buf.as_mut_slice()];
442         let (bytes, more_files) = self.recv_into_bufs_all(&mut slices)?;
443         if bytes < hdr.get_size() as usize {
444             return Err(Error::PartialMessage);
445         } else if !body.is_valid() || more_files.is_some() {
446             return Err(Error::InvalidMessage);
447         }
448 
449         Ok((hdr, body, buf, files))
450     }
451 }
452 
453 impl<R: Req, E: Endpoint<R> + ?Sized> EndpointExt<R> for E {}
454 
455 #[cfg(test)]
456 pub(crate) mod tests {
457     use super::*;
458     cfg_if::cfg_if! {
459         if #[cfg(unix)] {
460             #[cfg(feature = "vmm")]
461             pub(crate) use super::unix::tests::*;
462         } else if #[cfg(windows)] {
463             #[cfg(feature = "vmm")]
464             pub(crate) use windows::tests::*;
465         }
466     }
467 
468     #[test]
test_advance_slices()469     fn test_advance_slices() {
470         // Test case from https://doc.rust-lang.org/std/io/struct.IoSlice.html#method.advance_slices
471         let buf1 = [1; 8];
472         let buf2 = [2; 16];
473         let buf3 = [3; 8];
474         let mut bufs = &mut [&buf1[..], &buf2[..], &buf3[..]][..];
475         advance_slices(&mut bufs, 10);
476         assert_eq!(bufs[0], [2; 14].as_ref());
477         assert_eq!(bufs[1], [3; 8].as_ref());
478     }
479 
480     #[test]
test_advance_slices_mut()481     fn test_advance_slices_mut() {
482         // Test case from https://doc.rust-lang.org/std/io/struct.IoSliceMut.html#method.advance_slices
483         let mut buf1 = [1; 8];
484         let mut buf2 = [2; 16];
485         let mut buf3 = [3; 8];
486         let mut bufs = &mut [&mut buf1[..], &mut buf2[..], &mut buf3[..]][..];
487         advance_slices_mut(&mut bufs, 10);
488         assert_eq!(bufs[0], [2; 14].as_ref());
489         assert_eq!(bufs[1], [3; 8].as_ref());
490     }
491 }
492