1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

ssh: stub out libssh impl

This commit is contained in:
Wez Furlong 2021-10-17 21:57:00 -07:00
parent f1e5c59566
commit 0bf50924b1
3 changed files with 103 additions and 8 deletions

View File

@ -1,5 +1,6 @@
use crate::session::{
ChannelId, ChannelInfo, DescriptorState, SessionRequest, SessionSender, SessionWrap,
SignalChannel,
};
use filedescriptor::{socketpair, FileDescriptor};
use portable_pty::{ExitStatus, PtySize};
@ -127,8 +128,13 @@ impl portable_pty::Child for SshChildProcess {
}
fn kill(&mut self) -> std::io::Result<()> {
// There is no way to send a signal via libssh2.
// Just pretend that we did. :-/
if let Some(tx) = self.tx.as_ref() {
tx.try_send(SessionRequest::SignalChannel(SignalChannel {
channel: self.channel,
signame: "HUP",
}))
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
}
Ok(())
}

View File

@ -8,6 +8,7 @@ use filedescriptor::{
poll, pollfd, socketpair, AsRawSocketDescriptor, FileDescriptor, SocketDescriptor, POLLIN,
POLLOUT,
};
use libssh_rs as libssh;
use portable_pty::{ExitStatus, PtySize};
use smol::channel::{bounded, Receiver, Sender, TryRecvError};
use ssh2::BlockDirections;
@ -65,6 +66,13 @@ pub(crate) enum SessionRequest {
ResizePty(ResizePty),
Exec(Exec),
Sftp(SftpRequest),
SignalChannel(SignalChannel),
}
#[derive(Debug)]
pub(crate) struct SignalChannel {
pub channel: ChannelId,
pub signame: &'static str,
}
#[derive(Debug)]
@ -143,6 +151,7 @@ pub(crate) struct Ssh2Session {
pub(crate) enum SessionWrap {
Ssh2(Ssh2Session),
LibSsh(libssh::Session),
}
impl SessionWrap {
@ -150,15 +159,21 @@ impl SessionWrap {
Self::Ssh2(Ssh2Session { sess, sftp: None })
}
pub fn with_libssh(sess: libssh::Session) -> Self {
Self::LibSsh(sess)
}
pub fn set_blocking(&mut self, blocking: bool) {
match self {
Self::Ssh2(sess) => sess.sess.set_blocking(blocking),
Self::LibSsh(sess) => sess.set_blocking(blocking),
}
}
pub fn is_blocking(&mut self) -> bool {
match self {
Self::Ssh2(sess) => sess.sess.is_blocking(),
Self::LibSsh(sess) => sess.is_blocking(),
}
}
@ -170,12 +185,22 @@ impl SessionWrap {
BlockDirections::Outbound => POLLOUT,
BlockDirections::Both => POLLIN | POLLOUT,
},
Self::LibSsh(sess) => {
let (read, write) = sess.get_poll_state();
match (read, write) {
(false, false) => 0,
(true, false) => POLLIN,
(false, true) => POLLOUT,
(true, true) => POLLIN | POLLOUT,
}
}
}
}
pub fn as_socket_descriptor(&self) -> SocketDescriptor {
match self {
Self::Ssh2(sess) => sess.sess.as_socket_descriptor(),
Self::LibSsh(sess) => sess.as_socket_descriptor(),
}
}
@ -187,12 +212,18 @@ impl SessionWrap {
// channel.handle_extended_data(ssh2::ExtendedData::Merge)?;
Ok(ChannelWrap::Ssh2(channel))
}
Self::LibSsh(sess) => {
let channel = sess.new_channel()?;
channel.open_session()?;
Ok(ChannelWrap::LibSsh(channel))
}
}
}
}
pub(crate) enum ChannelWrap {
Ssh2(ssh2::Channel),
LibSsh(libssh::Channel),
}
fn has_signal(chan: &ssh2::Channel) -> Option<ssh2::ExitSignal> {
@ -220,18 +251,32 @@ impl ChannelWrap {
None
}
}
Self::LibSsh(chan) => {
if chan.is_eof() {
if let Some(status) = chan.get_exit_status() {
return Some(ExitStatus::with_exit_code(status as u32));
}
}
None
}
}
}
pub fn reader(&mut self, idx: usize) -> impl std::io::Read + '_ {
pub fn reader(&mut self, idx: usize) -> Box<dyn std::io::Read + '_> {
match self {
Self::Ssh2(chan) => chan.stream(idx as i32),
Self::Ssh2(chan) => Box::new(chan.stream(idx as i32)),
Self::LibSsh(chan) => match idx {
1 => Box::new(chan.stdout()),
2 => Box::new(chan.stderr()),
_ => unreachable!(),
},
}
}
pub fn writer(&mut self) -> impl std::io::Write + '_ {
pub fn writer(&mut self) -> Box<dyn std::io::Write + '_> {
match self {
Self::Ssh2(chan) => chan,
Self::Ssh2(chan) => Box::new(chan),
Self::LibSsh(chan) => Box::new(chan.stdin()),
}
}
@ -240,6 +285,9 @@ impl ChannelWrap {
Self::Ssh2(chan) => {
let _ = chan.close();
}
Self::LibSsh(chan) => {
let _ = chan.close();
}
}
}
@ -255,24 +303,32 @@ impl ChannelWrap {
newpty.size.pixel_height.into(),
)),
)?),
Self::LibSsh(chan) => Ok(chan.request_pty(
&newpty.term,
newpty.size.cols.into(),
newpty.size.rows.into(),
)?),
}
}
pub fn request_env(&mut self, name: &str, value: &str) -> anyhow::Result<()> {
match self {
Self::Ssh2(chan) => Ok(chan.setenv(name, value)?),
Self::LibSsh(chan) => Ok(chan.request_env(name, value)?),
}
}
pub fn request_exec(&mut self, command_line: &str) -> anyhow::Result<()> {
match self {
Self::Ssh2(chan) => Ok(chan.exec(command_line)?),
Self::LibSsh(chan) => Ok(chan.request_exec(command_line)?),
}
}
pub fn request_shell(&mut self) -> anyhow::Result<()> {
match self {
Self::Ssh2(chan) => Ok(chan.shell()?),
Self::LibSsh(chan) => Ok(chan.request_shell()?),
}
}
@ -284,6 +340,16 @@ impl ChannelWrap {
Some(resize.size.pixel_width.into()),
Some(resize.size.pixel_height.into()),
)?),
Self::LibSsh(chan) => {
Ok(chan.change_pty_size(resize.size.cols.into(), resize.size.rows.into())?)
}
}
}
pub fn send_signal(&mut self, signame: &str) -> anyhow::Result<()> {
match self {
Self::Ssh2(_) => Ok(()),
Self::LibSsh(chan) => Ok(chan.request_send_signal(signame)?),
}
}
}
@ -324,6 +390,10 @@ impl SessionInner {
}
fn run_impl(&mut self) -> anyhow::Result<()> {
self.run_impl_ssh2()
}
fn run_impl_ssh2(&mut self) -> anyhow::Result<()> {
let hostname = self
.config
.get("hostname")
@ -586,6 +656,12 @@ impl SessionInner {
}
Ok(true)
}
SessionRequest::SignalChannel(info) => {
if let Err(err) = self.signal_channel(&info) {
log::error!("{:?} -> error: {:#}", info, err);
}
Ok(true)
}
SessionRequest::Sftp(SftpRequest::OpenWithMode(msg)) => {
if let Err(err) = self.open_with_mode(sess, &msg) {
log::error!("{:?} -> error: {:#}", msg, err);
@ -731,6 +807,15 @@ impl SessionInner {
}
}
pub fn signal_channel(&mut self, info: &SignalChannel) -> anyhow::Result<()> {
let chan_info = self
.channels
.get_mut(&info.channel)
.ok_or_else(|| anyhow::anyhow!("invalid channel id {}", info.channel))?;
chan_info.channel.send_signal(info.signame)?;
Ok(())
}
pub fn exec(&mut self, sess: &mut SessionWrap, exec: &Exec) -> anyhow::Result<()> {
let mut channel = sess.open_session()?;
@ -1223,6 +1308,7 @@ impl SessionInner {
}
Ok(sess.sftp.as_mut().expect("sftp should have been set above"))
}
SessionWrap::LibSsh(_) => Err(SftpChannelError::NotImplemented),
}
}
}

View File

@ -46,7 +46,10 @@ pub enum SftpChannelError {
RecvFailed(#[from] RecvError),
#[error("Library-specific error: {}", .0)]
Other(#[source] ssh2::Error),
Ssh2(#[source] ssh2::Error),
#[error("Not Implemented")]
NotImplemented,
}
/// Represents an open sftp channel for performing filesystem operations
@ -476,7 +479,7 @@ mod ssh2_impl {
fn from(err: ssh2::Error) -> Self {
match SftpError::try_from(err) {
Ok(x) => Self::Sftp(x),
Err(x) => Self::Other(x),
Err(x) => Self::Ssh2(x),
}
}
}