### Bidirectional File Descriptor Passing with asyncfd and Tokio Source: https://context7.com/chrisstaite/asyncfd/llms.txt This example showcases sending and receiving file descriptors asynchronously between two Tokio tasks. It demonstrates creating a socket pair, sending one end through a Unix stream, and then communicating over both the main stream and the passed socket. Dependencies include `asyncfd`, `tokio`, and standard Rust libraries for OS file descriptor manipulation. ```rust use std::os::fd::FromRawFd; use std::os::unix::net::UnixStream; use asyncfd::UnixFdStream; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; async fn sender(socket: UnixStream) { let mut stream = UnixFdStream::new(socket, 0).unwrap(); // Create a new socket pair and send one end to receiver let (local_end, remote_end) = UnixStream::pair().unwrap(); stream.push_outgoing_fd(remote_end); // Send message along with the file descriptor stream.write_all(b"initial socket\n").await.unwrap(); // Also write to the local end of the passed socket let mut local_stream = UnixFdStream::new(local_end, 0).unwrap(); local_stream.write_all(b"passed socket data\n").await.unwrap(); // Keep connection alive until receiver processes everything local_stream.readable().await.ok(); } async fn receiver(socket: UnixStream) { let stream = UnixFdStream::new(socket, 4).unwrap(); let reader = BufReader::new(stream); let mut lines = reader.lines(); while let Some(line) = lines.next_line().await.unwrap() { println!("Main socket: {}", line); // Check for received file descriptors after each read if let Some(fd) = lines.get_ref().get_ref().pop_incoming_fd() { // Convert RawFd to typed socket (unsafe - no type info transmitted) let received: UnixStream = unsafe { UnixStream::from_raw_fd(fd) }; let inner_reader = BufReader::new( tokio::net::UnixStream::from_std(received).unwrap() ); if let Some(inner_line) = inner_reader.lines().next_line().await.unwrap() { println!("Passed socket: {}", inner_line); } } } } #[tokio::main] async fn main() { let (client, server) = UnixStream::pair().unwrap(); tokio::join!( tokio::spawn(sender(client)), tokio::spawn(receiver(server)) ); } ``` -------------------------------- ### Check Incoming File Descriptor Count (Rust) Source: https://context7.com/chrisstaite/asyncfd/llms.txt Demonstrates how to get the number of file descriptors currently waiting in the incoming buffer using the `incoming_count` method. This is useful for checking availability before calling `pop_incoming_fd`. ```rust use std::os::unix::net::UnixStream; use asyncfd::UnixFdStream; let (_, receiver) = UnixStream::pair().unwrap(); let stream = UnixFdStream::new(receiver, 4).unwrap(); // Check how many FDs are waiting to be processed let pending_fds = stream.incoming_count(); println!("File descriptors waiting: {}", pending_fds); ``` -------------------------------- ### Add asyncfd Crate Dependency (TOML) Source: https://github.com/chrisstaite/asyncfd/blob/main/README.md This snippet shows how to add the asyncfd crate as a dependency to your Rust project by modifying the Cargo.toml file. It specifies the version of the crate to be used. ```toml # Cargo.toml [dependencies] asyncfd = "0.1.0" ``` -------------------------------- ### Create UnixFdStream from UnixStream (Rust) Source: https://context7.com/chrisstaite/asyncfd/llms.txt Demonstrates how to create a new `UnixFdStream` from an existing `std::os::unix::net::UnixStream`. The `max_read_fds` parameter limits the number of file descriptors that can be received per read operation; exceeding this limit results in silent discarding by the kernel. For send-only streams, `max_read_fds` should be set to 0. ```rust use std::os::unix::net::UnixStream; use asyncfd::UnixFdStream; // Create a Unix socket pair let (client, server) = UnixStream::pair().expect("Failed to create socket pair"); // Wrap with UnixFdStream - receive up to 4 file descriptors per message let client_stream = UnixFdStream::new(client, 4).expect("Failed to create UnixFdStream"); // For send-only streams, use 0 for max_read_fds let server_stream = UnixFdStream::new(server, 0).expect("Failed to create UnixFdStream"); ``` -------------------------------- ### Queue Outgoing File Descriptor with UnixFdStream (Rust) Source: https://context7.com/chrisstaite/asyncfd/llms.txt Shows how to queue a file descriptor for sending using `push_outgoing_fd`. Ownership of the file descriptor is transferred to the stream and will be closed automatically after transmission or when the stream is dropped. The file descriptor is sent along with the next write operation. ```rust use std::os::unix::net::UnixStream; use asyncfd::UnixFdStream; use tokio::io::AsyncWriteExt; #[tokio::main] async fn main() { let (sender_socket, _receiver_socket) = UnixStream::pair().unwrap(); let mut sender = UnixFdStream::new(sender_socket, 0).unwrap(); // Create a new socket pair to send one end to the receiver let (local_end, remote_end) = UnixStream::pair().unwrap(); // Queue the file descriptor for sending (ownership transferred) sender.push_outgoing_fd(remote_end); // Write data - the queued FD is sent along with this message sender.write_all(b"Here's a socket for you!\n").await.unwrap(); sender.shutdown().await.unwrap(); } ``` -------------------------------- ### Wait for Socket Readability with UnixFdStream (Rust) Source: https://context7.com/chrisstaite/asyncfd/llms.txt Shows how to asynchronously wait for the underlying socket to become readable using the `readable` method. This function returns when data or file descriptors are available for reading. ```rust use std::os::unix::net::UnixStream; use asyncfd::UnixFdStream; #[tokio::main] async fn main() { let (_, receiver) = UnixStream::pair().unwrap(); let stream = UnixFdStream::new(receiver, 4).unwrap(); // Wait until socket is readable stream.readable().await.expect("Socket error"); println!("Socket is now readable"); } ``` -------------------------------- ### Split UnixFdStream into Borrowed Halves (Rust) Source: https://context7.com/chrisstaite/asyncfd/llms.txt Splits a `UnixFdStream` into borrowed read and write halves. This is useful for concurrent read/write operations within the same task. It does not require moving ownership of the stream halves. ```rust use std::os::unix::net::UnixStream; use asyncfd::UnixFdStream; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; #[tokio::main] async fn main() { let (socket, _) = UnixStream::pair().unwrap(); let mut stream = UnixFdStream::new(socket, 4).unwrap(); // Split into borrowed halves let (read_half, mut write_half) = stream.split(); // Use write half to send data and FDs let (local, remote) = UnixStream::pair().unwrap(); write_half.push_outgoing_fd(remote); write_half.write_all(b"message\n").await.unwrap(); // Use read half to receive data and FDs let reader = BufReader::new(read_half); // read_half.pop_incoming_fd() to get received FDs } ``` -------------------------------- ### Split UnixFdStream into Owned Halves for Tasks (Rust) Source: https://context7.com/chrisstaite/asyncfd/llms.txt Splits a `UnixFdStream` into owned read and write halves using `into_split`. These halves can be moved to different asynchronous tasks. Ownership of the underlying stream is shared via `Arc`. ```rust use std::os::unix::net::UnixStream; use std::os::fd::FromRawFd; use asyncfd::UnixFdStream; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; #[tokio::main] async fn main() { let (first, second) = UnixStream::pair().unwrap(); // Create streams and split into owned halves let first_stream = UnixFdStream::new(first, 0).unwrap(); let (_, mut first_write) = first_stream.into_split(); let second_stream = UnixFdStream::new(second, 4).unwrap(); let (second_read, _) = second_stream.into_split(); let second_read = BufReader::new(second_read); // Spawn sender task with owned write half let sender = tokio::spawn(async move { let (local, remote) = UnixStream::pair().unwrap(); first_write.push_outgoing_fd(remote); first_write.write_all(b"hello from sender\n").await.unwrap(); first_write.shutdown().await.unwrap(); // Keep local end alive until receiver is done let mut local_stream = UnixFdStream::new(local, 0).unwrap(); local_stream.write_all(b"inner message\n").await.unwrap(); local_stream.readable().await.ok(); }); // Spawn receiver task with owned read half let receiver = tokio::spawn(async move { let mut lines = second_read.lines(); while let Some(line) = lines.next_line().await.unwrap() { println!("Received: {}", line); if let Some(fd) = lines.get_ref().get_ref().pop_incoming_fd() { let socket: UnixStream = unsafe { UnixStream::from_raw_fd(fd) }; let reader = BufReader::new( tokio::net::UnixStream::from_std(socket).unwrap() ); if let Some(inner_line) = reader.lines().next_line().await.unwrap() { println!("From passed socket: {}", inner_line); } } } }); tokio::join!(sender, receiver); } ``` -------------------------------- ### Retrieve Incoming File Descriptor from UnixFdStream (Rust) Source: https://context7.com/chrisstaite/asyncfd/llms.txt Illustrates how to retrieve the oldest file descriptor from the incoming buffer using `pop_incoming_fd`. If no file descriptors are available, it returns `None`. The returned `RawFd` requires conversion to a typed descriptor using `unsafe` code, as type information is not transmitted. ```rust use std::os::unix::net::UnixStream; use std::os::fd::FromRawFd; use asyncfd::UnixFdStream; use tokio::io::{AsyncBufReadExt, BufReader}; #[tokio::main] async fn main() { let (_sender, receiver_socket) = UnixStream::pair().unwrap(); let stream = UnixFdStream::new(receiver_socket, 4).unwrap(); let reader = BufReader::new(stream); let mut lines = reader.lines(); // After reading data, check for received file descriptors while let Some(line) = lines.next_line().await.unwrap() { println!("Received: {}", line); // Pop received file descriptor if available if let Some(fd) = lines.get_ref().get_ref().pop_incoming_fd() { // SAFETY: We trust the sender to have sent a UnixStream let received_socket: UnixStream = unsafe { UnixStream::from_raw_fd(fd) }; println!("Received a file descriptor!"); } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.