use crate::errors::{ConnectError, ParseError};
use crate::protocol::xproto::{Setup, SetupAuthenticate, SetupFailed, SetupRequest};
use crate::x11_utils::{Serialize, TryParse};
#[cfg(feature = "std")]
use crate::xauth::{get_auth, Family};
use alloc::{vec, vec::Vec};
use core::fmt;
pub struct Connect {
buffer: Vec<u8>,
advanced: usize,
}
const INITIAL_CAPACITY: usize = 8;
#[cfg(target_endian = "little")]
const BYTE_ORDER: u8 = b'l';
#[cfg(not(target_endian = "little"))]
const BYTE_ORDER: u8 = b'B';
const PROTOCOL_MAJOR_VERSION: u16 = 11;
const PROTOCOL_MINOR_VERSION: u16 = 0;
impl Connect {
fn blank() -> Self {
Self {
buffer: vec![0; INITIAL_CAPACITY],
advanced: 0,
}
}
pub fn with_authorization(protocol_name: Vec<u8>, protocol_data: Vec<u8>) -> (Self, Vec<u8>) {
let sr = SetupRequest {
byte_order: BYTE_ORDER,
protocol_major_version: PROTOCOL_MAJOR_VERSION,
protocol_minor_version: PROTOCOL_MINOR_VERSION,
authorization_protocol_name: protocol_name,
authorization_protocol_data: protocol_data,
};
(Self::blank(), sr.serialize())
}
#[cfg(feature = "std")]
pub fn new(
family: Family,
address: &[u8],
display: u16,
) -> Result<(Self, Vec<u8>), ConnectError> {
match get_auth(family, address, display)? {
Some((name, data)) => Ok(Self::with_authorization(name, data)),
None => {
Ok(Self::with_authorization(Vec::new(), Vec::new()))
}
}
}
pub fn buffer(&mut self) -> &mut [u8] {
&mut self.buffer[self.advanced..]
}
pub fn advance(&mut self, bytes: usize) -> bool {
self.advanced += bytes;
debug_assert!(self.buffer.len() >= self.advanced);
if self.advanced == INITIAL_CAPACITY {
let length = u16::from_ne_bytes([self.buffer[6], self.buffer[7]]);
let length = length as usize * 4;
self.buffer.reserve_exact(length);
self.buffer.resize(length + self.buffer.len(), 0);
false
} else {
self.advanced == self.buffer.len()
}
}
pub fn into_setup(self) -> Result<Setup, ConnectError> {
if self.advanced != self.buffer.len() {
return Err(ConnectError::Incomplete {
expected: self.buffer.len(),
received: self.advanced,
});
}
match self.buffer[0] {
0 => {
let (failed, _) = SetupFailed::try_parse(&self.buffer)?;
Err(ConnectError::SetupFailed(failed))
}
1 => {
let (success, _) = Setup::try_parse(&self.buffer)?;
Ok(success)
}
2 => {
let (more_auth, _) = SetupAuthenticate::try_parse(&self.buffer)?;
Err(ConnectError::SetupAuthenticate(more_auth))
}
_ => {
Err(ParseError::InvalidValue.into())
}
}
}
}
impl fmt::Debug for Connect {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Connect")
.field(
"buffer",
&format_args!("{}/{}", self.advanced, self.buffer.len()),
)
.finish()
}
}
impl TryFrom<Connect> for Setup {
type Error = ConnectError;
fn try_from(connect: Connect) -> Result<Self, Self::Error> {
connect.into_setup()
}
}
#[cfg(test)]
#[cfg(all(feature = "extra-traits", feature = "std"))]
mod tests {
use super::Connect;
use crate::errors::ConnectError;
use crate::protocol::xproto::{ImageOrder, Setup, SetupAuthenticate, SetupFailed};
use crate::x11_utils::Serialize;
use alloc::vec;
fn test_setup() -> Setup {
let mut s = Setup {
status: 1,
protocol_major_version: 11,
protocol_minor_version: 0,
length: 0,
release_number: 0,
resource_id_base: 1,
resource_id_mask: 1,
motion_buffer_size: 0,
maximum_request_length: 0,
image_byte_order: ImageOrder::LSB_FIRST,
bitmap_format_bit_order: ImageOrder::LSB_FIRST,
bitmap_format_scanline_unit: 32,
bitmap_format_scanline_pad: 32,
min_keycode: 0,
max_keycode: 0,
vendor: b"Testing Setup".to_vec(),
pixmap_formats: vec![],
roots: vec![],
};
s.length = ((s.serialize().len() - 8 + 3) / 4) as u16;
s
}
fn try_receive_bytes(item: &impl Serialize) -> Result<Setup, ConnectError> {
let mut connect = Connect::blank();
let mut item_bytes = vec![];
item.serialize_into(&mut item_bytes);
let mut i = 0;
loop {
i += 1;
if i > 500 {
panic!("too many iterations");
}
let buffer = connect.buffer();
let bytes_to_copy = std::cmp::min(item_bytes.len(), buffer.len());
buffer[..bytes_to_copy].copy_from_slice(&item_bytes[..bytes_to_copy]);
drop(item_bytes.drain(..bytes_to_copy));
if connect.advance(bytes_to_copy) {
break;
}
}
connect.into_setup()
}
#[test]
fn test_connect_receive_setup() {
let setup = test_setup();
let b = try_receive_bytes(&setup);
match b {
Ok(s) => assert_eq!(s, setup),
Err(e) => panic!("{:?}", e),
}
}
#[test]
fn test_connect_receive_setup_authenticate() {
let setup = SetupAuthenticate {
status: 2,
reason: b"Needs more auth.".to_vec(),
};
let b = try_receive_bytes(&setup);
match b {
Ok(s) => panic!("{:?}", s),
Err(ConnectError::SetupAuthenticate(e)) => assert_eq!(e, setup),
Err(e) => panic!("{:?}", e),
}
}
#[test]
fn test_connect_receive_setup_failed() {
let mut setup = SetupFailed {
status: 0,
protocol_major_version: 11,
protocol_minor_version: 0,
length: 0,
reason: b"whatever".to_vec(),
};
setup.length = ((setup.serialize().len() - 8) / 4) as _;
let b = try_receive_bytes(&setup);
match b {
Ok(s) => panic!("{:?}", s),
Err(ConnectError::SetupFailed(e)) => assert_eq!(e, setup),
Err(e) => panic!("{:?}", e),
}
}
}