nbd_async/
nbd.rs

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    /// Force Unit Access flag.
24    pub fua: bool,
25    /// No Hole flag.
26    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}