use crate::algorithm::encryption::Encryption;
use crate::client_r::Signature;
use crate::config::Config;
use crate::error::{SshError, SshResult};
use crate::h::H;
use crate::timeout::Timeout;
use crate::user_info::UserInfo;
use std::io::{self, Read, Write};
use std::ops::{Deref, DerefMut};
pub struct Client<S>
where
S: Read + Write,
{
pub(crate) stream: S,
pub(crate) sequence: Sequence,
pub(crate) timeout: Timeout,
pub(crate) config: Config,
pub(crate) encryption: Option<Box<dyn Encryption>>,
pub(crate) is_encryption: bool,
pub(crate) session_id: Vec<u8>,
pub(crate) w_size: usize,
pub(crate) signature: Option<Signature>,
pub(crate) is_r_1_gb: bool,
pub(crate) is_w_1_gb: bool,
}
#[derive(Clone)]
pub(crate) struct Sequence {
pub(crate) client_sequence_num: u32,
pub(crate) server_sequence_num: u32,
}
impl Sequence {
pub(crate) fn client_auto_increment(&mut self) {
if self.client_sequence_num == u32::MAX {
self.client_sequence_num = 0;
}
self.client_sequence_num += 1;
}
pub(crate) fn server_auto_increment(&mut self) {
if self.server_sequence_num == u32::MAX {
self.server_sequence_num = 0;
}
self.server_sequence_num += 1;
}
}
impl<S> Client<S>
where
S: Read + Write,
{
pub(crate) fn connect(
stream: S,
timeout_sec: u64,
user_info: UserInfo,
) -> SshResult<Client<S>> {
Ok(Client {
stream,
sequence: Sequence {
client_sequence_num: 0,
server_sequence_num: 0,
},
timeout: Timeout::new(timeout_sec),
config: Config::new(user_info),
encryption: None,
is_encryption: false,
session_id: vec![],
w_size: 0,
signature: None,
is_r_1_gb: false,
is_w_1_gb: false,
})
}
pub(crate) fn version(&mut self, h: &mut H) -> SshResult<()> {
log::info!("start for version negotiation.");
let vec = self.read_version();
let from_utf8 = crate::util::from_utf8(vec)?;
let sv = from_utf8.trim();
log::info!("server version: [{}]", sv);
self.config.version.server_version = sv.to_string();
let cv = self.config.version.client_version.clone();
self.write_version(format!("{}\r\n", cv.as_str()).as_bytes())?;
log::info!("client version: [{}]", cv);
self.config.version.validation()?;
h.set_v_s(sv);
h.set_v_c(&cv);
log::info!("version negotiation was successful.");
Ok(())
}
pub(crate) fn close(self) -> Result<(), SshError> {
drop(self);
Ok(())
}
pub(crate) fn is_would_block(e: &io::Error) -> bool {
e.kind() == io::ErrorKind::WouldBlock
}
}
impl<S> Drop for Client<S>
where
S: Read + Write,
{
fn drop(&mut self) {
log::info!("client close");
}
}
impl<S> Deref for Client<S>
where
S: Read + Write,
{
type Target = S;
fn deref(&self) -> &Self::Target {
&self.stream
}
}
impl<S> DerefMut for Client<S>
where
S: Read + Write,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.stream
}
}