Advice for creating stdio wrapper of a socket / mio on Windows?


#1

I’m working on making a stdio wrapper to a socket. That is, the anything that comes in on stdin would be written to the socket, and anything that gets read from the socket gets written to stdout. I have an initial solution that works well enough:

fn run() -> Result<()> {
    let path = Path::new("socket-path");
    // Eventually abstract this out to work with named-pipes and actual sockets
    let mut read_half = UnixStream::connect(socket_path)?;
    read_half.set_nonblocking(false)?;
    let mut write_half = read_half.try_clone()?;

    let t1 = thread::spawn(move || {
        copy(&mut stdin(), &mut write_half).unwrap();
    });
    thread::spawn(move || {
        copy(&mut read_half, &mut stdout()).unwrap();
    });
    let _ = t1.join();
    Ok(())
}

Having to use multiple threads kind of bugs me though, and I can’t think of a good way to make this gracefully handle interrupt signals. I think Async IO fixes this, and on Unix I believe I can do non-blocking reads from stdin by using mio::unix::EventedFd. Then I could have my main loop listen for read/write/signal events, and handle them all correctly.

Ideally, I want this to work cross platform, and I don’t know how to make the above solution work on windows (I don’t see anything in mio that works with RawHandle).

Any advice on how to make mio work with stdin/stdout on Windows would be appreciated, or maybe there’s even a simpler way of doing this that I haven’t thought of?


#2

You may want to look at https://docs.rs/tokio-process/0.2.0/tokio_process/ for inspiration.


#3

That would let me gracefully handle interrupts, thanks! Still not crazy about this being multi-threaded, so I’m going to explore mio some more.


#4

Apologies for link dropping, but https://github.com/tokio-rs/tokio-uds is a unix domain socket binding for tokio - might be a good place to see how it plugs into mio.