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}