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