//! Creating binary from messages //! //! `SerializedMessage` to `Bytes`. use super::*; use bytes::{ Bytes, BytesMut, BufMut, Buf, }; macro_rules! try_from { (ref $into:ty, $from:expr $(; $fmt:literal)?) => { { let from = &$from; #[inline] fn _type_name_of_val(_: &T) -> &'static str { ::std::any::type_name::() } <$into>::try_from(*from).wrap_err(eyre!("Failed to convert type")) .with_section(|| ::std::any::type_name::<$into>().header("New type")) .with_section(|| _type_name_of_val(from).header("Old type")) .with_section(|| from.to_string().header("Value was")) } }; } /// Check bit written/read from binary streams to check basic integrity. pub const MESSAGE_HEADER_CHECK: [u8; 4] = (0xc0ffee00u32).to_be_bytes(); impl SerializedMessage { /// Write this message to a buffer /// /// # Panics /// If `buffer` cannot hold enough bytes. pub fn into_buffer(self, mut buffer: impl BufMut) -> eyre::Result { let mut w=0; macro_rules! write { ($bytes:expr) => { { let slice: &[u8] = ($bytes).as_ref(); buffer.put_slice(slice); w+=slice.len(); } }; (? $o:expr) => { { match $o { Some(opt) => { buffer.put_u8(1); write!(opt); }, None => {buffer.put_u8(0);}, } w+=1; } }; (: $ser:expr) => { { let mut v = StackVec::new(); #[inline] fn _type_name_of_val(_: &T) -> &'static str { ::std::any::type_name::() } let ser = $ser; serde_cbor::to_writer(&mut v, $ser) .wrap_err(eyre!("Failed to serialise value to temporary buffer")) .with_section(|| _type_name_of_val(ser).header("Type was"))?; buffer.put_u64(try_from!(ref u64, v.len())?); write!(&v[..]); } }; } write!(MESSAGE_HEADER_CHECK); write!(: &self.header); buffer.put_u64(try_from!(ref u64, self.data.len())?); write!(self.data); write!(self.hash); write!(? self.enc_key); write!(? self.sig); Ok(w) } /// Write this message to a new `Bytes`. pub fn into_bytes(self) -> eyre::Result { let mut output = BytesMut::with_capacity(4096); //TODO: Find a better default capacity for this. self.into_buffer(&mut output)?; Ok(output.freeze()) } } impl SerializedMessage { /// Create from a buffer of bytes. /// /// # Panics /// If `bytes` does not contain enough data to read. pub fn from_buffer(mut bytes: impl Buf) -> eyre::Result { macro_rules! read { ($bref:expr) => { { let by: &mut [u8] = ($bref).as_mut(); bytes.copy_to_slice(by); } }; (? $odef:expr) => { { let by = bytes.get_u8(); match by { 0 => None, 1 => { let mut def = $odef; read!(&mut def); Some(def) }, x => { return Err(eyre!("Invalid optional-set bit (should be 0 or 1)").with_section(|| x.header("Value was"))); } } } }; (: $ser:ty) => { { let len = try_from!(ref usize, bytes.get_u64())?; if len > MAX_READ_SIZE { return Err(eyre!("Invalid length read: {}", len) .with_section(|| MAX_READ_SIZE.header("Max length read"))); } alloc_local_bytes(len, |de| { read!(&mut de[..]); serde_cbor::from_slice::<$ser>(&de[..]).wrap_err(eyre!("Failed to deserialise CBOR from reader")).with_section(|| std::any::type_name::<$ser>().header("Type to deserialise was")) })? } }; ($into:expr, $num:expr) => { { let num = $num; let reader = (&mut bytes).reader(); copy_buffer($into, reader, num).wrap_err(eyre!("Failed to read {} bytes from reader", num))? } } } let mut check = [0u8; MESSAGE_HEADER_CHECK.len()]; read!(&mut check[..]); if check != MESSAGE_HEADER_CHECK { return Err(eyre!("Invalid check bit for message header")) .with_section(|| u32::from_be_bytes(check).header("Expected")) .with_section(|| u32::from_be_bytes(MESSAGE_HEADER_CHECK).header("Got")); } let header = read!(: SerHeader); let data_len = try_from!(ref usize, bytes.get_u64())?; if MAX_BODY_SIZE > 0 && data_len > MAX_BODY_SIZE { return Err(eyre!("Body size too large")) .with_section(|| data_len.header("Encoded size was")) .with_section(|| MAX_BODY_SIZE.header("Max size is")); } let mut data = Vec::with_capacity(std::cmp::min(data_len, MAX_ALLOC_SIZE)); //XXX: Redesign so we don't allocate OR try to read massive buffers by accident on corrupted/malformed messages read!(&mut data, data_len); if data.len()!=data_len { return Err(eyre!("Failed to read body bytes from buffer")) .with_section(|| format!("{} bytes", data_len).header("Tried to read")) .with_section(|| format!("{} bytes", data.len()).header("Read only")); } let mut hash = sha256::Sha256Hash::default(); read!(&mut hash); let enc_key: Option<[u8; RSA_BLOCK_SIZE]> = read!(? [0u8; RSA_BLOCK_SIZE]); let sig: Option = read!(? rsa::Signature::default()); Ok(Self { header, data, hash, enc_key, sig, _phantom: PhantomData, }) } /// Create from a slice of bytes #[inline] pub fn from_slice(bytes: impl AsRef<[u8]>) -> eyre::Result { Self::from_buffer(bytes.as_ref()) } /// Create from a `Bytes` instance #[inline(always)] pub fn from_bytes(bytes: Bytes) -> eyre::Result { Self::from_buffer(bytes) } }