From 39c1f51378ac8806a75bef044dbdf156f5e95571 Mon Sep 17 00:00:00 2001 From: Matt Johnston <matt@ucc.asn.au> Date: Wed, 17 Aug 2022 23:41:44 +0800 Subject: [PATCH] a bit towards serv1 async --- .gitignore | 1 + async/examples/serv1.rs | 118 ++++++++++++++++++++++++++++++++++++++ async/src/lib.rs | 2 + sshproto/src/behaviour.rs | 4 ++ sshproto/src/conn.rs | 4 ++ sshproto/src/runner.rs | 16 ++++++ sshproto/src/servauth.rs | 7 +++ sshproto/src/server.rs | 8 +++ 8 files changed, 160 insertions(+) create mode 100644 async/examples/serv1.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..e2a3069 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +*~ diff --git a/async/examples/serv1.rs b/async/examples/serv1.rs new file mode 100644 index 0000000..e8b2156 --- /dev/null +++ b/async/examples/serv1.rs @@ -0,0 +1,118 @@ +#[allow(unused_imports)] +use { + // crate::error::Error, + log::{debug, error, info, log, trace, warn}, +}; +use anyhow::{Context, Result, Error, bail}; +use pretty_hex::PrettyHex; + +use tokio::net::{TcpStream, TcpListener}; + +use std::{net::Ipv6Addr, io::Read}; + +use door_sshproto::*; +use door_async::{SSHServer, raw_pty}; + +use simplelog::*; +#[derive(argh::FromArgs)] +/** con1 + */ +struct Args { + #[argh(switch, short='v')] + /// verbose debug logging + debug: bool, + + #[argh(switch)] + /// more verbose + trace: bool, + + #[argh(option, short='p', default="22")] + /// port + port: u16, +} + +fn parse_args() -> Result<Args> { + let mut args: Args = argh::from_env(); + + Ok(args) +} + +fn main() -> Result<()> { + let args = parse_args()?; + + setup_log(&args)?; + + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { + run(&args).await + }) + .map_err(|e| { + error!("Exit with error: {e:?}"); + e + }); + Ok(()) +} + +fn setup_log(args: &Args) -> Result<()> { + let mut conf = simplelog::ConfigBuilder::new(); + let conf = conf + .add_filter_allow_str("door") + .add_filter_allow_str("serv1") + // not debugging these bits of the stack at present + // .add_filter_ignore_str("door_sshproto::traffic") + // .add_filter_ignore_str("door_sshproto::runner") + // .add_filter_ignore_str("door_async::async_door") + .set_time_offset_to_local().expect("Couldn't get local timezone") + .build(); + + let level = if args.trace { + LevelFilter::Trace + } else if args.debug { + LevelFilter::Debug + } else { + LevelFilter::Warn + }; + + let mut logs: Vec<Box<dyn SharedLogger>> = vec![ + TermLogger::new(level, conf.clone(), TerminalMode::Mixed, ColorChoice::Auto), + ]; + + CombinedLogger::init(logs).unwrap(); + Ok(()) +} + +fn run_session<'a, R: Send>(scope: &'a moro::Scope<'a, '_, R>, stream: TcpStream) -> Result<()> { + let rxbuf = vec![0; 3000]; + // TODO: better lifetime rather than leaking + let rxbuf = Box::leak(Box::new(rxbuf)).as_mut_slice(); + let txbuf = vec![0; 3000]; + let txbuf = Box::leak(Box::new(txbuf)).as_mut_slice(); + + let mut serv = SSHServer::new(rxbuf, txbuf)?; + + scope.spawn(async { + + }); + Ok(()) + +} + +async fn run(args: &Args) -> Result<()> { + let listener = TcpListener::bind(("", args.port)).await?; + moro::async_scope!(|scope| { + scope.spawn(async { + loop { + let (stream, _) = listener.accept().await?; + + run_session(scope, stream)? + } + #[allow(unreachable_code)] + Ok::<_, anyhow::Error>(()) + }); + + }).await; + Ok(()) +} diff --git a/async/src/lib.rs b/async/src/lib.rs index 0bd2e20..f802913 100644 --- a/async/src/lib.rs +++ b/async/src/lib.rs @@ -1,6 +1,7 @@ #![allow(unused_imports)] mod client; +mod server; mod async_door; mod async_channel; mod cmdline_client; @@ -8,6 +9,7 @@ mod pty; pub use async_door::AsyncDoor; pub use client::SSHClient; +pub use server::SSHServer; pub use cmdline_client::CmdlineClient; #[cfg(unix)] diff --git a/sshproto/src/behaviour.rs b/sshproto/src/behaviour.rs index f0ad108..de627f9 100644 --- a/sshproto/src/behaviour.rs +++ b/sshproto/src/behaviour.rs @@ -42,6 +42,10 @@ pub enum BhError { // Permit impl Trait in type aliases // https://github.com/rust-lang/rust/issues/63063 +// TODO: another interim option would to split the async trait methods +// into a separate trait (which impls the non-async trait) for a bit more +// DRY. + pub struct Behaviour<'a> { #[cfg(feature = "std")] inner: async_behaviour::AsyncCliServ<'a>, diff --git a/sshproto/src/conn.rs b/sshproto/src/conn.rs index de77fe7..da464d5 100644 --- a/sshproto/src/conn.rs +++ b/sshproto/src/conn.rs @@ -110,6 +110,10 @@ impl<'a> Conn<'a> { Self::new(ClientServer::Client(client::Client::new())) } + pub fn new_server() -> Result<Self> { + Self::new(ClientServer::Server(server::Server::new())) + } + fn new(cliserv: ClientServer) -> Result<Self, Error> { Ok(Conn { kex: kex::Kex::new()?, diff --git a/sshproto/src/runner.rs b/sshproto/src/runner.rs index ddae3a0..19ade4a 100644 --- a/sshproto/src/runner.rs +++ b/sshproto/src/runner.rs @@ -46,6 +46,22 @@ impl<'a> Runner<'a> { Ok(runner) } + pub fn new_server( + inbuf: &'a mut [u8], + outbuf: &'a mut [u8], + ) -> Result<Runner<'a>, Error> { + let conn = Conn::new_server()?; + let runner = Runner { + conn, + traffic: traffic::Traffic::new(outbuf, inbuf), + keys: KeyState::new_cleartext(), + output_waker: None, + input_waker: None, + }; + + Ok(runner) + } + pub fn input(&mut self, buf: &[u8]) -> Result<usize, Error> { self.traffic.input( &mut self.keys, diff --git a/sshproto/src/servauth.rs b/sshproto/src/servauth.rs index 5919e4d..364658d 100644 --- a/sshproto/src/servauth.rs +++ b/sshproto/src/servauth.rs @@ -2,3 +2,10 @@ use crate::*; pub(crate) struct ServAuth { } + + +impl ServAuth { + pub fn new() -> Self { + Self {} + } +} diff --git a/sshproto/src/server.rs b/sshproto/src/server.rs index f16f2e3..a507787 100644 --- a/sshproto/src/server.rs +++ b/sshproto/src/server.rs @@ -4,3 +4,11 @@ use crate::servauth::ServAuth; pub(crate) struct Server { auth: ServAuth, } + +impl Server { + pub fn new() -> Self { + Server { + auth: ServAuth::new(), + } + } +} -- GitLab