1use std::fs::File;
5use std::mem;
6
7use base::AsRawDescriptor;
8#[cfg(windows)]
9use base::CloseNotifier;
10use base::Event;
11use base::RawDescriptor;
12use base::ReadNotifier;
13use zerocopy::FromBytes;
14use zerocopy::Immutable;
15use zerocopy::IntoBytes;
16
17use crate::backend::VhostUserMemoryRegionInfo;
18use crate::backend::VringConfigData;
19use crate::into_single_file;
20use crate::message::*;
21use crate::Connection;
22use crate::Error as VhostUserError;
23use crate::FrontendReq;
24use crate::Result as VhostUserResult;
25use crate::Result;
26use crate::SharedMemoryRegion;
27
28pub struct BackendClient {
30 connection: Connection,
31 set_need_reply: bool,
32}
33
34impl BackendClient {
35 pub fn new(connection: Connection) -> Self {
37 BackendClient {
38 connection,
39 set_need_reply: false,
40 }
41 }
42
43 pub fn set_need_reply(&mut self, enable: bool) {
47 self.set_need_reply = enable;
48 }
49
50 pub fn get_features(&mut self) -> Result<u64> {
52 let hdr = self.send_request_header(FrontendReq::GET_FEATURES, None)?;
53 let val = self.recv_reply::<VhostUserU64>(&hdr)?;
54 Ok(val.value)
55 }
56
57 pub fn set_features(&mut self, features: u64) -> Result<()> {
60 let val = VhostUserU64::new(features);
61 let hdr = self.send_request_with_body(FrontendReq::SET_FEATURES, &val, None)?;
62 self.wait_for_ack(&hdr)
63 }
64
65 pub fn set_owner(&self) -> Result<()> {
68 let hdr = self.send_request_header(FrontendReq::SET_OWNER, None)?;
69 self.wait_for_ack(&hdr)
70 }
71
72 pub fn reset_owner(&self) -> Result<()> {
75 let hdr = self.send_request_header(FrontendReq::RESET_OWNER, None)?;
76 self.wait_for_ack(&hdr)
77 }
78
79 pub fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()> {
82 let mut ctx = VhostUserMemoryContext::new();
83 for region in regions.iter() {
84 let reg = VhostUserMemoryRegion {
85 guest_phys_addr: region.guest_phys_addr,
86 memory_size: region.memory_size,
87 user_addr: region.userspace_addr,
88 mmap_offset: region.mmap_offset,
89 };
90 ctx.append(®, region.mmap_handle);
91 }
92
93 let body = VhostUserMemory::new(ctx.regions.len() as u32);
94 let hdr = self.send_request_with_payload(
95 FrontendReq::SET_MEM_TABLE,
96 &body,
97 ctx.regions.as_bytes(),
98 Some(ctx.fds.as_slice()),
99 )?;
100 self.wait_for_ack(&hdr)
101 }
102
103 pub fn set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()> {
105 let val = VhostUserU64::new(base);
106 let hdr = self.send_request_with_body(
107 FrontendReq::SET_LOG_BASE,
108 &val,
109 fd.as_ref().map(std::slice::from_ref),
110 )?;
111 self.wait_for_ack(&hdr)
112 }
113
114 pub fn set_log_fd(&self, fd: RawDescriptor) -> Result<()> {
116 let fds = [fd];
117 let hdr = self.send_request_header(FrontendReq::SET_LOG_FD, Some(&fds))?;
118 self.wait_for_ack(&hdr)
119 }
120
121 pub fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> {
123 let val = VhostUserVringState::new(queue_index as u32, num.into());
124 let hdr = self.send_request_with_body(FrontendReq::SET_VRING_NUM, &val, None)?;
125 self.wait_for_ack(&hdr)
126 }
127
128 pub fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()> {
130 let val = VhostUserVringAddr::from_config_data(queue_index as u32, config_data);
131 let hdr = self.send_request_with_body(FrontendReq::SET_VRING_ADDR, &val, None)?;
132 self.wait_for_ack(&hdr)
133 }
134
135 pub fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()> {
138 let val = VhostUserVringState::new(queue_index as u32, base.into());
139 let hdr = self.send_request_with_body(FrontendReq::SET_VRING_BASE, &val, None)?;
140 self.wait_for_ack(&hdr)
141 }
142
143 pub fn get_vring_base(&self, queue_index: usize) -> Result<u32> {
146 let req = VhostUserVringState::new(queue_index as u32, 0);
147 let hdr = self.send_request_with_body(FrontendReq::GET_VRING_BASE, &req, None)?;
148 let reply = self.recv_reply::<VhostUserVringState>(&hdr)?;
149 Ok(reply.num)
150 }
151
152 pub fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()> {
158 let hdr = self.send_fd_for_vring(
159 FrontendReq::SET_VRING_CALL,
160 queue_index,
161 event.as_raw_descriptor(),
162 )?;
163 self.wait_for_ack(&hdr)
164 }
165
166 pub fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()> {
173 let hdr = self.send_fd_for_vring(
174 FrontendReq::SET_VRING_KICK,
175 queue_index,
176 event.as_raw_descriptor(),
177 )?;
178 self.wait_for_ack(&hdr)
179 }
180
181 pub fn set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()> {
186 let hdr = self.send_fd_for_vring(
187 FrontendReq::SET_VRING_ERR,
188 queue_index,
189 event.as_raw_descriptor(),
190 )?;
191 self.wait_for_ack(&hdr)
192 }
193
194 pub fn set_device_state_fd(
199 &self,
200 transfer_direction: VhostUserTransferDirection,
201 migration_phase: VhostUserMigrationPhase,
202 fd: &impl AsRawDescriptor,
203 ) -> Result<Option<File>> {
204 let req = DeviceStateTransferParameters {
206 transfer_direction: match transfer_direction {
207 VhostUserTransferDirection::Save => 0,
208 VhostUserTransferDirection::Load => 1,
209 },
210 migration_phase: match migration_phase {
211 VhostUserMigrationPhase::Stopped => 0,
212 },
213 };
214 let hdr = self.send_request_with_body(
215 FrontendReq::SET_DEVICE_STATE_FD,
216 &req,
217 Some(&[fd.as_raw_descriptor()]),
218 )?;
219 let (reply, files) = self.recv_reply_with_files::<VhostUserU64>(&hdr)?;
221 let has_err = reply.value & 0xff != 0;
222 let invalid_fd = reply.value & 0x100 != 0;
223 if has_err {
224 return Err(VhostUserError::BackendInternalError);
225 }
226 match (invalid_fd, files.len()) {
227 (true, 0) => Ok(None),
228 (false, 1) => Ok(files.into_iter().next()),
229 _ => Err(VhostUserError::IncorrectFds),
230 }
231 }
232
233 pub fn check_device_state(&self) -> Result<()> {
236 let hdr = self.send_request_header(FrontendReq::CHECK_DEVICE_STATE, None)?;
237 let reply = self.recv_reply::<VhostUserU64>(&hdr)?;
238 if reply.value != 0 {
239 return Err(VhostUserError::BackendInternalError);
240 }
241 Ok(())
242 }
243
244 pub fn get_protocol_features(&self) -> Result<VhostUserProtocolFeatures> {
246 let hdr = self.send_request_header(FrontendReq::GET_PROTOCOL_FEATURES, None)?;
247 let val = self.recv_reply::<VhostUserU64>(&hdr)?;
248 Ok(VhostUserProtocolFeatures::from_bits_truncate(val.value))
249 }
250
251 pub fn set_protocol_features(&mut self, features: VhostUserProtocolFeatures) -> Result<()> {
253 let val = VhostUserU64::new(features.bits());
254 let hdr = self.send_request_with_body(FrontendReq::SET_PROTOCOL_FEATURES, &val, None)?;
255 self.wait_for_ack(&hdr)
256 }
257
258 pub fn get_queue_num(&self) -> Result<u64> {
260 let hdr = self.send_request_header(FrontendReq::GET_QUEUE_NUM, None)?;
261 let val = self.recv_reply::<VhostUserU64>(&hdr)?;
262 Ok(val.value)
263 }
264
265 pub fn set_vring_enable(&self, queue_index: usize, enable: bool) -> Result<()> {
271 let val = VhostUserVringState::new(queue_index as u32, enable.into());
272 let hdr = self.send_request_with_body(FrontendReq::SET_VRING_ENABLE, &val, None)?;
273 self.wait_for_ack(&hdr)
274 }
275
276 pub fn get_config(
278 &self,
279 offset: u32,
280 size: u32,
281 flags: VhostUserConfigFlags,
282 buf: &[u8],
283 ) -> Result<(VhostUserConfig, VhostUserConfigPayload)> {
284 let body = VhostUserConfig::new(offset, size, flags);
285
286 let hdr = self.send_request_with_payload(FrontendReq::GET_CONFIG, &body, buf, None)?;
290 let (body_reply, buf_reply, rfds) =
291 self.recv_reply_with_payload::<VhostUserConfig>(&hdr)?;
292 if !rfds.is_empty() {
293 return Err(VhostUserError::InvalidMessage);
294 } else if body_reply.size == 0 {
295 return Err(VhostUserError::BackendInternalError);
296 } else if body_reply.size != body.size
297 || body_reply.size as usize != buf.len()
298 || body_reply.offset != body.offset
299 {
300 return Err(VhostUserError::InvalidMessage);
301 }
302
303 Ok((body_reply, buf_reply))
304 }
305
306 pub fn set_config(&self, offset: u32, flags: VhostUserConfigFlags, buf: &[u8]) -> Result<()> {
309 let body = VhostUserConfig::new(
310 offset,
311 buf.len()
312 .try_into()
313 .map_err(VhostUserError::InvalidCastToInt)?,
314 flags,
315 );
316
317 let hdr = self.send_request_with_payload(FrontendReq::SET_CONFIG, &body, buf, None)?;
318 self.wait_for_ack(&hdr)
319 }
320
321 pub fn set_backend_req_fd(&self, fd: &dyn AsRawDescriptor) -> Result<()> {
323 let fds = [fd.as_raw_descriptor()];
324 let hdr = self.send_request_header(FrontendReq::SET_BACKEND_REQ_FD, Some(&fds))?;
325 self.wait_for_ack(&hdr)
326 }
327
328 pub fn get_inflight_fd(
330 &self,
331 inflight: &VhostUserInflight,
332 ) -> Result<(VhostUserInflight, File)> {
333 let hdr = self.send_request_with_body(FrontendReq::GET_INFLIGHT_FD, inflight, None)?;
334 let (inflight, files) = self.recv_reply_with_files::<VhostUserInflight>(&hdr)?;
335
336 match into_single_file(files) {
337 Some(file) => Ok((inflight, file)),
338 None => Err(VhostUserError::IncorrectFds),
339 }
340 }
341
342 pub fn set_inflight_fd(&self, inflight: &VhostUserInflight, fd: RawDescriptor) -> Result<()> {
344 let hdr =
345 self.send_request_with_body(FrontendReq::SET_INFLIGHT_FD, inflight, Some(&[fd]))?;
346 self.wait_for_ack(&hdr)
347 }
348
349 pub fn get_max_mem_slots(&self) -> Result<u64> {
351 let hdr = self.send_request_header(FrontendReq::GET_MAX_MEM_SLOTS, None)?;
352 let val = self.recv_reply::<VhostUserU64>(&hdr)?;
353
354 Ok(val.value)
355 }
356
357 pub fn add_mem_region(&self, region: &VhostUserMemoryRegionInfo) -> Result<()> {
359 let body = VhostUserSingleMemoryRegion::new(
360 region.guest_phys_addr,
361 region.memory_size,
362 region.userspace_addr,
363 region.mmap_offset,
364 );
365 let fds = [region.mmap_handle];
366 let hdr = self.send_request_with_body(FrontendReq::ADD_MEM_REG, &body, Some(&fds))?;
367 self.wait_for_ack(&hdr)
368 }
369
370 pub fn remove_mem_region(&self, region: &VhostUserMemoryRegionInfo) -> Result<()> {
372 let body = VhostUserSingleMemoryRegion::new(
373 region.guest_phys_addr,
374 region.memory_size,
375 region.userspace_addr,
376 region.mmap_offset,
377 );
378 let hdr = self.send_request_with_body(FrontendReq::REM_MEM_REG, &body, None)?;
379 self.wait_for_ack(&hdr)
380 }
381
382 pub fn get_shmem_config(&self) -> Result<Vec<SharedMemoryRegion>> {
384 let hdr = self.send_request_header(FrontendReq::GET_SHMEM_CONFIG, None)?;
385 let reply: VhostUserShMemConfig = self.recv_reply(&hdr)?;
386
387 let shared_memory_regions = reply
388 .sizes
389 .into_iter()
390 .enumerate()
391 .filter(|&(_, n)| n != 0)
392 .take(reply.nregions.try_into().unwrap())
393 .map(|(id, length)| SharedMemoryRegion {
394 id: id as u8,
395 length,
396 })
397 .collect();
398
399 Ok(shared_memory_regions)
400 }
401
402 fn send_request_header(
403 &self,
404 code: FrontendReq,
405 fds: Option<&[RawDescriptor]>,
406 ) -> VhostUserResult<VhostUserMsgHeader> {
407 let hdr = self.new_request_header(code, 0);
408 self.connection.send_header_only_message(&hdr, fds)?;
409 Ok(hdr)
410 }
411
412 fn send_request_with_body<T: IntoBytes + Immutable>(
413 &self,
414 code: FrontendReq,
415 msg: &T,
416 fds: Option<&[RawDescriptor]>,
417 ) -> VhostUserResult<VhostUserMsgHeader> {
418 let hdr = self.new_request_header(code, mem::size_of::<T>() as u32);
419 self.connection.send_message(&hdr, msg, fds)?;
420 Ok(hdr)
421 }
422
423 fn send_request_with_payload<T: IntoBytes + Immutable>(
424 &self,
425 code: FrontendReq,
426 msg: &T,
427 payload: &[u8],
428 fds: Option<&[RawDescriptor]>,
429 ) -> VhostUserResult<VhostUserMsgHeader> {
430 let len = mem::size_of::<T>()
431 .checked_add(payload.len())
432 .ok_or(VhostUserError::OversizedMsg)?;
433 let hdr = self.new_request_header(
434 code,
435 len.try_into().map_err(VhostUserError::InvalidCastToInt)?,
436 );
437 self.connection
438 .send_message_with_payload(&hdr, msg, payload, fds)?;
439 Ok(hdr)
440 }
441
442 fn send_fd_for_vring(
443 &self,
444 code: FrontendReq,
445 queue_index: usize,
446 fd: RawDescriptor,
447 ) -> VhostUserResult<VhostUserMsgHeader> {
448 let msg = VhostUserU64::new(queue_index as u64);
452 let hdr = self.new_request_header(code, mem::size_of::<VhostUserU64>() as u32);
453 self.connection.send_message(&hdr, &msg, Some(&[fd]))?;
454 Ok(hdr)
455 }
456
457 fn recv_reply<T: Sized + FromBytes + IntoBytes + Default + VhostUserMsgValidator>(
458 &self,
459 hdr: &VhostUserMsgHeader,
460 ) -> VhostUserResult<T> {
461 if hdr.is_reply() {
462 return Err(VhostUserError::InvalidParam(
463 "recv_reply: header is not a reply",
464 ));
465 }
466 let (reply, body, rfds) = self.connection.recv_message::<T>()?;
467 if !reply.is_valid() || !reply.is_reply_for(hdr) || !rfds.is_empty() || !body.is_valid() {
468 return Err(VhostUserError::InvalidMessage);
469 }
470 Ok(body)
471 }
472
473 fn recv_reply_with_files<T: Sized + IntoBytes + FromBytes + Default + VhostUserMsgValidator>(
474 &self,
475 hdr: &VhostUserMsgHeader,
476 ) -> VhostUserResult<(T, Vec<File>)> {
477 if hdr.is_reply() {
478 return Err(VhostUserError::InvalidParam(
479 "with_files: expected a reply, but the header is not marked as a reply",
480 ));
481 }
482
483 let (reply, body, files) = self.connection.recv_message::<T>()?;
484 if !reply.is_valid() || !reply.is_reply_for(hdr) || !body.is_valid() {
485 return Err(VhostUserError::InvalidMessage);
486 }
487 Ok((body, files))
488 }
489
490 fn recv_reply_with_payload<
491 T: Sized + IntoBytes + FromBytes + Default + VhostUserMsgValidator,
492 >(
493 &self,
494 hdr: &VhostUserMsgHeader,
495 ) -> VhostUserResult<(T, Vec<u8>, Vec<File>)> {
496 if hdr.is_reply() {
497 return Err(VhostUserError::InvalidParam(
498 "with_payload: expected a reply, but the header is not marked as a reply",
499 ));
500 }
501
502 let (reply, body, buf, files, more_files) =
503 self.connection.recv_message_with_payload::<T>()?;
504 if !reply.is_valid()
505 || !reply.is_reply_for(hdr)
506 || !files.is_empty()
507 || !more_files.is_empty()
508 || !body.is_valid()
509 {
510 return Err(VhostUserError::InvalidMessage);
511 }
512
513 Ok((body, buf, files))
514 }
515
516 fn wait_for_ack(&self, hdr: &VhostUserMsgHeader) -> VhostUserResult<()> {
517 if !hdr.is_need_reply() {
518 return Ok(());
519 }
520
521 let (reply, body, rfds) = self.connection.recv_message::<VhostUserU64>()?;
522 if !reply.is_valid() || !reply.is_reply_for(hdr) || !rfds.is_empty() || !body.is_valid() {
523 return Err(VhostUserError::InvalidMessage);
524 }
525 if body.value != 0 {
526 return Err(VhostUserError::BackendInternalError);
527 }
528 Ok(())
529 }
530
531 #[inline]
532 fn new_request_header(&self, request: FrontendReq, size: u32) -> VhostUserMsgHeader {
533 VhostUserMsgHeader::new_request_header(request, size, self.set_need_reply)
534 }
535}
536
537#[cfg(windows)]
538impl CloseNotifier for BackendClient {
539 fn get_close_notifier(&self) -> &dyn AsRawDescriptor {
540 self.connection.0.get_close_notifier()
541 }
542}
543
544impl ReadNotifier for BackendClient {
545 fn get_read_notifier(&self) -> &dyn AsRawDescriptor {
546 self.connection.0.get_read_notifier()
547 }
548}
549
550struct VhostUserMemoryContext {
553 regions: VhostUserMemoryPayload,
554 fds: Vec<RawDescriptor>,
555}
556
557impl VhostUserMemoryContext {
558 pub fn new() -> Self {
560 VhostUserMemoryContext {
561 regions: VhostUserMemoryPayload::new(),
562 fds: Vec::new(),
563 }
564 }
565
566 pub fn append(&mut self, region: &VhostUserMemoryRegion, fd: RawDescriptor) {
568 self.regions.push(*region);
569 self.fds.push(fd);
570 }
571}
572
573#[cfg(test)]
574mod tests {
575 use base::INVALID_DESCRIPTOR;
576
577 use super::*;
578
579 const BUFFER_SIZE: usize = 0x1001;
580 const INVALID_PROTOCOL_FEATURE: u64 = 1 << 63;
581
582 fn create_pair() -> (BackendClient, Connection) {
583 let (client_connection, server_connection) = Connection::pair().unwrap();
584 let backend_client = BackendClient::new(client_connection);
585 (backend_client, server_connection)
586 }
587
588 #[test]
589 fn create_backend_client() {
590 let (backend_client, peer) = create_pair();
591
592 assert!(backend_client.connection.as_raw_descriptor() != INVALID_DESCRIPTOR);
593 backend_client.set_owner().unwrap();
595 backend_client.reset_owner().unwrap();
596
597 let (hdr, rfds) = peer.recv_header().unwrap();
598 assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_OWNER));
599 assert_eq!(hdr.get_size(), 0);
600 assert_eq!(hdr.get_version(), 0x1);
601 assert!(rfds.is_empty());
602
603 let (hdr, rfds) = peer.recv_header().unwrap();
604 assert_eq!(hdr.get_code(), Ok(FrontendReq::RESET_OWNER));
605 assert_eq!(hdr.get_size(), 0);
606 assert_eq!(hdr.get_version(), 0x1);
607 assert!(rfds.is_empty());
608 }
609
610 #[test]
611 fn test_features() {
612 let (mut backend_client, peer) = create_pair();
613
614 backend_client.set_owner().unwrap();
615 let (hdr, rfds) = peer.recv_header().unwrap();
616 assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_OWNER));
617 assert_eq!(hdr.get_size(), 0);
618 assert_eq!(hdr.get_version(), 0x1);
619 assert!(rfds.is_empty());
620
621 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_FEATURES, 8);
622 let msg = VhostUserU64::new(0x15);
623 peer.send_message(&hdr, &msg, None).unwrap();
624 let features = backend_client.get_features().unwrap();
625 assert_eq!(features, 0x15u64);
626 let (_hdr, rfds) = peer.recv_header().unwrap();
627 assert!(rfds.is_empty());
628
629 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::SET_FEATURES, 8);
630 let msg = VhostUserU64::new(0x15);
631 peer.send_message(&hdr, &msg, None).unwrap();
632 backend_client.set_features(0x15).unwrap();
633 let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
634 assert!(rfds.is_empty());
635 let val = msg.value;
636 assert_eq!(val, 0x15);
637
638 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_FEATURES, 8);
639 let msg = 0x15u32;
640 peer.send_message(&hdr, &msg, None).unwrap();
641 assert!(backend_client.get_features().is_err());
642 }
643
644 #[test]
645 fn test_protocol_features() {
646 let (mut backend_client, peer) = create_pair();
647
648 backend_client.set_owner().unwrap();
649 let (hdr, rfds) = peer.recv_header().unwrap();
650 assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_OWNER));
651 assert!(rfds.is_empty());
652
653 let pfeatures = VhostUserProtocolFeatures::all();
654 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_PROTOCOL_FEATURES, 8);
655 let msg = VhostUserU64::new(pfeatures.bits() | INVALID_PROTOCOL_FEATURE);
657 peer.send_message(&hdr, &msg, None).unwrap();
658 let features = backend_client.get_protocol_features().unwrap();
659 assert_eq!(features, pfeatures);
660 let (_hdr, rfds) = peer.recv_header().unwrap();
661 assert!(rfds.is_empty());
662
663 backend_client
664 .set_protocol_features(VhostUserProtocolFeatures::all())
665 .unwrap();
666 let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
667 assert!(rfds.is_empty());
668 let val = msg.value;
669 assert_eq!(val, pfeatures.bits());
670
671 let vfeatures = 0x15 | 1 << VHOST_USER_F_PROTOCOL_FEATURES;
672 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_FEATURES, 8);
673 let msg = VhostUserU64::new(vfeatures);
674 peer.send_message(&hdr, &msg, None).unwrap();
675 let features = backend_client.get_features().unwrap();
676 assert_eq!(features, vfeatures);
677 let (_hdr, rfds) = peer.recv_header().unwrap();
678 assert!(rfds.is_empty());
679
680 backend_client.set_features(vfeatures).unwrap();
681 let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
682 assert!(rfds.is_empty());
683 let val = msg.value;
684 assert_eq!(val, vfeatures);
685
686 let pfeatures = VhostUserProtocolFeatures::all();
687 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_PROTOCOL_FEATURES, 8);
688 let msg = VhostUserU64::new(pfeatures.bits() | INVALID_PROTOCOL_FEATURE);
690 peer.send_message(&hdr, &msg, None).unwrap();
691 let features = backend_client.get_protocol_features().unwrap();
692 assert_eq!(features, pfeatures);
693 let (_hdr, rfds) = peer.recv_header().unwrap();
694 assert!(rfds.is_empty());
695
696 backend_client.set_protocol_features(pfeatures).unwrap();
697 let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
698 assert!(rfds.is_empty());
699 let val = msg.value;
700 assert_eq!(val, pfeatures.bits());
701
702 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::SET_PROTOCOL_FEATURES, 8);
703 let msg = VhostUserU64::new(pfeatures.bits());
704 peer.send_message(&hdr, &msg, None).unwrap();
705 assert!(backend_client.get_protocol_features().is_err());
706 }
707
708 #[test]
709 fn test_backend_client_get_config_negative0() {
710 let (backend_client, peer) = create_pair();
711 let buf = vec![0x0; BUFFER_SIZE];
712
713 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
714 let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
715 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
716 .unwrap();
717 assert!(backend_client
718 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
719 .is_ok());
720
721 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_FEATURES, 16);
722 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
723 .unwrap();
724 assert!(backend_client
725 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
726 .is_err());
727 }
728
729 #[test]
730 fn test_backend_client_get_config_negative1() {
731 let (backend_client, peer) = create_pair();
732 let buf = vec![0x0; BUFFER_SIZE];
733
734 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
735 let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
736 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
737 .unwrap();
738 assert!(backend_client
739 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
740 .is_ok());
741
742 let hdr = VhostUserMsgHeader::new_request_header(FrontendReq::GET_CONFIG, 16, false);
743 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
744 .unwrap();
745 assert!(backend_client
746 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
747 .is_err());
748 }
749
750 #[test]
751 fn test_backend_client_get_config_negative2() {
752 let (backend_client, peer) = create_pair();
753 let buf = vec![0x0; BUFFER_SIZE];
754
755 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
756 let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
757 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
758 .unwrap();
759 assert!(backend_client
760 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
761 .is_ok());
762 }
763
764 #[test]
765 fn test_backend_client_get_config_negative3() {
766 let (backend_client, peer) = create_pair();
767 let buf = vec![0x0; BUFFER_SIZE];
768
769 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
770 let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
771 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
772 .unwrap();
773 assert!(backend_client
774 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
775 .is_ok());
776
777 msg.offset = 0;
778 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
779 .unwrap();
780 assert!(backend_client
781 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
782 .is_err());
783 }
784
785 #[test]
786 fn test_backend_client_get_config_negative4() {
787 let (backend_client, peer) = create_pair();
788 let buf = vec![0x0; BUFFER_SIZE];
789
790 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
791 let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
792 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
793 .unwrap();
794 assert!(backend_client
795 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
796 .is_ok());
797
798 msg.offset = 0x101;
799 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
800 .unwrap();
801 assert!(backend_client
802 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
803 .is_err());
804 }
805
806 #[test]
807 fn test_backend_client_get_config_negative5() {
808 let (backend_client, peer) = create_pair();
809 let buf = vec![0x0; BUFFER_SIZE];
810
811 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
812 let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
813 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
814 .unwrap();
815 assert!(backend_client
816 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
817 .is_ok());
818
819 msg.offset = (BUFFER_SIZE) as u32;
820 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
821 .unwrap();
822 assert!(backend_client
823 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
824 .is_err());
825 }
826
827 #[test]
828 fn test_backend_client_get_config_negative6() {
829 let (backend_client, peer) = create_pair();
830 let buf = vec![0x0; BUFFER_SIZE];
831
832 let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
833 let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
834 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
835 .unwrap();
836 assert!(backend_client
837 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
838 .is_ok());
839
840 msg.size = 6;
841 peer.send_message_with_payload(&hdr, &msg, &buf[0..6], None)
842 .unwrap();
843 assert!(backend_client
844 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
845 .is_err());
846 }
847}