use std::io::{self, Read, Write};
use bytes::{Bytes, BytesMut};
use rat_rdp_connector::MonotonicInstant;
use rat_rdp_pdu::PduHint;
use tracing::debug;
pub struct Framed<S> {
stream: S,
buf: BytesMut,
last_read_at: Option<MonotonicInstant>,
}
impl<S> Framed<S> {
pub fn new(stream: S) -> Self {
Self::new_with_leftover(stream, BytesMut::new())
}
pub fn new_with_leftover(stream: S, leftover: BytesMut) -> Self {
Self {
stream,
buf: leftover,
last_read_at: None,
}
}
pub fn into_inner(self) -> (S, BytesMut) {
(self.stream, self.buf)
}
pub fn into_inner_no_leftover(self) -> S {
let (stream, leftover) = self.into_inner();
debug_assert_eq!(leftover.len(), 0, "unexpected leftover");
stream
}
pub fn get_inner(&self) -> (&S, &BytesMut) {
(&self.stream, &self.buf)
}
pub fn get_inner_mut(&mut self) -> (&mut S, &mut BytesMut) {
(&mut self.stream, &mut self.buf)
}
pub fn last_read_at(&self) -> Option<MonotonicInstant> {
self.last_read_at
}
pub fn peek(&self) -> &[u8] {
&self.buf
}
}
impl<S> Framed<S>
where
S: Read,
{
pub(crate) fn read_exact(&mut self, length: usize) -> io::Result<BytesMut> {
loop {
if self.buf.len() >= length {
return Ok(self.buf.split_to(length));
} else {
self.buf
.reserve(length.checked_sub(self.buf.len()).expect("length > self.buf.len()"));
}
let len = self.read()?;
if len == 0 {
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "not enough bytes"));
}
}
}
pub fn read_pdu(&mut self) -> io::Result<(rat_rdp_pdu::Action, BytesMut)> {
loop {
match rat_rdp_pdu::find_size(self.peek()) {
Ok(Some(pdu_info)) => {
let frame = self.read_exact(pdu_info.length)?;
return Ok((pdu_info.action, frame));
}
Ok(None) => {
let len = self.read()?;
if len == 0 {
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "not enough bytes"));
}
}
Err(e) => return Err(io::Error::other(e)),
};
}
}
pub fn read_by_hint(&mut self, hint: &dyn PduHint) -> io::Result<Bytes> {
loop {
match hint.find_size(self.peek()).map_err(io::Error::other)? {
Some((matched, length)) => {
let bytes = self.read_exact(length)?.freeze();
if matched {
return Ok(bytes);
} else {
debug!("Received and lost an unexpected PDU");
}
}
None => {
let len = self.read()?;
if len == 0 {
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "not enough bytes"));
}
}
};
}
}
fn read(&mut self) -> io::Result<usize> {
let mut read_bytes = [0u8; 1024];
let len = self.stream.read(&mut read_bytes)?;
self.last_read_at = Some(monotonic_now());
self.buf.extend_from_slice(&read_bytes[..len]);
Ok(len)
}
}
impl<S> Framed<S>
where
S: Write,
{
pub fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.stream.write_all(buf)
}
}
fn monotonic_now() -> MonotonicInstant {
static EPOCH: std::sync::LazyLock<std::time::Instant> = std::sync::LazyLock::new(std::time::Instant::now);
MonotonicInstant::from_millis(u64::try_from(EPOCH.elapsed().as_millis()).unwrap_or(u64::MAX))
}