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