use std::os::fd::OwnedFd;
use vsock::{VsockAddr, VsockStream};
use super::{read_frame, write_frame, PeerIdentity, RpcTransport};
use crate::rpc::RpcResult;
pub struct VsockTransport {
stream: VsockStream,
peer: PeerIdentity,
desc: String,
}
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 })
}
}
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::io::Write;
let mut w = &self.stream;
super::write_all_reporting(&mut w, buf)?;
w.flush()?;
Ok(())
}
fn recv_raw(&self, buf: &mut [u8]) -> RpcResult<usize> {
use std::io::Read;
let mut r = &self.stream;
loop {
return match r.read(buf) {
Ok(n) => Ok(n),
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) if super::is_timeout(&e) => Err(crate::rpc::RpcError::Timeout),
Err(e) => Err(e.into()),
};
}
}
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)?;
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))
}
}