use std::os::fd::OwnedFd;
use vsock::{VsockAddr, VsockStream};
use super::{read_frame, write_frame, OutQueue, PeerIdentity, ReadDeadline, RpcTransport};
use crate::rpc::RpcResult;
pub struct VsockTransport {
stream: VsockStream,
peer: PeerIdentity,
desc: String,
reads: ReadDeadline,
queue: OutQueue,
}
impl VsockTransport {
pub fn connect(cid: u32, port: u32) -> RpcResult<Self> {
let stream = VsockStream::connect(&VsockAddr::new(cid, port))?;
Self::from_stream(stream)
}
pub fn from_owned_fd(fd: OwnedFd) -> RpcResult<Self> {
Self::from_stream(VsockStream::from(fd))
}
pub fn from_stream(stream: VsockStream) -> RpcResult<Self> {
let peer = match stream.peer_addr() {
Ok(a) => PeerIdentity::Vsock { cid: a.cid() },
Err(_) => PeerIdentity::Anonymous,
};
let desc = match stream.peer_addr() {
Ok(a) => format!("vsock:cid={},port={}", a.cid(), a.port()),
Err(_) => "vsock".to_string(),
};
Ok(VsockTransport {
stream,
peer,
desc,
reads: ReadDeadline::default(),
queue: OutQueue::default(),
})
}
}
impl RpcTransport for VsockTransport {
fn send_frame(&self, buf: &[u8]) -> RpcResult<()> {
let mut w = &self.stream;
write_frame(&mut w, buf)
}
fn recv_frame(&self) -> RpcResult<Vec<u8>> {
let mut r = &self.stream;
read_frame(&mut r)
}
fn send_raw(&self, buf: &[u8]) -> RpcResult<()> {
use std::os::fd::AsFd;
let slices = &mut [std::io::IoSlice::new(buf)];
super::unix::send_waiting(self.stream.as_fd(), &self.queue, slices, &[], None)
}
fn recv_raw(&self, buf: &mut [u8]) -> RpcResult<usize> {
use std::os::fd::AsFd;
let sock = Some(self.stream.as_fd());
self.reads.read(sock, &self.queue, || {
super::read_raw(&mut &self.stream, buf)
})
}
fn send_raw_draining(
&self,
buf: &[u8],
fds: &[std::os::fd::BorrowedFd<'_>],
drain: &mut dyn FnMut() -> RpcResult<()>,
) -> RpcResult<()> {
use std::os::fd::AsFd;
if !fds.is_empty() {
return self.send_raw_with_fds(buf, fds);
}
super::unix::send_waiting(
self.stream.as_fd(),
&self.queue,
&mut [std::io::IoSlice::new(buf)],
&[],
Some(drain),
)
}
fn peer_identity(&self) -> PeerIdentity {
self.peer.clone()
}
fn describe(&self) -> &str {
&self.desc
}
fn set_read_timeout(&self, timeout: Option<std::time::Duration>) -> RpcResult<()> {
self.stream.set_read_timeout(timeout)?;
self.reads.note(timeout);
Ok(())
}
fn set_write_timeout(&self, timeout: Option<std::time::Duration>) -> RpcResult<()> {
self.stream.set_write_timeout(timeout)?;
Ok(())
}
fn shutdown(&self) -> RpcResult<()> {
super::absorb_already_shut(self.stream.shutdown(std::net::Shutdown::Both))
}
fn peer_closed(&self) -> Option<bool> {
use std::os::fd::AsFd;
super::socket_peer_closed(self.stream.as_fd(), super::SocketKind::TcpOrVsock)
}
fn shutdown_handle(&self) -> Option<Box<dyn FnOnce() + Send>> {
use std::os::fd::AsFd;
super::socket_shutdown_handle(self.stream.as_fd())
}
}