use std::io::{Read, Write};
use crate::client::Client;
use crate::constant::size::LOCAL_WINDOW_SIZE;
use crate::constant::ssh_msg_code;
use crate::data::Data;
use crate::error::SshResult;
pub struct WindowSize {
pub(crate) server_channel_no: u32,
pub(crate) client_channel_no: u32,
local_window_size: u32,
remote_window_size: u32,
}
impl WindowSize {
pub(crate) fn new() -> Self {
WindowSize {
server_channel_no: 0,
client_channel_no: 0,
local_window_size: LOCAL_WINDOW_SIZE,
remote_window_size: 0,
}
}
pub(crate) fn get_size(&self, data: &[u8]) -> Option<u32> {
let mc = &data[0];
match *mc {
ssh_msg_code::SSH_MSG_CHANNEL_DATA => {
let mut data = Data::from(data);
data.get_u8(); data.get_u32(); let vec = data.get_u8s(); let size = vec.len() as u32;
Some(size)
}
ssh_msg_code::SSH_MSG_CHANNEL_EXTENDED_DATA => {
let mut data = Data::from(data);
data.get_u8(); data.get_u32(); data.get_u32(); let vec = data.get_u8s(); let size = vec.len() as u32;
Some(size)
}
_ => None,
}
}
}
impl WindowSize {
pub(crate) fn process_remote_window_size<S>(
&mut self,
data: &[u8],
client: &mut Client<S>,
) -> SshResult<()>
where
S: Read + Write,
{
let size = match self.get_size(data) {
None => return Ok(()),
Some(size) => size,
};
if size > self.remote_window_size {
return self.read_window_size(client);
}
self.remote_window_size -= size;
Ok(())
}
pub(crate) fn add_remote_window_size(&mut self, rws: u32) {
self.remote_window_size += rws;
}
pub(crate) fn read_window_size<S>(&mut self, client: &mut Client<S>) -> SshResult<()>
where
S: Read + Write,
{
let results = client.read()?;
if results.is_empty() {
return Ok(());
}
for mut data in results {
let mc = data.get_u8();
if ssh_msg_code::SSH_MSG_CHANNEL_WINDOW_ADJUST == mc {
data.get_u32();
let size = data.get_u32();
self.remote_window_size += size;
}
}
Ok(())
}
}
impl WindowSize {
pub(crate) fn process_local_window_size<S>(
&mut self,
data: &[u8],
client: &mut Client<S>,
) -> SshResult<()>
where
S: Read + Write,
{
let size = match self.get_size(data) {
None => return Ok(()),
Some(size) => size,
};
if self.local_window_size <= size {
let used = LOCAL_WINDOW_SIZE - self.local_window_size;
let mut data = Data::new();
data.put_u8(ssh_msg_code::SSH_MSG_CHANNEL_WINDOW_ADJUST)
.put_u32(self.server_channel_no)
.put_u32(used);
client.write(data)?;
self.local_window_size += used;
}
self.local_window_size -= size;
Ok(())
}
}