mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
Merge pull request #13 from ashleysmithgpu/master
Changed sockets to nix crate
This commit is contained in:
commit
9048e8341a
@ -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.
|
||||
|
@ -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"
|
||||
|
@ -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> {
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user