use crate::{
error::Error,
options::{SessionOptions, StreamOptions},
proto::session::SessionController,
style::SessionStyle,
synchronous::{read_response, stream::Stream},
};
use std::{io::Write, net::TcpStream};
pub mod style;
pub struct Session<S> {
controller: SessionController,
options: SessionOptions,
context: S,
}
impl<S: SessionStyle> Session<S> {
pub fn new(options: SessionOptions) -> crate::Result<Self> {
let mut controller = SessionController::new(options.clone())?;
let mut context = S::new(options.clone())?;
let command = controller.handshake_session()?;
context.write_command(&command)?;
let response = context.read_command()?;
controller.handle_response(&response)?;
let command = controller.create_session(context.create_session())?;
context.write_command(&command)?;
let response = context.read_command()?;
controller.handle_response(&response)?;
Ok(Self {
controller,
options,
context,
})
}
pub fn destination(&self) -> &str {
self.controller.destination()
}
}
impl Session<style::Stream> {
pub fn connect(&mut self, destination: &str) -> crate::Result<Stream> {
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", self.options.samv3_tcp_port))?;
let command = self.controller.handshake_stream()?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
let command = self.controller.create_stream(&destination, Default::default())?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
Ok(Stream::from_stream(stream, destination.to_string()))
}
pub async fn connect_with_options(
&mut self,
destination: &str,
options: StreamOptions,
) -> crate::Result<Stream> {
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", self.options.samv3_tcp_port))?;
let command = self.controller.handshake_stream()?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
let command = self.controller.create_stream(&destination, options)?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
Ok(Stream::from_stream(stream, destination.to_string()))
}
pub fn accept(&mut self) -> crate::Result<Stream> {
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", self.options.samv3_tcp_port))?;
let command = self.controller.handshake_stream()?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
let command = self.controller.accept_stream()?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
Ok(Stream::from_stream(stream, response.to_string()))
}
pub fn forward(&mut self, port: u16) -> crate::Result<()> {
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", self.options.samv3_tcp_port))?;
let command = self.controller.handshake_stream()?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
let command = self.controller.forward_stream(port)?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
style::Stream::store_forwarded(&mut self.context, stream);
Ok(())
}
}
impl Session<style::Repliable> {
pub fn send_to(&mut self, buf: &[u8], destination: &str) -> crate::Result<()> {
style::Repliable::send_to(&mut self.context, buf, destination)
}
pub fn recv_from(&mut self, buf: &mut [u8]) -> crate::Result<(usize, String)> {
style::Repliable::recv_from(&mut self.context, buf)
}
}
impl Session<style::Anonymous> {
pub fn send_to(&mut self, buf: &[u8], destination: &str) -> crate::Result<()> {
style::Anonymous::send_to(&mut self.context, buf, destination)
}
pub fn recv(&mut self, buf: &mut [u8]) -> crate::Result<usize> {
style::Anonymous::recv(&mut self.context, buf)
}
}