Skip to content

feat: add MethodCall::push_fd() for passing file descriptors (SCM_RIGHTS)#149

Open
lsjostro wants to merge 1 commit into
varlink:masterfrom
lsjostro:feat/methodcall-push-fd
Open

feat: add MethodCall::push_fd() for passing file descriptors (SCM_RIGHTS)#149
lsjostro wants to merge 1 commit into
varlink:masterfrom
lsjostro:feat/methodcall-push-fd

Conversation

@lsjostro

@lsjostro lsjostro commented Jul 2, 2026

Copy link
Copy Markdown

Varlink lets a method call carry file descriptors as ancillary data (SCM_RIGHTS),
referenced from the parameters by push order — but this crate had no client-side
way to attach them. This adds that.

API

let mut call = client.some_method(args);
let idx = call.push_fd(fd)?;   // -> 0, then 1, ... (push order == the index methods reference)
call.more()?;                  // or .call()/.oneway(); fds are delivered with the request
  • MethodCall::push_fd(fd) -> io::Result<usize> (unix only). Dups the fd with
    F_DUPFD_CLOEXEC (caller keeps ownership of the original), queues it, and
    returns its push-order index.
  • On send, queued fds are delivered with the request via a single
    sendmsg() + SCM_RIGHTS on the connection's socket; any bytes past the first
    sendmsg are written normally through the existing writer.
  • Only socket-backed connections (Connection::with_address) support this; a
    reader/writer-pair connection has no socket for ancillary data, so push_fd
    returns io::ErrorKind::Unsupported.

Passing descriptors is part of the Varlink protocol; this lets a client talk to
services that accept them (e.g. handing over stdio fds).

Scope

Send-only. Receiving descriptors (server → client) is not implemented — it would
require recvmsg-based reading throughout the input path, and nothing needs it yet.
cfg(unix) only, matching the crate's existing platform split; libc is already
a unix dependency.

Tests

varlink/src/test.rs:

  • test_push_fd_passes_descriptor: push an fd over one end of a socketpair,
    recvmsg() the other end, and confirm the descriptor arrives and refers to the
    same underlying pipe (write through the received fd, read it back).
  • test_push_fd_requires_socket: push_fd on a non-socket connection returns
    Unsupported.

cargo test -p varlink passes.

…HTS)

Varlink allows a method call to carry file descriptors as ancillary data
(SCM_RIGHTS), referenced from the parameters by push order. The client side had
no way to attach them.

Add MethodCall::push_fd(fd) (unix only): it dups the fd (F_DUPFD_CLOEXEC, so the
caller keeps ownership), queues it, and returns its push-order index. send() then
delivers the queued fds with the request via a single sendmsg()/SCM_RIGHTS on the
connection's socket (any tail past the first sendmsg is written normally). Only
socket-backed connections (Connection::with_address) support this; a
reader/writer-pair connection has no socket and push_fd() returns an Unsupported
error.

This is send-only; receiving fds is not implemented.

Tested in varlink/src/test.rs: push_fd() over a socketpair, recvmsg() on the peer
confirming the descriptor arrives and refers to the same underlying pipe, plus
the Unsupported case for non-socket connections.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant