openvmm: support rpc over named pipes - #4389
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The new stream adapters should avoid potentially blocking reads on zero-length buffers to prevent subtle hangs in async I/O paths.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR extends OpenVMM’s RPC server to support Windows named pipes as an alternative to Unix domain sockets, enabling non-TCP transports for ttrpc/gRPC clients on Windows.
Changes:
- Add a Windows named-pipe listener mode for the
--rpcserver and dispatch loop. - Generalize
mesh_rpc::Server::{serve_connection, serve_connection_grpc}to accept generic async read/write streams (not just sockets). - Update CLI parsing/docs and expand VMM tests to cover named-pipe endpoints on Windows.
File summaries
| File | Description |
|---|---|
| vmm_tests/vmm_tests/tests/tests/ttrpc.rs | Adds Windows coverage for RPC over named pipes and threads endpoint type through the OpenVMM launcher and client dialer. |
| support/mesh/mesh_rpc/src/server.rs | Generalizes server connection handlers to accept futures::AsyncRead/AsyncWrite streams, improving transport flexibility. |
| openvmm/openvmm_entry/src/ttrpc/mod.rs | Introduces Listener abstraction and named-pipe accept/dispatch path on Windows, including prefix-based protocol sniffing for pipes. |
| openvmm/openvmm_entry/src/lib.rs | Wires --rpc listener selection into runtime: unix socket vs Windows named pipe. |
| openvmm/openvmm_entry/src/cli_args.rs | Extends --rpc syntax with `listener=<unix |
| Guide/src/reference/openvmm/management/grpc.md | Documents listener=pipe usage for Windows named-pipe RPC endpoints. |
Review details
Suppressed comments (1)
support/mesh/mesh_rpc/src/server.rs:386
- In this
Wrap<T>TokioAsyncReadadapter, it’s safer to short-circuit when theReadBufhas no remaining capacity. Otherwise the innerfutures::AsyncReadmay be polled with an empty slice, which can block instead of returning immediately.
impl<T: AsyncRead + Unpin> tokio::io::AsyncRead for Wrap<T> {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
- Files reviewed: 6/6 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🔵 Needs a closer look
The Windows named-pipe client dialer lacks bounded retry handling for common transient pipe-open failures, risking flaky tests, and CLI parsing should reject listener=pipe on non-Windows earlier for a clearer failure mode.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
openvmm/openvmm_entry/src/cli_args.rs:1998
listener=pipeis documented as Windows-only, butRpcCli::from_strcurrently accepts it on non-Windows targets and only errors later during runtime startup. Rejecting it during option parsing provides a clearer, earlier failure mode and avoids accepting an unsupported configuration.
vmm_tests/vmm_tests/tests/tests/ttrpc.rs:1113- Named pipe connection setup can be transiently unavailable (e.g. server still starting, pipe not yet created, or ERROR_PIPE_BUSY).
dial()currently fails immediately on these cases, which can make the Windows named-pipe test path flaky. Consider retrying open for a bounded time when the error is NotFound or ERROR_PIPE_BUSY.
- Files reviewed: 7/7 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
The current named-pipe path detection is case-sensitive on Windows (can misroute valid \\.\PIPE\... inputs), and the public UnixDialier→UnixDialer rename should preserve compatibility via a deprecated alias.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
support/mesh/mesh_rpc/src/client.rs:72
- Renaming the public
UnixDialiertype toUnixDialeris an API-breaking change for any external users ofmesh_rpc. Consider keeping a deprecated type alias for backward compatibility (the alias will still expose::newand other inherent methods).
- Files reviewed: 7/7 changed files
- Comments generated: 2
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
It introduces at least one breaking public API rename and a new named-pipe accept loop that currently drops accept errors silently, both of which should be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
support/mesh/mesh_rpc/src/client.rs:73
UnixDialierwas a public type; renaming it toUnixDialeris a breaking change for downstream crates. Consider keeping a deprecated type alias so existing callers continue to compile while migrating to the corrected name.
- Files reviewed: 8/8 changed files
- Comments generated: 2
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
The new named-pipe accept loop drops pending accepts in a way that can block the async runtime, and the gRPC stream adapter’s shutdown path likely fails on PolledPipe (both are fixable but should be addressed before approval).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
support/mesh/mesh_rpc/src/server.rs:399
- The Tokio adapter for
futures::AsyncWritein thisWrap<T>impl mapspoll_shutdown()topoll_close()(see below in this impl). Forpal_async::pipe::PolledPipe,poll_close()returnsUnsupported, which will likely surface as an I/O error when serving gRPC over named pipes. Consider treatingUnsupportedas a successful shutdown (drop will still close the handle).
- Files reviewed: 8/8 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
The Windows named-pipe server path in openvmm_entry/src/ttrpc/mod.rs contains a compile-breaking call signature mismatch in serve_pipe.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 2
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
The new named-pipe accept loop currently drops accept/wrap errors without logging, which can mask connectivity failures and complicate diagnosis.
Review details
Suppressed comments (1)
openvmm/openvmm_entry/src/ttrpc/mod.rs:329
- In the named-pipe accept loop, errors from
acceptand fromPolledPipe::neware silently ignored, which can make failures hard to diagnose (and can lead to a server that appears to hang without any logs). Please log these error cases explicitly instead of dropping them.
result = accept => {
accept.set(listener.accept(driver)?.fuse());
if let Ok(conn) = result.and_then(|conn| pal_async::pipe::PolledPipe::new(driver, conn)) {
tasks.push(async move {
let _ = serve_pipe(server, conn, transport)
- Files reviewed: 8/8 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
The gRPC stream adapter can treat named-pipe shutdown as an error (unsupported close semantics), which risks spurious failures/log noise for gRPC over named pipes.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
support/mesh/mesh_rpc/src/server.rs:399
serve_connection_grpcmapstokio::io::AsyncWrite::poll_shutdownto the underlying stream’sfutures::AsyncWrite::poll_close. This returnsErrorKind::Unsupportedforpal_async::pipe::PolledPipe, which can surface as spurious connection errors when serving gRPC over named pipes. Consider treatingUnsupportedas a successful shutdown (best-effort), since pipes don’t support a socket-like half-close.
- Files reviewed: 8/8 changed files
- Comments generated: 0 new
- Review effort level: Lite
Tonic, a Rust RPC framework that uses Tokio as its async runtime, allows consumers to define a
Connectorthat builds aChannelover non-TCP transports such as UDS or named pipes.Windows clients could supply a connector over AF_UNIX, but doing so requires a custom async socket adapter: implementing Tokio’s AsyncRead and AsyncWrite traits around Winsock APIs.
Tokio already exposes Windows named pipes as AsyncRead/AsyncWrite streams. Tonic can consume those streams through the standard TokioIo adapter, so Windows OpenVMM clients need only a small connector that opens the named pipe.
This PR allows OpenVMM to expose its RPC server over a named-pipe listener.