cuprate_levin/
header.rs

1// Rust Levin Library
2// Written in 2023 by
3//   Cuprate Contributors
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15
16//! This module provides a struct `BucketHead` for the header of a levin protocol
17//! message.
18
19use bitflags::bitflags;
20use bytes::{Buf, BufMut, BytesMut};
21
22use crate::LevinCommand;
23
24/// The size of the header (in bytes)
25pub const HEADER_SIZE: usize = 33;
26
27/// Levin header flags
28#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
29pub struct Flags(u32);
30
31bitflags! {
32    impl Flags: u32 {
33        /// The request flag.
34        ///
35        /// Depending on the `have_to_return_data` field in [`BucketHead`], this message is either
36        /// a request or notification.
37        const REQUEST = 0b0000_0001;
38        /// The response flags.
39        ///
40        /// Messages with this set are responses to requests.
41        const RESPONSE = 0b0000_0010;
42
43        /// The start fragment flag.
44        ///
45        /// Messages with this flag set tell the parser that the next messages until a message
46        /// with [`Flags::END_FRAGMENT`] should be combined into a single bucket.
47        const START_FRAGMENT = 0b0000_0100;
48        /// The end fragment flag.
49        ///
50        /// Messages with this flag set tell the parser that all fragments of a fragmented message
51        /// have been sent.
52        const END_FRAGMENT = 0b0000_1000;
53
54        /// A dummy message.
55        ///
56        /// Messages with this flag will be completely ignored by the parser.
57        const DUMMY = Self::START_FRAGMENT.bits() | Self::END_FRAGMENT.bits();
58
59        const _ = !0;
60    }
61}
62
63impl From<u32> for Flags {
64    fn from(value: u32) -> Self {
65        Self(value)
66    }
67}
68
69impl From<Flags> for u32 {
70    fn from(value: Flags) -> Self {
71        value.0
72    }
73}
74
75/// The Header of a Bucket. This contains
76#[derive(Debug, PartialEq, Eq, Clone, Copy)]
77pub struct BucketHead<C> {
78    /// The network signature, should be `LEVIN_SIGNATURE` for Monero
79    pub signature: u64,
80    /// The size of the body
81    pub size: u64,
82    /// If the peer has to send data in the order of requests - some
83    /// messages require responses but don't have this set (some notifications)
84    pub have_to_return_data: bool,
85    /// Command
86    pub command: C,
87    /// Return Code - will be 0 for requests and >0 for ok responses otherwise will be
88    /// a negative number corresponding to the error
89    pub return_code: i32,
90    /// The Flags of this header
91    pub flags: Flags,
92    /// The protocol version, for Monero this is currently 1
93    pub protocol_version: u32,
94}
95
96impl<C: LevinCommand> BucketHead<C> {
97    /// Builds the header from bytes, this function does not check any fields should
98    /// match the expected ones.
99    ///
100    /// # Panics
101    /// This function will panic if there aren't enough bytes to fill the header.
102    /// Currently [`HEADER_SIZE`]
103    pub fn from_bytes(buf: &mut BytesMut) -> Self {
104        Self {
105            signature: buf.get_u64_le(),
106            size: buf.get_u64_le(),
107            have_to_return_data: buf.get_u8() != 0,
108            command: buf.get_u32_le().into(),
109            return_code: buf.get_i32_le(),
110            flags: Flags::from(buf.get_u32_le()),
111            protocol_version: buf.get_u32_le(),
112        }
113    }
114
115    /// Serializes the header
116    pub fn write_bytes_into(&self, dst: &mut BytesMut) {
117        dst.reserve(HEADER_SIZE);
118
119        dst.put_u64_le(self.signature);
120        dst.put_u64_le(self.size);
121        dst.put_u8(if self.have_to_return_data { 1 } else { 0 });
122        dst.put_u32_le(self.command.clone().into());
123        dst.put_i32_le(self.return_code);
124        dst.put_u32_le(self.flags.into());
125        dst.put_u32_le(self.protocol_version);
126    }
127}