use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
use crate::connection::FrameKind;
use crate::error::ConnectError;
pub async fn send_abridged(stream: &mut TcpStream, data: &[u8]) -> Result<(), ConnectError> {
let words = data.len() / 4;
let mut frame = if words < 0x7f {
let mut v = Vec::with_capacity(1 + data.len());
v.push(words as u8);
v
} else {
let mut v = Vec::with_capacity(4 + data.len());
v.extend_from_slice(&[
0x7f,
(words & 0xff) as u8,
((words >> 8) & 0xff) as u8,
((words >> 16) & 0xff) as u8,
]);
v
};
frame.extend_from_slice(data);
stream.write_all(&frame).await?;
Ok(())
}
pub async fn recv_raw_frame(
stream: &mut TcpStream,
kind: &FrameKind,
) -> Result<Vec<u8>, ConnectError> {
match kind {
FrameKind::Obfuscated { cipher } => {
let mut h = [0u8; 1];
stream.read_exact(&mut h).await?;
cipher.lock().await.decrypt(&mut h);
let words = if h[0] < 0x7f {
h[0] as usize
} else {
let mut b = [0u8; 3];
stream.read_exact(&mut b).await?;
cipher.lock().await.decrypt(&mut b);
b[0] as usize | (b[1] as usize) << 8 | (b[2] as usize) << 16
};
if words == 0 || words > 0x8000 {
return Err(ConnectError::other(format!(
"obfuscated recv_raw: implausible word count {words}"
)));
}
let mut buf = vec![0u8; words * 4];
stream.read_exact(&mut buf).await?;
cipher.lock().await.decrypt(&mut buf);
Ok(buf)
}
_ => recv_abridged(stream).await,
}
}
pub async fn recv_abridged(stream: &mut TcpStream) -> Result<Vec<u8>, ConnectError> {
let mut h = [0u8; 1];
stream.read_exact(&mut h).await?;
let words = if h[0] < 0x7f {
h[0] as usize
} else {
let mut b = [0u8; 3];
stream.read_exact(&mut b).await?;
let w = b[0] as usize | (b[1] as usize) << 8 | (b[2] as usize) << 16;
if w == 1 {
let mut code_buf = [0u8; 4];
stream.read_exact(&mut code_buf).await?;
let code = i32::from_le_bytes(code_buf);
return Err(ConnectError::TransportCode(code));
}
w
};
if words == 0 || words > 0x8000 {
return Err(ConnectError::other(format!(
"abridged: implausible word count {words} (possible transport error or framing mismatch)"
)));
}
let mut buf = vec![0u8; words * 4];
stream.read_exact(&mut buf).await?;
Ok(buf)
}