channel.rs
1 use super::transport::Transport; 2 use super::types::{Behavior, Request, TransportError}; 3 use super::wire::into_u32; 4 5 /// Destination of data written to a channel. 6 #[derive(Debug, Clone, Copy)] 7 pub enum Pipe { 8 /// Standard output. 9 Stdout, 10 /// Standard error. 11 Stderr, 12 } 13 14 /// Channel associated with an SSH transport. 15 pub struct Channel<'a, 'b, T: Behavior> { 16 transport: &'b mut Transport<'a, T>, 17 } 18 19 impl<'a, 'b, T: Behavior> Channel<'a, 'b, T> { 20 pub(crate) fn new(transport: &'b mut Transport<'a, T>) -> Self { 21 Self { transport } 22 } 23 24 /// Returns the request associated with this channel. 25 pub fn request(&self) -> Request<T::Command> { 26 self.transport.channel_request() 27 } 28 29 /// Returns the user associated with this channel. 30 pub fn user(&self) -> T::User { 31 self.transport.channel_user() 32 } 33 34 /// Returns the identification string of the client. 35 pub fn client_ssh_id_string(&self) -> &str { 36 self.transport.client_ssh_id_string() 37 } 38 39 /// Closes the channel with a given exit status. 40 pub async fn exit(self, exit_status: u32) -> Result<(), TransportError<T>> { 41 self.transport.channel_exit(exit_status).await 42 } 43 44 /// Obtains a reader over this channel. 45 pub async fn reader( 46 &mut self, 47 len: Option<usize>, 48 ) -> Result<Reader<'a, '_, T>, TransportError<T>> { 49 self.transport.channel_adjust(len.map(into_u32)).await?; 50 Ok(Reader::new(self.transport)) // must read until done 51 } 52 53 /// Convenience method for exact-or-until-EOF reads. 54 /// 55 /// This method reads up to an exact number of bytes from the channel, stopping early 56 /// only in the case of EOF, and returns the number of bytes that were actually read. 57 pub async fn read_exact_stdin( 58 &mut self, 59 mut bytes: &mut [u8], 60 ) -> Result<usize, TransportError<T>> { 61 let read_len = bytes.len(); 62 63 let mut reader = self.reader(Some(read_len)).await?; 64 65 while let Some(read) = reader.read().await? { 66 let (dest, remaining) = bytes.split_at_mut(read.len()); 67 dest.copy_from_slice(read); 68 bytes = remaining; 69 } 70 71 Ok(read_len - bytes.len()) 72 } 73 74 /// Obtains a writer over this channel for the specified pipe. 75 pub fn writer(&mut self, pipe: Pipe) -> Writer<'a, '_, T> { 76 Writer::new(self.transport, pipe) 77 } 78 79 /// Obtains a writer over this channel for standard output. 80 pub fn stdout(&mut self) -> Writer<'a, '_, T> { 81 self.writer(Pipe::Stdout) 82 } 83 84 /// Obtains a writer over this channel for standard error. 85 pub fn stderr(&mut self) -> Writer<'a, '_, T> { 86 self.writer(Pipe::Stderr) 87 } 88 89 /// Convenience method that writes all bytes into standard output. 90 pub async fn write_all_stdout(&mut self, bytes: &[u8]) -> Result<(), TransportError<T>> { 91 self.stdout().write_all_internal(bytes).await 92 } 93 94 /// Convenience method that writes all bytes into standard error. 95 pub async fn write_all_stderr(&mut self, bytes: &[u8]) -> Result<(), TransportError<T>> { 96 self.stderr().write_all_internal(bytes).await 97 } 98 } 99 100 /// Reader associated with an SSH channel. 101 pub struct Reader<'a, 'b, T: Behavior> { 102 transport: &'b mut Transport<'a, T>, 103 } 104 105 impl<'a, 'b, T: Behavior> Reader<'a, 'b, T> { 106 fn new(transport: &'b mut Transport<'a, T>) -> Self { 107 Self { transport } 108 } 109 110 /// Reads data from the underlying channel. 111 /// 112 /// This method will never read more data than was originally requested upon 113 /// construction of the reader object, or `Ok(None)` if no more data or EOF. 114 pub async fn read(&mut self) -> Result<Option<&[u8]>, TransportError<T>> { 115 self.transport.channel_read().await 116 } 117 118 /// Returns whether the channel's receiving half has reached EOF. 119 pub fn is_eof(&mut self) -> bool { 120 self.transport.channel_is_eof() 121 } 122 } 123 124 /// Writer associated with an SSH channel. 125 pub struct Writer<'a, 'b, T: Behavior> { 126 transport: &'b mut Transport<'a, T>, 127 pipe: Pipe, 128 } 129 130 impl<'a, 'b, T: Behavior> Writer<'a, 'b, T> { 131 fn new(transport: &'b mut Transport<'a, T>, pipe: Pipe) -> Self { 132 Self { transport, pipe } 133 } 134 135 /// Returns a byte slice into the packet buffer. 136 pub fn buffer(&mut self) -> &mut [u8] { 137 self.transport.channel_data_payload_buffer(self.pipe) 138 } 139 140 /// Writes all requested bytes already present in the packet buffer. 141 /// 142 /// This will take the first `len` bytes in the byte slice returned 143 /// by the `buffer()` method and send them as a single SSH message. 144 pub async fn write_all(self, len: usize) -> Result<(), TransportError<T>> { 145 self.transport.channel_write_all(len, self.pipe).await?; 146 147 // TODO: report to the caller whether we wrote all bytes (the only 148 // case where we don't is if the client closed the channel on us). 149 150 Ok(()) 151 } 152 153 async fn write_all_internal(mut self, bytes: &[u8]) -> Result<(), TransportError<T>> { 154 for chunk in bytes.chunks(self.buffer().len()) { 155 self.buffer()[..chunk.len()].copy_from_slice(chunk); 156 self.transport 157 .channel_write_all(chunk.len(), self.pipe) 158 .await?; 159 } 160 161 // TODO: report to the caller whether we wrote all bytes (the only 162 // case where we don't is if the client closed the channel on us). 163 164 Ok(()) 165 } 166 }