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.
|
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.
|
||||||
|
@ -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"
|
||||||
|
@ -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> {
|
||||||
|
@ -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");
|
||||||
|
Loading…
Reference in New Issue
Block a user