sunset_embassy/
server.rs

1use embedded_io_async::{Read, Write};
2
3use sunset::*;
4
5use crate::*;
6use embassy_sunset::EmbassySunset;
7
8/// An async SSH server instance 
9///
10/// The [`run()`][Self::run] method runs the session to completion, with application behaviour
11/// defined by the [`ServBehaviour`] instance.
12///
13/// Once the client has opened sessions, those can be retrieved with [`stdio()`][Self::stdio]
14/// and [`stdio_stderr()`][Self::stdio_stderr] methods.
15///
16/// This is async executor agnostic, though requires the `ServBehaviour` instance
17/// to be wrapped in a [`SunsetMutex`].
18pub struct SSHServer<'a> {
19    sunset: EmbassySunset<'a>,
20}
21
22impl<'a> SSHServer<'a> {
23    // May return an error if RNG fails
24    pub fn new(inbuf: &'a mut [u8], outbuf: &'a mut [u8],
25        ) -> Result<Self> {
26        let runner = Runner::new_server(inbuf, outbuf)?;
27        let sunset = EmbassySunset::new(runner);
28        Ok(Self { sunset })
29    }
30
31    /// Runs the session to completion.
32    ///
33    /// `rsock` and `wsock` are the SSH network channel (TCP port 22 or equivalent).
34    /// `b` is an instance of [`ServBehaviour`] which defines application behaviour.
35    pub async fn run<S: ServBehaviour>(&self,
36        rsock: &mut impl Read,
37        wsock: &mut impl Write,
38        b: &SunsetMutex<S>) -> Result<()>
39    {
40        self.sunset.run(rsock, wsock, b).await
41    }
42
43    /// Returns a [`ChanInOut`] representing a channel.
44    ///
45    /// For a shell this is stdin/stdout, for other channel types it is the only
46    /// data type.
47    /// `ch` is the [`ChanHandle`] passed to the application's `Behaviour`
48    /// methods.
49    pub async fn stdio(&'a self, ch: ChanHandle) -> Result<ChanInOut<'a>> {
50        let num = ch.num();
51        self.sunset.add_channel(ch, 1).await?;
52        Ok(ChanInOut::new(num, ChanData::Normal, &self.sunset))
53    }
54
55    /// Retrieve the stdin/stdout/stderr streams.
56    ///
57    /// If stderr is not required, use [`stdio()`][Self::stdio] instead to avoid needing to poll
58    /// the returned stderr.
59    /// The session will block until the streams are drained (they use the session buffer),
60    /// so they must be drained if used.
61    pub async fn stdio_stderr(&'a self, ch: ChanHandle)
62        -> Result<(ChanInOut<'a>, ChanOut<'a>)> {
63        let num = ch.num();
64        self.sunset.add_channel(ch, 2).await?;
65        let i = ChanInOut::new(num, ChanData::Normal, &self.sunset);
66        let e = ChanOut::new(num, ChanData::Stderr, &self.sunset);
67        Ok((i, e))
68    }
69
70    // TODO: add stdio_stderr()
71}