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. 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 # CLI
There is also a cli available. There is also a cli available.

View File

@ -17,3 +17,4 @@ rand = "0.8"
signal-hook = "0.3" signal-hook = "0.3"
pciid-parser = { git = "https://github.com/ilyazzz/pci-id-parser.git" } 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::gpu_controller::{GpuInfo, PowerProfile};
use crate::Daemon;
use crate::DaemonError; use crate::DaemonError;
use crate::{
config::Config,
gpu_controller::{FanControlInfo, GpuStats},
};
use crate::{Action, DaemonResponse, SOCK_PATH}; use crate::{Action, DaemonResponse, SOCK_PATH};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::io::{Read, Write};
use std::os::unix::net::UnixStream;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct DaemonConnection {} pub struct DaemonConnection {}
pub const BUFFER_SIZE: usize = 4096;
impl DaemonConnection { impl DaemonConnection {
pub fn new() -> Result<Self, DaemonError> { pub fn new() -> Result<Self, DaemonError> {
match UnixStream::connect(SOCK_PATH) { let addr = nix::sys::socket::SockAddr::Unix(
Ok(mut stream) => { nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(),
stream );
.write(&bincode::serialize(&Action::CheckAlive).unwrap()) let socket = nix::sys::socket::socket(
.unwrap(); 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 nix::unistd::write(socket, &bincode::serialize(&Action::CheckAlive).unwrap())
.shutdown(std::net::Shutdown::Write) .expect("Writing check alive to socket failed");
.expect("Could not shut down");
let mut buffer = Vec::<u8>::new(); nix::sys::socket::shutdown(socket, nix::sys::socket::Shutdown::Write)
stream.read_to_end(&mut buffer).unwrap(); .expect("Could not shut down");
let result: Result<DaemonResponse, DaemonResponse> = let mut buffer = Vec::<u8>::new();
bincode::deserialize(&buffer).unwrap(); buffer.resize(BUFFER_SIZE, 0);
match result { loop {
Ok(_) => Ok(DaemonConnection {}), match nix::unistd::read(socket, &mut buffer) {
Err(_) => Err(DaemonError::ConnectionFailed), 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), Err(_) => Err(DaemonError::ConnectionFailed),
} }
} }
fn send_action(&self, action: Action) -> Result<DaemonResponse, DaemonError> { 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()) let b = bincode::serialize(&action).unwrap();
.expect("Failed to write"); nix::unistd::write(socket, &b).expect("Writing action to socket failed");
s.shutdown(std::net::Shutdown::Write)
.expect("Could nto shut down");
let mut buffer = Vec::<u8>::new(); nix::sys::socket::shutdown(socket, nix::sys::socket::Shutdown::Write)
s.read_to_end(&mut buffer).unwrap(); .expect("Could not shut down");
let buffer = Daemon::read_buffer(socket);
bincode::deserialize(&buffer).expect("failed to deserialize message") bincode::deserialize(&buffer).expect("failed to deserialize message")
} }
@ -156,9 +187,19 @@ impl DaemonConnection {
} }
pub fn shutdown(&self) { pub fn shutdown(&self) {
let mut s = UnixStream::connect(SOCK_PATH).unwrap(); let addr = nix::sys::socket::SockAddr::Unix(
s.write_all(&bincode::serialize(&Action::Shutdown).unwrap()) nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(),
.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> { pub fn get_config(&self) -> Result<Config, DaemonError> {

View File

@ -8,24 +8,22 @@ use gpu_controller::PowerProfile;
use pciid_parser::PciDatabase; use pciid_parser::PciDatabase;
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::os::unix::net::{UnixListener, UnixStream}; use std::path::PathBuf;
use std::process::Command;
use std::{ use std::{
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
fs, fs,
}; };
use std::{
io::{Read, Write},
path::PathBuf,
};
use crate::gpu_controller::GpuController; 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 { pub struct Daemon {
gpu_controllers: HashMap<u32, GpuController>, gpu_controllers: HashMap<u32, GpuController>,
listener: UnixListener, listener: std::os::unix::io::RawFd,
config: Config, config: Config,
} }
@ -53,9 +51,18 @@ pub enum Action {
impl Daemon { impl Daemon {
pub fn new(unprivileged: bool) -> Daemon { pub fn new(unprivileged: bool) -> Daemon {
if fs::metadata(SOCK_PATH).is_ok() { let addr = nix::sys::socket::SockAddr::Unix(
fs::remove_file(SOCK_PATH).expect("Failed to take control over socket"); 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 config_path = PathBuf::from("/etc/lact.json");
let mut config = if unprivileged { 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); log::info!("Using config {:?}", config);
let gpu_controllers = Self::load_gpu_controllers(&mut config); let gpu_controllers = Self::load_gpu_controllers(&mut config);
@ -190,27 +177,45 @@ impl Daemon {
} }
pub fn listen(mut self) { pub fn listen(mut self) {
let listener = self.listener.try_clone().expect("couldn't try_clone"); loop {
for stream in listener.incoming() { let stream = nix::sys::socket::accept(self.listener).expect("Accept failed");
match stream { if stream < 0 {
Ok(stream) => { log::error!("Error from accept");
//let mut controller = self.gpu_controller.clone(); break;
//thread::spawn(move || Daemon::handle_connection(&mut controller, stream)); } else {
//Daemon::handle_connection(&mut self.gpu_controllers, stream); Daemon::handle_connection(&mut self, stream);
Daemon::handle_connection(&mut self, stream);
}
Err(err) => {
log::error!("Error: {}", err);
break;
}
} }
} }
} }
fn handle_connection(&mut self, mut stream: UnixStream) { pub fn read_buffer(stream: i32) -> Vec<u8> {
log::trace!("Reading buffer"); log::trace!("Reading buffer");
let mut buffer = Vec::<u8>::new(); 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!("finished reading, buffer size {}", buffer.len());
log::trace!("Attempting to deserialize {:?}", &buffer); log::trace!("Attempting to deserialize {:?}", &buffer);
//log::trace!("{:?}", action); //log::trace!("{:?}", action);
@ -418,7 +423,6 @@ impl Daemon {
controller.stop_fan_control(); controller.stop_fan_control();
} }
} }
fs::remove_file(SOCK_PATH).expect("Failed to remove socket");
} }
std::process::exit(0); std::process::exit(0);
} }
@ -432,10 +436,10 @@ impl Daemon {
Action::GetConfig => Ok(DaemonResponse::Config(self.config.clone())), Action::GetConfig => Ok(DaemonResponse::Config(self.config.clone())),
}; };
log::trace!("Responding"); let buffer = bincode::serialize(&response).unwrap();
stream
.write_all(&bincode::serialize(&response).unwrap()) log::trace!("Responding, buffer length {}", buffer.len());
.expect("Failed writing response"); nix::unistd::write(stream, &buffer).expect("Writing response to socket failed");
//stream //stream
// .shutdown(std::net::Shutdown::Write) // .shutdown(std::net::Shutdown::Write)
// .expect("Could not shut down"); // .expect("Could not shut down");