Skip to content

Commit

Permalink
Add two-way IPC channel (server-client still)
Browse files Browse the repository at this point in the history
  • Loading branch information
penumbra23 committed Sep 15, 2021
1 parent 3b824fc commit ed851b0
Showing 1 changed file with 157 additions and 1 deletion.
158 changes: 157 additions & 1 deletion src/core/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,141 @@ impl IpcChild {
}
}

pub struct IpcChannel {
fd: i32,
sock_path: String,
_client: Option<i32>,
}

impl IpcChannel {
pub fn new(path: &String) -> Result<IpcChannel> {
let socket_raw_fd = socket(
AddressFamily::Unix,
SockType::SeqPacket,
SockFlag::SOCK_CLOEXEC,
None,
)
.map_err(|_| Error {
msg: "unable to create IPC socket".to_string(),
err_type: ErrorType::Runtime,
})?;

let sockaddr = SockAddr::new_unix(Path::new(path)).map_err(|_| Error {
msg: "unable to create unix socket".to_string(),
err_type: ErrorType::Runtime,
})?;

bind(socket_raw_fd, &sockaddr).map_err(|_| Error {
msg: "unable to bind IPC socket".to_string(),
err_type: ErrorType::Runtime,
})?;

listen(socket_raw_fd, 10).map_err(|_| Error {
msg: "unable to listen IPC socket".to_string(),
err_type: ErrorType::Runtime,
})?;
Ok(IpcChannel {
fd: socket_raw_fd,
sock_path: path.clone(),
_client: None,
})
}

pub fn connect(path: &String) -> Result<IpcChannel> {
let socket_raw_fd = socket(
AddressFamily::Unix,
SockType::SeqPacket,
SockFlag::SOCK_CLOEXEC,
None,
)
.map_err(|_| Error {
msg: "unable to create IPC socket".to_string(),
err_type: ErrorType::Runtime,
})?;

let sockaddr = SockAddr::new_unix(Path::new(path)).map_err(|_| Error {
msg: "unable to create unix socket".to_string(),
err_type: ErrorType::Runtime,
})?;

connect(socket_raw_fd, &sockaddr).map_err(|_| Error {
msg: "unable to connect to unix socket".to_string(),
err_type: ErrorType::Runtime,
})?;

Ok(IpcChannel {
fd: socket_raw_fd,
sock_path: path.clone(),
_client: None,
})
}

pub fn accept(&mut self) -> Result<()> {
let child_socket_fd = nix::sys::socket::accept(self.fd).map_err(|_| Error {
msg: "unable to accept incoming socket".to_string(),
err_type: ErrorType::Runtime,
})?;

self._client = Some(child_socket_fd);
Ok(())
}

pub fn send(&self, msg: &str) -> Result<()> {
let fd = match self._client {
Some(fd) => fd,
None => self.fd,
};

write(fd, msg.as_bytes()).map_err(|err| Error {
msg: format!("unable to write to unix socket {}", err),
err_type: ErrorType::Runtime,
})?;

Ok(())
}

pub fn recv(&self) -> Result<String> {
let fd = match self._client {
Some(fd) => fd,
None => self.fd,
};
let mut buf = [0; 1024];
let num = read(fd, &mut buf).unwrap();

match std::str::from_utf8(&buf[0..num]) {
Ok(str) => Ok(str.trim().to_string()),
Err(_) => Err(Error {
msg: "error while converting byte to string {}".to_string(),
err_type: ErrorType::Runtime,
}),
}
}

pub fn send_recv(&self, msg: &str) -> Result<String> {
self.send(msg)?;
Ok(self.recv()?)
}

pub fn close(&self) -> Result<()> {
close(self.fd).map_err(|_| Error {
msg: "error closing socket".to_string(),
err_type: ErrorType::Runtime,
})?;

std::fs::remove_file(&self.sock_path).map_err(|_| Error {
msg: "error removing socket".to_string(),
err_type: ErrorType::Runtime,
})?;

Ok(())
}
}

#[cfg(test)]
mod tests {
use serial_test::serial;

use crate::core::ipc::IpcChild;
use crate::core::ipc::{IpcChannel, IpcChild};

use super::IpcParent;

Expand Down Expand Up @@ -183,4 +313,30 @@ mod tests {
parent1.close().unwrap();
parent2.close().unwrap();
}

#[test]
#[serial]
fn channel() {
let path = String::from("./tmp.sock");
let mut ch1 = IpcChannel::new(&path).unwrap();

let _ = std::thread::spawn(|| {
let ch2 = IpcChannel::connect(&String::from("./tmp.sock")).unwrap();
let mut res = ch2.send_recv("hi").unwrap();
assert_eq!(res, "hello");
res = ch2.send_recv("whadup").unwrap();
assert_eq!(res, "nothing");
ch2.send("bye").unwrap();
});

ch1.accept().unwrap();
let mut res = ch1.recv().unwrap();
assert_eq!(res, "hi");
res = ch1.send_recv("hello").unwrap();
assert_eq!(res, "whadup");
res = ch1.send_recv("nothing").unwrap();
assert_eq!(res, "bye");

ch1.close().unwrap();
}
}

0 comments on commit ed851b0

Please sign in to comment.