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)]
132pub enum MessageType {
133 Request,
135 Response,
137 Notification,
139}
140
141impl MessageType {
142 pub const fn have_to_return_data(&self) -> bool {
144 match self {
145 Self::Request => true,
146 Self::Response | Self::Notification => false,
147 }
148 }
149
150 pub const fn from_flags_and_have_to_return(
152 flags: Flags,
153 have_to_return: bool,
154 ) -> Result<Self, BucketError> {
155 Ok(match (flags, have_to_return) {
156 (Flags::REQUEST, true) => Self::Request,
157 (Flags::REQUEST, false) => Self::Notification,
158 (Flags::RESPONSE, false) => Self::Response,
159 _ => {
160 return Err(BucketError::InvalidHeaderFlags(
161 "Unable to assign a message type to this bucket",
162 ))
163 }
164 })
165 }
166
167 pub const fn as_flags(&self) -> Flags {
168 match self {
169 Self::Request | Self::Notification => Flags::REQUEST,
170 Self::Response => Flags::RESPONSE,
171 }
172 }
173}
174
175#[derive(Debug)]
176pub struct BucketBuilder<C> {
177 signature: Option<u64>,
178 ty: Option<MessageType>,
179 command: Option<C>,
180 return_code: Option<i32>,
181 protocol_version: Option<u32>,
182 body: Option<Bytes>,
183}
184
185impl<C: LevinCommand> BucketBuilder<C> {
186 pub const fn new(protocol: &Protocol) -> Self {
187 Self {
188 signature: Some(protocol.signature),
189 ty: None,
190 command: None,
191 return_code: None,
192 protocol_version: Some(protocol.version),
193 body: None,
194 }
195 }
196
197 pub fn set_signature(&mut self, sig: u64) {
198 self.signature = Some(sig);
199 }
200
201 pub fn set_message_type(&mut self, ty: MessageType) {
202 self.ty = Some(ty);
203 }
204
205 pub fn set_command(&mut self, command: C) {
206 self.command = Some(command);
207 }
208
209 pub fn set_return_code(&mut self, code: i32) {
210 self.return_code = Some(code);
211 }
212
213 pub fn set_protocol_version(&mut self, version: u32) {
214 self.protocol_version = Some(version);
215 }
216
217 pub fn set_body(&mut self, body: Bytes) {
218 self.body = Some(body);
219 }
220
221 pub fn finish(self) -> Bucket<C> {
222 let body = self.body.unwrap();
223 let ty = self.ty.unwrap();
224 Bucket {
225 header: BucketHead {
226 signature: self.signature.unwrap(),
227 size: usize_to_u64(body.len()),
228 have_to_return_data: ty.have_to_return_data(),
229 command: self.command.unwrap(),
230 return_code: self.return_code.unwrap(),
231 flags: ty.as_flags(),
232 protocol_version: self.protocol_version.unwrap(),
233 },
234 body,
235 }
236 }
237}
238
239pub trait LevinBody: Sized {
241 type Command: LevinCommand + Debug;
242
243 fn decode_message<B: Buf>(
245 body: &mut B,
246 ty: MessageType,
247 command: Self::Command,
248 ) -> Result<Self, BucketError>;
249
250 fn encode(self, builder: &mut BucketBuilder<Self::Command>) -> Result<(), BucketError>;
252}
253
254pub trait LevinCommand: From<u32> + Into<u32> + PartialEq + Clone {
259 fn bucket_size_limit(&self) -> u64;
263 fn is_handshake(&self) -> bool;
265}