Merge pull request #13 from ashleysmithgpu/master

Changed sockets to nix crate
This commit is contained in:
ilyazzz 2021-03-02 18:19:06 +02:00 committed by GitHub
commit 9048e8341a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 129 additions and 85 deletions

View File

@ -40,8 +40,6 @@ sudo systemctl enable --now lactd
```
You can now use the application.
Note: By default, only members of the group `wheel` can change settings. This can be changed by editing `/etc/lact.json` and changing the `group` value.
# CLI
There is also a cli available.

View File

@ -16,4 +16,5 @@ env_logger = "0.8"
rand = "0.8"
signal-hook = "0.3"
pciid-parser = { git = "https://github.com/ilyazzz/pci-id-parser.git" }
reqwest = { version = "0.11", features = ["blocking", "json"] }
reqwest = { version = "0.11", features = ["blocking", "json"] }
nix = "0.20"

View File

@ -1,53 +1,84 @@
use crate::config::Config;
use crate::gpu_controller::{FanControlInfo, GpuStats};
use crate::gpu_controller::{GpuInfo, PowerProfile};
use crate::Daemon;
use crate::DaemonError;
use crate::{
config::Config,
gpu_controller::{FanControlInfo, GpuStats},
};
use crate::{Action, DaemonResponse, SOCK_PATH};
use std::collections::{BTreeMap, HashMap};
use std::io::{Read, Write};
use std::os::unix::net::UnixStream;
#[derive(Clone, Copy)]
pub struct DaemonConnection {}
pub const BUFFER_SIZE: usize = 4096;
impl DaemonConnection {
pub fn new() -> Result<Self, DaemonError> {
match UnixStream::connect(SOCK_PATH) {
Ok(mut stream) => {
stream
.write(&bincode::serialize(&Action::CheckAlive).unwrap())
.unwrap();
let addr = nix::sys::socket::SockAddr::Unix(
nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(),
);
let socket = nix::sys::socket::socket(
nix::sys::socket::AddressFamily::Unix,
nix::sys::socket::SockType::Stream,
nix::sys::socket::SockFlag::empty(),
None,
)
.expect("Creating socket failed");
nix::sys::socket::connect(socket, &addr).expect("Socket connect failed");
stream
.shutdown(std::net::Shutdown::Write)
.expect("Could not shut down");
nix::unistd::write(socket, &bincode::serialize(&Action::CheckAlive).unwrap())
.expect("Writing check alive to socket failed");
let mut buffer = Vec::<u8>::new();
stream.read_to_end(&mut buffer).unwrap();
nix::sys::socket::shutdown(socket, nix::sys::socket::Shutdown::Write)
.expect("Could not shut down");
let result: Result<DaemonResponse, DaemonResponse> =
bincode::deserialize(&buffer).unwrap();
match result {
Ok(_) => Ok(DaemonConnection {}),
Err(_) => Err(DaemonError::ConnectionFailed),
let mut buffer = Vec::<u8>::new();
buffer.resize(BUFFER_SIZE, 0);
loop {
match nix::unistd::read(socket, &mut buffer) {
Ok(0) => {
break;
}
Ok(n) => {
assert!(n < buffer.len());
if n < buffer.len() {
buffer.resize(n, 0);
}
break;
}
Err(e) => {
panic!("Error reading from socket: {}", e);
}
}
}
let result: Result<DaemonResponse, DaemonResponse> =
bincode::deserialize(&buffer).expect("failed to deserialize message");
match result {
Ok(_) => Ok(DaemonConnection {}),
Err(_) => Err(DaemonError::ConnectionFailed),
}
}
fn send_action(&self, action: Action) -> Result<DaemonResponse, DaemonError> {
let mut s = UnixStream::connect(SOCK_PATH).expect("Connection to daemon dropped");
let addr = nix::sys::socket::SockAddr::Unix(
nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(),
);
let socket = nix::sys::socket::socket(
nix::sys::socket::AddressFamily::Unix,
nix::sys::socket::SockType::Stream,
nix::sys::socket::SockFlag::empty(),
None,
)
.expect("Socket failed");
nix::sys::socket::connect(socket, &addr).expect("connect failed");
s.write(&bincode::serialize(&action).unwrap())
.expect("Failed to write");
s.shutdown(std::net::Shutdown::Write)
.expect("Could nto shut down");
let b = bincode::serialize(&action).unwrap();
nix::unistd::write(socket, &b).expect("Writing action to socket failed");
let mut buffer = Vec::<u8>::new();
s.read_to_end(&mut buffer).unwrap();
nix::sys::socket::shutdown(socket, nix::sys::socket::Shutdown::Write)
.expect("Could not shut down");
let buffer = Daemon::read_buffer(socket);
bincode::deserialize(&buffer).expect("failed to deserialize message")
}
@ -156,9 +187,19 @@ impl DaemonConnection {
}
pub fn shutdown(&self) {
let mut s = UnixStream::connect(SOCK_PATH).unwrap();
s.write_all(&bincode::serialize(&Action::Shutdown).unwrap())
.unwrap();
let addr = nix::sys::socket::SockAddr::Unix(
nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(),
);
let socket = nix::sys::socket::socket(
nix::sys::socket::AddressFamily::Unix,
nix::sys::socket::SockType::Stream,
nix::sys::socket::SockFlag::empty(),
None,
)
.expect("Socket failed");
nix::sys::socket::connect(socket, &addr).expect("connect failed");
nix::unistd::write(socket, &mut &bincode::serialize(&Action::Shutdown).unwrap())
.expect("Writing shutdown to socket failed");
}
pub fn get_config(&self) -> Result<Config, DaemonError> {

View File

@ -8,24 +8,22 @@ use gpu_controller::PowerProfile;
use pciid_parser::PciDatabase;
use rand::prelude::*;
use serde::{Deserialize, Serialize};
use std::os::unix::net::{UnixListener, UnixStream};
use std::process::Command;
use std::path::PathBuf;
use std::{
collections::{BTreeMap, HashMap},
fs,
};
use std::{
io::{Read, Write},
path::PathBuf,
};
use crate::gpu_controller::GpuController;
pub const SOCK_PATH: &str = "/tmp/amdgpu-configurator.sock";
// Abstract socket allows anyone to connect without worrying about permissions
// https://unix.stackexchange.com/questions/579612/unix-domain-sockets-for-non-root-user
pub const SOCK_PATH: &str = "amdgpu-configurator.sock";
pub const BUFFER_SIZE: usize = 4096;
pub struct Daemon {
gpu_controllers: HashMap<u32, GpuController>,
listener: UnixListener,
listener: std::os::unix::io::RawFd,
config: Config,
}
@ -53,9 +51,18 @@ pub enum Action {
impl Daemon {
pub fn new(unprivileged: bool) -> Daemon {
if fs::metadata(SOCK_PATH).is_ok() {
fs::remove_file(SOCK_PATH).expect("Failed to take control over socket");
}
let addr = nix::sys::socket::SockAddr::Unix(
nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(),
);
let listener = nix::sys::socket::socket(
nix::sys::socket::AddressFamily::Unix,
nix::sys::socket::SockType::Stream,
nix::sys::socket::SockFlag::empty(),
None,
)
.expect("Socket failed");
nix::sys::socket::bind(listener, &addr).expect("Bind failed");
nix::sys::socket::listen(listener, 128).expect("Listen failed");
let config_path = PathBuf::from("/etc/lact.json");
let mut config = if unprivileged {
@ -75,26 +82,6 @@ impl Daemon {
}
};
let listener = UnixListener::bind(SOCK_PATH).unwrap();
Command::new("chmod")
.arg("664")
.arg(SOCK_PATH)
.output()
.expect("Failed to chmod");
Command::new("chown")
.arg("nobody:wheel")
.arg(SOCK_PATH)
.output()
.expect("Failed to chown");
Command::new("chown")
.arg(&format!("nobody:{}", config.group))
.arg(SOCK_PATH)
.output()
.expect("Failed to chown");
log::info!("Using config {:?}", config);
let gpu_controllers = Self::load_gpu_controllers(&mut config);
@ -190,27 +177,45 @@ impl Daemon {
}
pub fn listen(mut self) {
let listener = self.listener.try_clone().expect("couldn't try_clone");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
//let mut controller = self.gpu_controller.clone();
//thread::spawn(move || Daemon::handle_connection(&mut controller, stream));
//Daemon::handle_connection(&mut self.gpu_controllers, stream);
Daemon::handle_connection(&mut self, stream);
}
Err(err) => {
log::error!("Error: {}", err);
break;
}
loop {
let stream = nix::sys::socket::accept(self.listener).expect("Accept failed");
if stream < 0 {
log::error!("Error from accept");
break;
} else {
Daemon::handle_connection(&mut self, stream);
}
}
}
fn handle_connection(&mut self, mut stream: UnixStream) {
pub fn read_buffer(stream: i32) -> Vec<u8> {
log::trace!("Reading buffer");
let mut buffer = Vec::<u8>::new();
stream.read_to_end(&mut buffer).unwrap();
buffer.resize(BUFFER_SIZE, 0);
loop {
match nix::unistd::read(stream, &mut buffer) {
Ok(0) => {
break;
}
Ok(n) => {
assert!(n < buffer.len());
if n < buffer.len() {
buffer.resize(n, 0);
}
break;
}
Err(e) => {
panic!("Error reading from socket: {}", e);
}
}
}
buffer
}
fn handle_connection(&mut self, stream: i32) {
let buffer = Self::read_buffer(stream);
//log::trace!("finished reading, buffer size {}", buffer.len());
log::trace!("Attempting to deserialize {:?}", &buffer);
//log::trace!("{:?}", action);
@ -418,7 +423,6 @@ impl Daemon {
controller.stop_fan_control();
}
}
fs::remove_file(SOCK_PATH).expect("Failed to remove socket");
}
std::process::exit(0);
}
@ -432,10 +436,10 @@ impl Daemon {
Action::GetConfig => Ok(DaemonResponse::Config(self.config.clone())),
};
log::trace!("Responding");
stream
.write_all(&bincode::serialize(&response).unwrap())
.expect("Failed writing response");
let buffer = bincode::serialize(&response).unwrap();
log::trace!("Responding, buffer length {}", buffer.len());
nix::unistd::write(stream, &buffer).expect("Writing response to socket failed");
//stream
// .shutdown(std::net::Shutdown::Write)
// .expect("Could not shut down");