1use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
2use std::io::{self, Cursor};
3
4pub const CMD_MASK_COMMAND: u32 = 0x0000_ffff;
5pub const REQUEST_MAGIC: u32 = 0x2560_9513;
6pub const REPLY_MAGIC: u32 = 0x6744_6698;
7
8pub const SIZE_OF_REQUEST: usize = 28;
9pub const SIZE_OF_REPLY: usize = 16;
10
11#[derive(Clone, Copy, Debug)]
12pub enum Command {
13 Read,
14 Write,
15 Disc,
16 Flush,
17 Trim,
18 WriteZeroes,
19}
20
21#[derive(Debug, Clone, Copy)]
22pub struct RequestFlags {
23 pub fua: bool,
25 pub no_hole: bool,
27}
28
29#[derive(Debug, Clone, Copy)]
30pub struct Request {
31 pub magic: u32,
32 pub command: Command,
33 pub flags: RequestFlags,
34 pub handle: u64,
35 pub from: u64,
36 pub len: usize,
37}
38
39impl Request {
40 pub fn try_from_bytes(d: &[u8]) -> io::Result<Self> {
41 let mut rdr = Cursor::new(d);
42 let magic = rdr.read_u32::<NetworkEndian>()?;
43 let type_f = rdr.read_u32::<NetworkEndian>()?;
44 let handle = rdr.read_u64::<NetworkEndian>()?;
45 let from = rdr.read_u64::<NetworkEndian>()?;
46 let len = rdr.read_u32::<NetworkEndian>()? as usize;
47 if magic != REQUEST_MAGIC {
48 return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid magic"));
49 }
50 let command = match type_f & CMD_MASK_COMMAND {
51 0 => Command::Read,
52 1 => Command::Write,
53 2 => Command::Disc,
54 3 => Command::Flush,
55 4 => Command::Trim,
56 5 => Command::WriteZeroes,
57 _ => {
58 return Err(io::Error::new(
59 io::ErrorKind::InvalidData,
60 "invalid command",
61 ))
62 }
63 };
64 let flags = type_f >> 16;
65 let fua = flags & 1 == 1;
66 let no_hole = flags & (1 << 1) == (1 << 1);
67 Ok(Self {
68 magic,
69 command,
70 flags: RequestFlags { fua, no_hole },
71 handle,
72 from,
73 len,
74 })
75 }
76}
77
78#[derive(Debug, Clone)]
79pub struct Reply {
80 pub magic: u32,
81 pub error: i32,
82 pub handle: u64,
83}
84
85impl Reply {
86 pub fn from_request(request: &Request) -> Self {
87 Self {
88 magic: REPLY_MAGIC,
89 handle: request.handle,
90 error: 0,
91 }
92 }
93 pub fn append_to_vec(&self, buf: &mut Vec<u8>) -> io::Result<()> {
94 buf.write_u32::<NetworkEndian>(self.magic)?;
95 buf.write_i32::<NetworkEndian>(self.error)?;
96 buf.write_u64::<NetworkEndian>(self.handle)?;
97 Ok(())
98 }
99 pub fn write_to_slice(&self, mut slice: &mut [u8]) -> io::Result<()> {
100 slice.write_u32::<NetworkEndian>(self.magic)?;
101 slice.write_i32::<NetworkEndian>(self.error)?;
102 slice.write_u64::<NetworkEndian>(self.handle)?;
103 Ok(())
104 }
105}