diff --git a/Cargo.toml b/Cargo.toml index 90bd7d8d6e1dfb3c6bd8b8228971656f20104da0..77b6d437c3dd791f900ab5c84abe504b07255f13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ mio = "0.6.16" mio-extras = "2.0.5" slab = "0.4.0" libc = "0.2" +uds = "^0" [dev-dependencies] etherparse = "0.8.0" diff --git a/examples/tap/main.rs b/examples/tap/main.rs index 99d1b8eec6ab3b4189c1f30833bd84da8a3f2860..165df86e6fa852eadf4aa9b901af7c117b6bcde2 100644 --- a/examples/tap/main.rs +++ b/examples/tap/main.rs @@ -33,6 +33,11 @@ fn main() -> Result<(), Box> { loop { poll.poll(&mut events, duration)?; - duration = slirp.dispatch(&events)?; + duration = match slirp.dispatch(&events)? { + (false, _) => break, + (true, d) => d, + } } + + Ok(()) } diff --git a/src/bin/slirp-helper.rs b/src/bin/slirp-helper.rs index 6f27cbcb479c9ad5aea47d0452d2633e286f1e26..22afa09a6878f535f5a7f10225a2f312c4063853 100644 --- a/src/bin/slirp-helper.rs +++ b/src/bin/slirp-helper.rs @@ -1,9 +1,14 @@ use std::error::Error; use std::os::unix::io::AsRawFd; use std::os::unix::io::FromRawFd; +use std::os::unix::io::RawFd; use std::os::unix::net::UnixDatagram; +use std::thread; + use std::path::PathBuf; +use uds::UnixSeqpacketListener; + use libc; use libslirp; use mio::{Events, Poll}; @@ -21,6 +26,9 @@ struct Opt { /// Unix datagram socket path #[structopt(name = "path", parse(from_os_str), long = "socket-path")] socket_path: Option, + /// Listen on Unix seq packet socket path + #[structopt(name = "seqpath", parse(from_os_str), long = "listen-seqsocket-path")] + seq_socket_path: Option, /// Unix datagram socket file descriptor #[structopt(long)] fd: Option, @@ -36,36 +44,74 @@ fn set_exit_with_parent() { } } +fn handle_stream(fd: RawFd, opt: libslirp::Opt, debug: bool) -> Result<(), Box> { + let poll = Poll::new()?; + let mut slirp = libslirp::MioHandler::new(&opt, &poll, fd); + + let mut events = Events::with_capacity(1024); + let mut duration = None; + + loop { + if debug { + dbg!(duration); + } + + poll.poll(&mut events, duration)?; + duration = match slirp.dispatch(&events)? { + (true, _) => break, + (false, d) => d, + }; + } + Ok(()) +} + fn main() -> Result<(), Box> { let opt = Opt::from_args(); if opt.debug { dbg!(&opt); } let stream = match &opt { - Opt { fd: Some(fd), .. } => unsafe { UnixDatagram::from_raw_fd(*fd) }, + Opt { fd: Some(fd), .. } => unsafe { Some(UnixDatagram::from_raw_fd(*fd)) }, Opt { socket_path: Some(path), .. - } => UnixDatagram::bind(path)?, - _ => panic!("Missing a socket argument"), + } => Some(UnixDatagram::bind(path)?), + _ => None, + }; + let listener = match &opt { + Opt { + seq_socket_path: Some(path), + .. + } => Some(UnixSeqpacketListener::bind(path)?), + _ => None, + }; + + match (&listener, &stream) { + (None, None) => panic!("Missing socket or listener argument"), + (Some(_), Some(_)) => panic!("Can have only one of socket or listener argument"), + _ => (), }; if opt.exit_with_parent { set_exit_with_parent(); } - let poll = Poll::new()?; - let mut slirp = libslirp::MioHandler::new(&opt.slirp, &poll, stream.as_raw_fd()); - - let mut events = Events::with_capacity(1024); - let mut duration = None; + if let Some(s) = stream { + handle_stream(s.as_raw_fd(), opt.slirp, opt.debug)?; + } else if let Some(l) = listener { + loop { + let s = match l.accept_unix_addr() { + Ok((s, _)) => s, + Err(e) => { + eprintln!("Accept failed: {}", e); + continue; + } + }; - loop { - if opt.debug { - dbg!(duration); + let o = opt.slirp.clone(); + let debug = opt.debug; + thread::spawn(move || handle_stream(s.as_raw_fd(), o, debug).unwrap()); } - - poll.poll(&mut events, duration)?; - duration = slirp.dispatch(&events)?; } + Ok(()) } diff --git a/src/context.rs b/src/context.rs index 8463c53db1a3c695f51773f4e7515d9a1de2924a..6b6f0b7993eae936498a79d77cd64a70973064b0 100644 --- a/src/context.rs +++ b/src/context.rs @@ -94,14 +94,14 @@ impl Handler for Rc> { } extern "C" fn write_handler_cl(buf: *const c_void, len: usize, opaque: *mut c_void) -> isize { - let closure: &mut &mut FnMut(&[u8]) -> isize = unsafe { mem::transmute(opaque) }; + let closure: &mut &mut dyn FnMut(&[u8]) -> isize = unsafe { mem::transmute(opaque) }; let slice = unsafe { slice::from_raw_parts(buf as *const u8, len) }; closure(slice) } extern "C" fn read_handler_cl(buf: *mut c_void, len: usize, opaque: *mut c_void) -> isize { - let closure: &mut &mut FnMut(&mut [u8]) -> isize = unsafe { mem::transmute(opaque) }; + let closure: &mut &mut dyn FnMut(&mut [u8]) -> isize = unsafe { mem::transmute(opaque) }; let slice = unsafe { slice::from_raw_parts_mut(buf as *mut u8, len) }; closure(slice) @@ -206,13 +206,13 @@ impl fmt::Debug for PollEvents { } extern "C" fn add_poll_handler_cl(fd: c_int, events: c_int, opaque: *mut c_void) -> c_int { - let closure: &mut &mut FnMut(RawFd, PollEvents) -> i32 = unsafe { mem::transmute(opaque) }; + let closure: &mut &mut dyn FnMut(RawFd, PollEvents) -> i32 = unsafe { mem::transmute(opaque) }; closure(fd, PollEvents(events as usize)) } extern "C" fn get_revents_handler_cl(idx: c_int, opaque: *mut c_void) -> c_int { - let closure: &mut &mut FnMut(i32) -> PollEvents = unsafe { mem::transmute(opaque) }; + let closure: &mut &mut dyn FnMut(i32) -> PollEvents = unsafe { mem::transmute(opaque) }; closure(idx).0 as c_int } @@ -418,7 +418,7 @@ impl Context { where F: FnMut(RawFd, PollEvents) -> i32, { - let mut cb: &mut FnMut(RawFd, PollEvents) -> i32 = &mut add_poll_cb; + let mut cb: &mut dyn FnMut(RawFd, PollEvents) -> i32 = &mut add_poll_cb; let cb = &mut cb; unsafe { @@ -435,7 +435,7 @@ impl Context { where F: FnMut(i32) -> PollEvents, { - let mut cb: &mut FnMut(i32) -> PollEvents = &mut get_revents_cb; + let mut cb: &mut dyn FnMut(i32) -> PollEvents = &mut get_revents_cb; let cb = &mut cb; unsafe { @@ -453,7 +453,7 @@ impl Context { where F: FnMut(&[u8]) -> isize, { - let mut cb: &mut FnMut(&[u8]) -> isize = &mut write_cb; + let mut cb: &mut dyn FnMut(&[u8]) -> isize = &mut write_cb; let cb = &mut cb; unsafe { @@ -470,7 +470,7 @@ impl Context { where F: FnMut(&mut [u8]) -> isize, { - let mut cb: &mut FnMut(&mut [u8]) -> isize = &mut read_cb; + let mut cb: &mut dyn FnMut(&mut [u8]) -> isize = &mut read_cb; let cb = &mut cb; unsafe { diff --git a/src/mio.rs b/src/mio.rs index 326fa136e80207ff7813c1c0f9d8286a3c272748..4ce36f98d683e08aff95ff3aa2ea53589f103ee8 100644 --- a/src/mio.rs +++ b/src/mio.rs @@ -176,8 +176,6 @@ mod tests { } fn from_mio_ready(ready: mio::Ready) -> PollEvents { - use PollEvents; - let mut events = PollEvents::empty(); let ready = UnixReady::from(ready); @@ -220,7 +218,7 @@ impl<'a> MioHandler<'a> { } } - pub fn dispatch(&mut self, events: &Events) -> io::Result> { + pub fn dispatch(&mut self, events: &Events) -> io::Result<(bool, Option)> { let inner = self.inner.clone(); for (_, token) in inner.borrow().tokens.iter() { @@ -242,6 +240,9 @@ impl<'a> MioHandler<'a> { .stream .read(&mut buffer[..]) .unwrap(); + if len == 0 { + return Ok((true, None)); + } self.ctxt.input(&buffer[..len]); } i => { @@ -303,6 +304,6 @@ impl<'a> MioHandler<'a> { Some(Duration::from_millis(timeout as u64)) }; - Ok(duration) + Ok((false, duration)) } } diff --git a/src/opt.rs b/src/opt.rs index 8ef348ce56ef884b0c4b0ab604503431e31c42e2..230b897d676c13442a2869bbe6a3f6965e5682d2 100644 --- a/src/opt.rs +++ b/src/opt.rs @@ -2,7 +2,7 @@ use std::net::{Ipv4Addr, Ipv6Addr}; use std::path::PathBuf; use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, StructOpt, Clone)] pub struct OptIpv4 { /// Whether to disable IPv4 #[structopt(name = "disable-ipv4", long = "disable-ipv4")] @@ -29,7 +29,7 @@ pub struct OptIpv4 { pub dns: Ipv4Addr, } -#[derive(Debug, StructOpt)] +#[derive(Debug, StructOpt, Clone)] pub struct OptIpv6 { /// Whether to disable IPv6 #[structopt(name = "disable-ipv6", long = "disable-ipv6")] @@ -48,7 +48,7 @@ pub struct OptIpv6 { pub dns: Ipv6Addr, } -#[derive(Debug, StructOpt)] +#[derive(Debug, StructOpt, Clone)] pub struct OptTftp { /// RFC2132 "TFTP server name" string #[structopt(name = "name", long = "tftp-name")] @@ -61,7 +61,7 @@ pub struct OptTftp { pub bootfile: Option, } -#[derive(Debug, StructOpt)] +#[derive(Debug, StructOpt, Clone)] #[structopt(name = "slirp-opt")] pub struct Opt { /// Isolate guest from host diff --git a/tests/foo.rs b/tests/foo.rs index 4c1afff6cf681014f346ea53581c010dfdeef451..055d258948f5be3b383bc5a7c658f41004f0ad12 100644 --- a/tests/foo.rs +++ b/tests/foo.rs @@ -1,8 +1,8 @@ use etherparse::{PacketBuilder, TcpOptionElement}; use libslirp; use std::io; -use std::os::unix::io::{FromRawFd, RawFd}; -use std::time::{Duration, Instant}; +use std::os::unix::io::{RawFd}; +use std::time::{Instant}; use structopt::StructOpt; impl libslirp::Handler for App { @@ -14,11 +14,11 @@ impl libslirp::Handler for App { (d.as_secs() * NANOS_PER_SEC + d.subsec_nanos() as u64) as i64 } - fn timer_new(&mut self, func: Box) -> Box { + fn timer_new(&mut self, _func: Box) -> Box { Box::new(0) } - fn timer_mod(&mut self, timer: &mut Box, expire_time: i64) {} + fn timer_mod(&mut self, _timer: &mut Box, _expire_time: i64) {} fn timer_free(&mut self, timer: Box) { drop(timer);