Skip to content

Commit

Permalink
refactor: unifying how unix/tcp streams are handled in ninep clients …
Browse files Browse the repository at this point in the history
…and servers
  • Loading branch information
sminez committed Sep 10, 2024
1 parent e08b72d commit e6a84d7
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 85 deletions.
6 changes: 3 additions & 3 deletions crates/ad_client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
//! A simple 9p based client for interacting with ad
use ninep::client;
use ninep::client::UnixClient;
use std::io;

/// A simple 9p client for ad
#[derive(Debug)]
pub struct Client {
inner: client::Client,
inner: UnixClient,
}

impl Client {
pub fn new() -> io::Result<Self> {
Ok(Self {
inner: client::Client::new_unix("ad", "")?,
inner: UnixClient::new_unix("ad", "")?,
})
}

Expand Down
6 changes: 3 additions & 3 deletions crates/ninep/examples/client.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! A simple demo of the 9p client interface
use ninep::{client::Client, fs::FileType};
use ninep::{client::UnixClient, fs::FileType};
use std::io;

fn main() -> io::Result<()> {
let mut client = Client::new_unix("ninep-server", "")?;
let mut client = UnixClient::new_unix("ninep-server", "")?;
tree(&mut client, "", 0)?;

for line in client.iter_lines("blocking")? {
Expand All @@ -13,7 +13,7 @@ fn main() -> io::Result<()> {
Ok(())
}

fn tree(client: &mut Client, path: &str, depth: usize) -> io::Result<()> {
fn tree(client: &mut UnixClient, path: &str, depth: usize) -> io::Result<()> {
for stat in client.read_dir(path)? {
let name = stat.fm.name;
println!("{:indent$}{name}", "", indent = depth * 2);
Expand Down
3 changes: 2 additions & 1 deletion crates/ninep/examples/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
//! ```
use ninep::{
fs::{FileMeta, IoUnit, Mode, Perm, Stat},
server::{ReadOutcome, Result, Serve9p, Server},
server::{ReadOutcome, Serve9p, Server},
Result,
};
use std::{
sync::mpsc::channel,
Expand Down
96 changes: 47 additions & 49 deletions crates/ninep/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use crate::{
fs::{Mode, Perm, Stat},
protocol::{Data, Format9p, RawStat, Rdata, Rmessage, Tdata, Tmessage},
Stream,
};
use std::{
cmp::min,
Expand Down Expand Up @@ -39,54 +40,32 @@ macro_rules! expect_rmessage {
const MSIZE: u32 = u16::MAX as u32;
const VERSION: &str = "9P2000";

#[derive(Debug)]
enum Socket {
Unix(UnixStream),
Tcp(TcpStream),
}

impl io::Write for Socket {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self {
Self::Unix(s) => s.write(buf),
Self::Tcp(s) => s.write(buf),
}
}

fn flush(&mut self) -> io::Result<()> {
match self {
Self::Unix(s) => s.flush(),
Self::Tcp(s) => s.flush(),
}
}
}

impl io::Read for Socket {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
Self::Unix(s) => s.read(buf),
Self::Tcp(s) => s.read(buf),
}
}
}

fn err<T, E>(e: E) -> io::Result<T>
where
E: Into<Box<dyn std::error::Error + Send + Sync>>,
{
Err(io::Error::new(io::ErrorKind::Other, e))
}

pub type UnixClient = Client<UnixStream>;
pub type TcpClient = Client<TcpStream>;

#[derive(Debug)]
pub struct Client {
socket: Socket,
pub struct Client<S>
where
S: Stream,
{
stream: S,
uname: String,
msize: u32,
fids: HashMap<String, u32>,
next_fid: u32,
}

impl Drop for Client {
impl<S> Drop for Client<S>
where
S: Stream,
{
fn drop(&mut self) {
let fids = std::mem::take(&mut self.fids);
for (_, fid) in fids.into_iter() {
Expand All @@ -95,18 +74,18 @@ impl Drop for Client {
}
}

impl Client {
impl Client<UnixStream> {
pub fn new_unix_with_explicit_path(
uname: String,
path: String,
aname: impl Into<String>,
) -> io::Result<Self> {
let socket = UnixStream::connect(path)?;
let stream = UnixStream::connect(path)?;
let mut fids = HashMap::new();
fids.insert(String::new(), 0);

let mut client = Self {
socket: Socket::Unix(socket),
stream,
uname,
msize: MSIZE,
fids,
Expand All @@ -127,17 +106,19 @@ impl Client {

Self::new_unix_with_explicit_path(uname, path, aname)
}
}

impl Client<TcpStream> {
pub fn new_tcp<T>(uname: String, addr: T, aname: impl Into<String>) -> io::Result<Self>
where
T: ToSocketAddrs,
{
let socket = TcpStream::connect(addr)?;
let stream = TcpStream::connect(addr)?;
let mut fids = HashMap::new();
fids.insert(String::new(), 0);

let mut client = Self {
socket: Socket::Tcp(socket),
stream,
uname,
msize: MSIZE,
fids,
Expand All @@ -147,12 +128,17 @@ impl Client {

Ok(client)
}
}

impl<S> Client<S>
where
S: Stream,
{
fn send(&mut self, tag: u16, content: Tdata) -> io::Result<Rmessage> {
let t = Tmessage { tag, content };
t.write_to(&mut self.socket)?;
t.write_to(&mut self.stream)?;

match Rmessage::read_from(&mut self.socket)? {
match Rmessage::read_from(&mut self.stream)? {
Rmessage {
content: Rdata::Error { ename },
..
Expand Down Expand Up @@ -311,7 +297,7 @@ impl Client {
Ok(stats)
}

pub fn iter_chunks(&mut self, path: impl Into<String>) -> io::Result<ChunkIter> {
pub fn iter_chunks(&mut self, path: impl Into<String>) -> io::Result<ChunkIter<S>> {
let fid = self.walk(path)?;
let mode = Mode::FILE.bits();
let count = self.msize;
Expand All @@ -325,7 +311,7 @@ impl Client {
})
}

pub fn iter_lines(&mut self, path: impl Into<String>) -> io::Result<ReadLineIter> {
pub fn iter_lines(&mut self, path: impl Into<String>) -> io::Result<ReadLineIter<S>> {
let fid = self.walk(path)?;
let mode = Mode::FILE.bits();
let count = self.msize;
Expand Down Expand Up @@ -416,14 +402,20 @@ impl Client {
}
}

pub struct ChunkIter<'a> {
client: &'a mut Client,
pub struct ChunkIter<'a, S>
where
S: Stream,
{
client: &'a mut Client<S>,
fid: u32,
offset: u64,
count: u32,
}

impl<'a> Iterator for ChunkIter<'a> {
impl<'a, S> Iterator for ChunkIter<'a, S>
where
S: Stream,
{
type Item = Vec<u8>;

fn next(&mut self) -> Option<Self::Item> {
Expand All @@ -443,16 +435,22 @@ impl<'a> Iterator for ChunkIter<'a> {
}
}

pub struct ReadLineIter<'a> {
client: &'a mut Client,
pub struct ReadLineIter<'a, S>
where
S: Stream,
{
client: &'a mut Client<S>,
buf: Vec<u8>,
fid: u32,
offset: u64,
count: u32,
at_eof: bool,
}

impl<'a> Iterator for ReadLineIter<'a> {
impl<'a, S> Iterator for ReadLineIter<'a, S>
where
S: Stream,
{
type Item = String;

fn next(&mut self) -> Option<Self::Item> {
Expand Down
32 changes: 32 additions & 0 deletions crates/ninep/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,38 @@
//! A simple 9p Protocol implementation for serving filesystem interfaces
use std::{
io::{Read, Write},
net::TcpStream,
os::unix::net::UnixStream,
};

pub mod client;
pub mod fs;
pub mod protocol;
pub mod server;

use protocol::{Format9p, Rdata, Rmessage};

pub type Result<T> = std::result::Result<T, String>;

pub trait Stream: Read + Write + Send + Sized + 'static {
/// The underlying try_clone implementations for file descriptors can fail at the libc level so
/// we need to account for that here.
fn try_clone(&self) -> Result<Self>;

fn reply(&mut self, tag: u16, resp: Result<Rdata>) {
let r: Rmessage = (tag, resp).into();
let _ = r.write_to(self);
}
}

impl Stream for UnixStream {
fn try_clone(&self) -> Result<Self> {
self.try_clone().map_err(|e| e.to_string())
}
}

impl Stream for TcpStream {
fn try_clone(&self) -> Result<Self> {
self.try_clone().map_err(|e| e.to_string())
}
}
31 changes: 3 additions & 28 deletions crates/ninep/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
use crate::{
fs::{FileMeta, FileType, IoUnit, Mode, Perm, Stat, QID_ROOT},
protocol::{Data, Format9p, Qid, RawStat, Rdata, Rmessage, Tdata, Tmessage, MAX_DATA_LEN},
Result, Stream,
};
use std::{
cmp::min,
collections::btree_map::{BTreeMap, Entry},
env, fs,
io::{Read, Write},
mem::size_of,
net::{TcpListener, TcpStream},
os::unix::net::{UnixListener, UnixStream},
net::TcpListener,
os::unix::net::UnixListener,
sync::{mpsc::Receiver, Arc, Mutex, RwLock},
thread::{spawn, JoinHandle},
};
Expand Down Expand Up @@ -64,8 +64,6 @@ const E_INVALID_OFFSET: &str = "invalid offset for read on directory";
const UNKNOWN_VERSION: &str = "unknown";
const SUPPORTED_VERSION: &str = "9P2000";

pub type Result<T> = std::result::Result<T, String>;

impl From<(u16, Result<Rdata>)> for Rmessage {
fn from((tag, content): (u16, Result<Rdata>)) -> Self {
Rmessage {
Expand Down Expand Up @@ -154,29 +152,6 @@ pub trait Serve9p: Send + 'static {
fn write_stat(&mut self, qid: u64, stat: Stat, uname: &str) -> Result<()>;
}

trait Stream: Read + Write + Send + Sized + 'static {
/// The underlying try_clone implementations for file descriptors can fail at the libc level so
/// we need to account for that here.
fn try_clone(&self) -> Result<Self>;

fn reply(&mut self, tag: u16, resp: Result<Rdata>) {
let r: Rmessage = (tag, resp).into();
let _ = r.write_to(self);
}
}

impl Stream for UnixStream {
fn try_clone(&self) -> Result<Self> {
self.try_clone().map_err(|e| e.to_string())
}
}

impl Stream for TcpStream {
fn try_clone(&self) -> Result<Self> {
self.try_clone().map_err(|e| e.to_string())
}
}

/// A threaded `9p` server capable of listening on either a TCP socket or UNIX domain socket.
#[derive(Debug)]
pub struct Server<S>
Expand Down
3 changes: 2 additions & 1 deletion src/fsys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
use crate::editor::InputEvent;
use ninep::{
fs::{FileMeta, IoUnit, Mode, Perm, Stat},
server::{ReadOutcome, Result, Serve9p, Server},
server::{ReadOutcome, Serve9p, Server},
Result,
};
use std::{
env,
Expand Down

0 comments on commit e6a84d7

Please sign in to comment.