unix sockets

This commit is contained in:
Toshit Chawda 2024-03-09 14:21:13 -08:00
parent a8709255b2
commit bc52ea54f3
2 changed files with 78 additions and 11 deletions

View file

@ -29,15 +29,20 @@ See `client/demo.js` for more examples.
$ cargo r -r --bin epoxy-server -- --help $ cargo r -r --bin epoxy-server -- --help
Implementation of the Wisp protocol in Rust, made for epoxy. Implementation of the Wisp protocol in Rust, made for epoxy.
Usage: epoxy-server [OPTIONS] --pubkey <PUBKEY> --privkey <PRIVKEY> Usage: epoxy-server [OPTIONS]
Options: Options:
--prefix <PREFIX> [default: ] --prefix <PREFIX> [default: ]
-l, --port <PORT> [default: 4000] -p, --port <PORT> [default: 4000]
-p, --pubkey <PUBKEY> -b, --host <HOST> [default: 0.0.0.0]
-P, --privkey <PRIVKEY> -u, --unix-socket
-h, --help Print help -h, --help Print help
-V, --version Print version -V, --version Print version
```
You can listen on a unix socket by passing the `--unix-socket` flag and the unix socket path in the `--host` flag. Example:
```
cargo r -r -- -u -b "/home/user/epoxy-socket"
``` ```
## Building ## Building

View file

@ -13,7 +13,11 @@ use hyper::{
}; };
use hyper_util::rt::TokioIo; use hyper_util::rt::TokioIo;
use tokio::net::{TcpListener, TcpStream, UdpSocket}; use tokio::net::{TcpListener, TcpStream, UdpSocket};
#[cfg(unix)]
use tokio::net::{UnixListener, UnixStream};
use tokio_util::codec::{BytesCodec, Framed}; use tokio_util::codec::{BytesCodec, Framed};
#[cfg(unix)]
use tokio_util::either::Either;
use wisp_mux::{ use wisp_mux::{
ws, CloseReason, ConnectPacket, MuxEvent, MuxStream, ServerMux, StreamType, WispError, ws, CloseReason, ConnectPacket, MuxEvent, MuxStream, ServerMux, StreamType, WispError,
@ -30,14 +34,72 @@ struct Cli {
port: String, port: String,
#[arg(long = "host", short, value_name = "HOST", default_value = "0.0.0.0")] #[arg(long = "host", short, value_name = "HOST", default_value = "0.0.0.0")]
bind_host: String, bind_host: String,
#[arg(long, short)]
unix_socket: bool,
}
#[cfg(not(unix))]
type ListenerStream = TcpStream;
#[cfg(unix)]
type ListenerStream = Either<TcpStream, UnixStream>;
enum Listener {
Tcp(TcpListener),
#[cfg(unix)]
Unix(UnixListener),
}
impl Listener {
pub async fn accept(&self) -> Result<(ListenerStream, String), std::io::Error> {
Ok(match self {
Listener::Tcp(listener) => {
let (stream, addr) = listener.accept().await?;
#[cfg(not(unix))]
{
(stream, addr.to_string())
}
#[cfg(unix)]
{
(Either::Left(stream), addr.to_string())
}
}
#[cfg(unix)]
Listener::Unix(listener) => {
let (stream, addr) = listener.accept().await?;
(
Either::Right(stream),
addr.as_pathname()
.map(|x| x.to_string_lossy().into())
.unwrap_or("unknown_unix_socket".into()),
)
}
})
}
}
async fn bind(addr: &str, unix: bool) -> Result<Listener, std::io::Error> {
#[cfg(unix)]
if unix {
return Ok(Listener::Unix(UnixListener::bind(addr)?));
}
#[cfg(not(unix))]
if unix {
panic!("Unix sockets are only supported on Unix.");
}
Ok(Listener::Tcp(TcpListener::bind(addr).await?))
} }
#[tokio::main(flavor = "multi_thread")] #[tokio::main(flavor = "multi_thread")]
async fn main() -> Result<(), Error> { async fn main() -> Result<(), Error> {
let opt = Cli::parse(); let opt = Cli::parse();
let addr = format!("{}:{}", opt.bind_host, opt.port); let addr = if opt.unix_socket {
opt.bind_host
} else {
format!("{}:{}", opt.bind_host, opt.port)
};
let socket = TcpListener::bind(&addr).await.expect("failed to bind"); let socket = bind(&addr, opt.unix_socket).await?;
println!("listening on `{}`", addr); println!("listening on `{}`", addr);
while let Ok((stream, addr)) = socket.accept().await { while let Ok((stream, addr)) = socket.accept().await {
@ -45,12 +107,12 @@ async fn main() -> Result<(), Error> {
tokio::spawn(async move { tokio::spawn(async move {
let io = TokioIo::new(stream); let io = TokioIo::new(stream);
let service = let service =
service_fn(move |res| accept_http(res, addr.to_string(), prefix_cloned.clone())); service_fn(move |res| accept_http(res, addr.clone(), prefix_cloned.clone()));
let conn = http1::Builder::new() let conn = http1::Builder::new()
.serve_connection(io, service) .serve_connection(io, service)
.with_upgrades(); .with_upgrades();
if let Err(err) = conn.await { if let Err(err) = conn.await {
println!("{:?}: failed to serve conn: {:?}", addr, err); println!("failed to serve conn: {:?}", err);
} }
}); });
} }