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