1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-27 12:23:46 +03:00

start a unix listener when running the mux server

This commit is contained in:
Wez Furlong 2019-03-13 15:18:45 -07:00
parent 0d51fd0e7d
commit 2b4b27c9c0
3 changed files with 140 additions and 26 deletions

View File

@ -4,6 +4,7 @@ use crate::font::FontConfiguration;
use crate::frontend::FrontEnd;
use crate::mux::tab::Tab;
use crate::mux::Mux;
use crate::server::listener::spawn_listener;
use failure::Error;
use promise::Executor;
use promise::SpawnFunc;
@ -33,8 +34,9 @@ pub struct MuxServerFrontEnd {
}
impl MuxServerFrontEnd {
pub fn try_new(_mux: &Rc<Mux>) -> Result<Rc<FrontEnd>, Error> {
pub fn try_new(mux: &Rc<Mux>) -> Result<Rc<FrontEnd>, Error> {
let (tx, rx) = mpsc::sync_channel(4);
spawn_listener(mux.config(), Box::new(MuxExecutor { tx: tx.clone() }))?;
Ok(Rc::new(Self { tx, rx }))
}
}
@ -61,6 +63,7 @@ impl FrontEnd for MuxServerFrontEnd {
_fontconfig: &Rc<FontConfiguration>,
_tab: &Rc<Tab>,
) -> Result<(), Error> {
unimplemented!();
// The tab was already added to the mux, so we are a NOP
Ok(())
}
}

View File

@ -1,36 +1,147 @@
use crate::config::Config;
use crate::server::{UnixListener, UnixStream};
use failure::Error;
use failure::{err_msg, Error};
#[cfg(unix)]
use libc::{mode_t, umask};
use promise::Executor;
use std::fs::{remove_file, DirBuilder};
use std::io::{Read, Write};
#[cfg(unix)]
use std::os::unix::fs::{DirBuilderExt, PermissionsExt};
use std::path::Path;
use std::sync::Arc;
use std::thread;
pub trait SocketLike: Read + Write + Send {}
pub trait Acceptor {
fn accept(&self) -> Result<Box<SocketLike>, Error>;
}
impl SocketLike for UnixStream {}
impl Acceptor for UnixListener {
fn accept(&self) -> Result<Box<SocketLike>, Error> {
let (stream, _addr) = UnixListener::accept(self)?;
#[cfg(unix)]
{
let timeout = std::time::Duration::new(60, 0);
stream.set_read_timeout(Some(timeout))?;
stream.set_write_timeout(Some(timeout))?;
}
Ok(Box::new(stream))
}
}
pub struct Listener {
acceptor: Box<Acceptor>,
acceptor: UnixListener,
executor: Box<Executor>,
}
impl Listener {
pub fn new(acceptor: Box<Acceptor>) -> Self {
Self { acceptor }
pub fn new(acceptor: UnixListener, executor: Box<Executor>) -> Self {
Self { acceptor, executor }
}
fn run(&mut self) {
for stream in self.acceptor.incoming() {
match stream {
Ok(stream) => {
let executor = self.executor.clone_executor();
let mut session = ClientSession::new(stream, executor);
thread::spawn(move || session.run());
}
Err(err) => {
eprintln!("accept failed: {}", err);
return;
}
}
}
}
}
pub struct ClientSession {}
pub struct ClientSession {
stream: UnixStream,
executor: Box<Executor>,
}
impl ClientSession {
fn new(stream: UnixStream, executor: Box<Executor>) -> Self {
Self { stream, executor }
}
fn run(&mut self) {}
}
/// Unfortunately, novice unix users can sometimes be running
/// with an overly permissive umask so we take care to install
/// a more restrictive mask while we might be creating things
/// in the filesystem.
/// This struct locks down the umask for its lifetime, restoring
/// the prior umask when it is dropped.
struct UmaskSaver {
#[cfg(unix)]
mask: mode_t,
}
impl UmaskSaver {
fn new() -> Self {
Self {
#[cfg(unix)]
mask: unsafe { umask(0o077) },
}
}
}
impl Drop for UmaskSaver {
fn drop(&mut self) {
#[cfg(unix)]
unsafe {
umask(self.mask);
}
}
}
/// Take care when setting up the listener socket;
/// we need to be sure that the directory that we create it in
/// is owned by the user and has appropriate file permissions
/// that prevent other users from manipulating its contents.
fn safely_create_sock_path(sock_path: &String) -> Result<UnixListener, Error> {
let sock_path = Path::new(sock_path);
eprintln!("setting up {}", sock_path.display());
let _saver = UmaskSaver::new();
let sock_dir = sock_path
.parent()
.ok_or_else(|| format_err!("sock_path {} has no parent dir", sock_path.display()))?;
let mut builder = DirBuilder::new();
builder.recursive(true);
#[cfg(unix)]
{
builder.mode(0o700);
}
builder.create(sock_dir)?;
// Let's be sure that the ownership looks sane
let meta = sock_dir.symlink_metadata()?;
#[cfg(unix)]
{
let permissions = meta.permissions();
if (permissions.mode() & 0o22) != 0 {
bail!(
"The permissions for {} are insecure and currently
allow other users to write to it (permissions={:?})",
sock_dir.display(),
permissions
);
}
}
if sock_path.exists() {
remove_file(sock_path)?;
}
UnixListener::bind(sock_path)
.map_err(|e| format_err!("Failed to bind to {}: {}", sock_path.display(), e))
}
pub fn spawn_listener(config: &Arc<Config>, executor: Box<Executor>) -> Result<(), Error> {
let sock_path = config
.mux_server_unix_domain_socket_path
.as_ref()
.ok_or_else(|| err_msg("no mux_server_unix_domain_socket_path"))?;
let mut listener = Listener::new(safely_create_sock_path(sock_path)?, executor);
thread::spawn(move || {
listener.run();
});
Ok(())
}

View File

@ -1,7 +1,7 @@
#[cfg(unix)]
use std::os::unix::net::{SocketAddr, UnixListener, UnixStream};
use std::os::unix::net::{UnixListener, UnixStream};
#[cfg(windows)]
use uds_windows::{SocketAddr, UnixListener, UnixStream};
use uds_windows::{UnixListener, UnixStream};
pub mod client;
pub mod listener;