cuprate_levin/
lib.rs
1#![forbid(unsafe_code)]
31#![deny(non_upper_case_globals)]
32#![deny(non_camel_case_types)]
33#![deny(unused_mut)]
34cfg_if::cfg_if! {
37 if #[cfg(test)] {
39 use futures as _;
40 use proptest as _;
41 use rand as _;
42 use tokio as _;
43 }
44}
45
46use std::fmt::Debug;
47
48use bytes::{Buf, Bytes};
49use thiserror::Error;
50
51use cuprate_helper::cast::usize_to_u64;
52
53pub mod codec;
54pub mod header;
55pub mod message;
56
57pub use codec::*;
58pub use header::BucketHead;
59pub use message::LevinMessage;
60
61use header::Flags;
62
63const MONERO_PROTOCOL_VERSION: u32 = 1;
65const MONERO_LEVIN_SIGNATURE: u64 = 0x0101010101012101;
68const MONERO_MAX_PACKET_SIZE_BEFORE_HANDSHAKE: u64 = 256 * 1000; const MONERO_MAX_PACKET_SIZE: u64 = 100_000_000; #[derive(Error, Debug)]
75pub enum BucketError {
76 #[error("Invalid header flags: {0}")]
78 InvalidHeaderFlags(&'static str),
79 #[error("Levin bucket exceeded max size")]
81 BucketExceededMaxSize,
82 #[error("Levin fragmented message was invalid: {0}")]
84 InvalidFragmentedMessage(&'static str),
85 #[error("Levin header had incorrect signature")]
87 InvalidHeaderSignature,
88 #[error("Error decoding bucket body: {0}")]
90 BodyDecodingError(Box<dyn std::error::Error + Send + Sync>),
91 #[error("Unknown command ID")]
93 UnknownCommand,
94 #[error("I/O error: {0}")]
96 IO(#[from] std::io::Error),
97}
98
99#[derive(Debug, Clone, Copy, Eq, PartialEq)]
103pub struct Protocol {
104 pub version: u32,
105 pub signature: u64,
106 pub max_packet_size_before_handshake: u64,
107 pub max_packet_size: u64,
108}
109
110impl Default for Protocol {
111 fn default() -> Self {
112 Self {
113 version: MONERO_PROTOCOL_VERSION,
114 signature: MONERO_LEVIN_SIGNATURE,
115 max_packet_size_before_handshake: MONERO_MAX_PACKET_SIZE_BEFORE_HANDSHAKE,
116 max_packet_size: MONERO_MAX_PACKET_SIZE,
117 }
118 }
119}
120
121#[derive(Debug, Clone)]
123pub struct Bucket<C> {
124 pub header: BucketHead<C>,
126 pub body: Bytes,
128}
129
130#[derive(Debug, Eq, PartialEq, Clone, Copy)]
132#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
133pub enum MessageType {
134 Request,
136 Response,
138 Notification,
140}
141
142impl MessageType {
143 pub const fn have_to_return_data(&self) -> bool {
145 match self {
146 Self::Request => true,
147 Self::Response | Self::Notification => false,
148 }
149 }
150
151 pub const fn from_flags_and_have_to_return(
153 flags: Flags,
154 have_to_return: bool,
155 ) -> Result<Self, BucketError> {
156 Ok(match (flags, have_to_return) {
157 (Flags::REQUEST, true) => Self::Request,
158 (Flags::REQUEST, false) => Self::Notification,
159 (Flags::RESPONSE, false) => Self::Response,
160 _ => {
161 return Err(BucketError::InvalidHeaderFlags(
162 "Unable to assign a message type to this bucket",
163 ))
164 }
165 })
166 }
167
168 pub const fn as_flags(&self) -> Flags {
169 match self {
170 Self::Request | Self::Notification => Flags::REQUEST,
171 Self::Response => Flags::RESPONSE,
172 }
173 }
174}
175
176#[derive(Debug)]
177pub struct BucketBuilder<C> {
178 signature: Option<u64>,
179 ty: Option<MessageType>,
180 command: Option<C>,
181 return_code: Option<i32>,
182 protocol_version: Option<u32>,
183 body: Option<Bytes>,
184}
185
186impl<C: LevinCommand> BucketBuilder<C> {
187 pub const fn new(protocol: &Protocol) -> Self {
188 Self {
189 signature: Some(protocol.signature),
190 ty: None,
191 command: None,
192 return_code: None,
193 protocol_version: Some(protocol.version),
194 body: None,
195 }
196 }
197
198 pub const fn set_signature(&mut self, sig: u64) {
199 self.signature = Some(sig);
200 }
201
202 pub const fn set_message_type(&mut self, ty: MessageType) {
203 self.ty = Some(ty);
204 }
205
206 pub fn set_command(&mut self, command: C) {
207 self.command = Some(command);
208 }
209
210 pub const fn set_return_code(&mut self, code: i32) {
211 self.return_code = Some(code);
212 }
213
214 pub const fn set_protocol_version(&mut self, version: u32) {
215 self.protocol_version = Some(version);
216 }
217
218 pub fn set_body(&mut self, body: Bytes) {
219 self.body = Some(body);
220 }
221
222 pub fn finish(self) -> Bucket<C> {
223 let body = self.body.unwrap();
224 let ty = self.ty.unwrap();
225 Bucket {
226 header: BucketHead {
227 signature: self.signature.unwrap(),
228 size: usize_to_u64(body.len()),
229 have_to_return_data: ty.have_to_return_data(),
230 command: self.command.unwrap(),
231 return_code: self.return_code.unwrap(),
232 flags: ty.as_flags(),
233 protocol_version: self.protocol_version.unwrap(),
234 },
235 body,
236 }
237 }
238}
239
240pub trait LevinBody: Sized {
242 type Command: LevinCommand + Debug;
243
244 fn decode_message<B: Buf>(
246 body: &mut B,
247 ty: MessageType,
248 command: Self::Command,
249 ) -> Result<Self, BucketError>;
250
251 fn encode(self, builder: &mut BucketBuilder<Self::Command>) -> Result<(), BucketError>;
253}
254
255pub trait LevinCommand: From<u32> + Into<u32> + PartialEq + Clone {
260 fn bucket_size_limit(&self) -> u64;
264 fn is_handshake(&self) -> bool;
266}