Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Framebuffer update #60

Merged
merged 10 commits into from
Oct 3, 2024
25 changes: 19 additions & 6 deletions bin/src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use rayhunter::diag_device::DiagDevice;
use axum::routing::{get, post};
use axum::Router;
use stats::get_qmdl_manifest;
use tokio::sync::mpsc::{self, Sender};
use tokio::sync::mpsc::{self, Sender, Receiver};
use tokio::sync::oneshot::error::TryRecvError;
use tokio::task::JoinHandle;
use tokio_util::task::TaskTracker;
Expand All @@ -43,11 +43,13 @@ async fn run_server(
config: &config::Config,
qmdl_store_lock: Arc<RwLock<RecordingStore>>,
server_shutdown_rx: oneshot::Receiver<()>,
ui_update_tx: Sender<framebuffer::DisplayState>,
diag_device_sender: Sender<DiagDeviceCtrlMessage>
) -> JoinHandle<()> {
let state = Arc::new(ServerState {
qmdl_store_lock,
diag_device_ctrl_sender: diag_device_sender,
ui_update_sender: ui_update_tx,
readonly_mode: config.readonly_mode
});

Expand Down Expand Up @@ -123,13 +125,15 @@ fn run_ctrl_c_thread(
})
}

async fn update_ui(task_tracker: &TaskTracker, config: &config::Config, mut ui_shutdown_rx: oneshot::Receiver<()>){
async fn update_ui(task_tracker: &TaskTracker, config: &config::Config, mut ui_shutdown_rx: oneshot::Receiver<()>, mut ui_update_rx: Receiver<framebuffer::DisplayState>){
static IMAGE_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/static/images/");
let display_level = config.ui_level;
if display_level == 0 {
info!("Invisible mode, not spawning UI.");
}

let mut display_color = framebuffer::Color565::Green;

task_tracker.spawn_blocking(move || {
let mut fb: Framebuffer = Framebuffer::new();
// this feels wrong, is there a more rusty way to do this?
Expand All @@ -149,6 +153,14 @@ async fn update_ui(task_tracker: &TaskTracker, config: &config::Config, mut ui_
Err(e) => panic!("error receiving shutdown message: {e}")

}
match ui_update_rx.try_recv() {
Ok(state) => {
display_color = Framebuffer::get_color_from_state(state);
},
Err(tokio::sync::mpsc::error::TryRecvError::Empty) => {},
Err(e) => panic!("error receiving framebuffer update message: {e}")
}

match display_level {
2 => {
fb.draw_gif(img.unwrap());
Expand All @@ -164,7 +176,7 @@ async fn update_ui(task_tracker: &TaskTracker, config: &config::Config, mut ui_
fb.draw_line(framebuffer::Color565::Cyan, 25);
},
1 | _ => {
fb.draw_line(framebuffer::Color565::Green, 2);
fb.draw_line(display_color, 2);
},
};
sleep(Duration::from_millis(100));
Expand All @@ -186,19 +198,20 @@ async fn main() -> Result<(), RayhunterError> {

let qmdl_store_lock = Arc::new(RwLock::new(init_qmdl_store(&config).await?));
let (tx, rx) = mpsc::channel::<DiagDeviceCtrlMessage>(1);
let (ui_update_tx, ui_update_rx) = mpsc::channel::<framebuffer::DisplayState>(1);
if !config.readonly_mode {
let mut dev = DiagDevice::new().await
.map_err(RayhunterError::DiagInitError)?;
dev.config_logs().await
.map_err(RayhunterError::DiagInitError)?;

run_diag_read_thread(&task_tracker, dev, rx, qmdl_store_lock.clone());
run_diag_read_thread(&task_tracker, dev, rx, ui_update_tx.clone(), qmdl_store_lock.clone());
}
let (ui_shutdown_tx, ui_shutdown_rx) = oneshot::channel();
let (server_shutdown_tx, server_shutdown_rx) = oneshot::channel::<()>();
run_ctrl_c_thread(&task_tracker, tx.clone(), server_shutdown_tx, ui_shutdown_tx, qmdl_store_lock.clone());
run_server(&task_tracker, &config, qmdl_store_lock.clone(), server_shutdown_rx, tx).await;
update_ui(&task_tracker, &config, ui_shutdown_rx).await;
run_server(&task_tracker, &config, qmdl_store_lock.clone(), server_shutdown_rx, ui_update_tx, tx).await;
update_ui(&task_tracker, &config, ui_shutdown_rx, ui_update_rx).await;

task_tracker.close();
task_tracker.wait().await;
Expand Down
20 changes: 16 additions & 4 deletions bin/src/diag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rayhunter::diag::{DataType, MessagesContainer};
use rayhunter::diag_device::DiagDevice;
use serde::Serialize;
use tokio::sync::RwLock;
use tokio::sync::mpsc::Receiver;
use tokio::sync::mpsc::{Receiver, Sender};
use rayhunter::qmdl::QmdlWriter;
use log::{debug, error, info};
use tokio::fs::File;
Expand All @@ -20,6 +20,7 @@ use tokio_util::io::ReaderStream;
use tokio_util::task::TaskTracker;
use futures::{StreamExt, TryStreamExt};

use crate::framebuffer;
use crate::qmdl_store::RecordingStore;
use crate::server::ServerState;

Expand Down Expand Up @@ -55,12 +56,12 @@ impl AnalysisWriter {

// Runs the analysis harness on the given container, serializing the results
// to the analysis file and returning the file's new length.
pub async fn analyze(&mut self, container: MessagesContainer) -> Result<usize, std::io::Error> {
pub async fn analyze(&mut self, container: MessagesContainer) -> Result<(usize, bool), std::io::Error> {
let row = self.harness.analyze_qmdl_messages(container);
if !row.is_empty() {
self.write(&row).await?;
}
Ok(self.bytes_written)
Ok((self.bytes_written, ! &row.analysis.is_empty()))
}

async fn write<T: Serialize>(&mut self, value: &T) -> Result<(), std::io::Error> {
Expand All @@ -83,6 +84,7 @@ pub fn run_diag_read_thread(
task_tracker: &TaskTracker,
mut dev: DiagDevice,
mut qmdl_file_rx: Receiver<DiagDeviceCtrlMessage>,
ui_update_sender: Sender<framebuffer::DisplayState>,
qmdl_store_lock: Arc<RwLock<RecordingStore>>
) {
task_tracker.spawn(async move {
Expand Down Expand Up @@ -143,8 +145,14 @@ pub fn run_diag_read_thread(
}

if let Some(analysis_writer) = maybe_analysis_writer.as_mut() {
let analysis_file_len = analysis_writer.analyze(container).await
let analysis_output = analysis_writer.analyze(container).await
.expect("failed to analyze container");
let (analysis_file_len, heuristic_warning) = analysis_output;
if heuristic_warning {
info!("a heuristic triggered on this run!");
ui_update_sender.send(framebuffer::DisplayState::WarningDetected).await
.expect("couldn't send ui update message: {}");
}
let mut qmdl_store = qmdl_store_lock.write().await;
let index = qmdl_store.current_entry.expect("DiagDevice had qmdl_writer, but QmdlStore didn't have current entry???");
qmdl_store.update_entry_analysis_size(index, analysis_file_len as usize).await
Expand Down Expand Up @@ -172,6 +180,8 @@ pub async fn start_recording(State(state): State<Arc<ServerState>>) -> Result<(S
let qmdl_writer = QmdlWriter::new(qmdl_file);
state.diag_device_ctrl_sender.send(DiagDeviceCtrlMessage::StartRecording((qmdl_writer, analysis_file))).await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send stop recording message: {}", e)))?;
state.ui_update_sender.send(framebuffer::DisplayState::Recording).await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send ui update message: {}", e)))?;
Ok((StatusCode::ACCEPTED, "ok".to_string()))
}

Expand All @@ -184,6 +194,8 @@ pub async fn stop_recording(State(state): State<Arc<ServerState>>) -> Result<(St
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't close current qmdl entry: {}", e)))?;
state.diag_device_ctrl_sender.send(DiagDeviceCtrlMessage::StopRecording).await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send stop recording message: {}", e)))?;
state.ui_update_sender.send(framebuffer::DisplayState::Paused).await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send ui update message: {}", e)))?;
Ok((StatusCode::ACCEPTED, "ok".to_string()))
}

Expand Down
15 changes: 15 additions & 0 deletions bin/src/framebuffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ struct Dimensions {
}

#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum Color565 {
Red = 0b1111100000000000,
Green = 0b0000011111100000,
Expand All @@ -22,6 +23,12 @@ pub enum Color565 {
Pink = 0b1111010010011111,
}

pub enum DisplayState {
Recording,
Paused,
WarningDetected,
}

#[derive(Copy, Clone)]
pub struct Framebuffer<'a> {
dimensions: Dimensions,
Expand All @@ -36,6 +43,14 @@ impl Framebuffer<'_>{
}
}

pub fn get_color_from_state(state: DisplayState) -> Color565 {
match state {
DisplayState::Paused => Color565::White,
DisplayState::Recording => Color565::Green,
DisplayState::WarningDetected => Color565::Red,
}
}

Comment on lines +46 to +53
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: idiomatically i think this should be an impl From<DisplayState> for Color565 {}, and then we could just say display_color = state.into() in the recv block

fn write(&mut self, img: DynamicImage) {
let mut width = img.width();
let mut height = img.height();
Expand Down
3 changes: 2 additions & 1 deletion bin/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ use tokio::sync::RwLock;
use tokio_util::io::ReaderStream;
use include_dir::{include_dir, Dir};

use crate::DiagDeviceCtrlMessage;
use crate::{framebuffer, DiagDeviceCtrlMessage};
use crate::qmdl_store::RecordingStore;

pub struct ServerState {
pub qmdl_store_lock: Arc<RwLock<RecordingStore>>,
pub diag_device_ctrl_sender: Sender<DiagDeviceCtrlMessage>,
pub ui_update_sender: Sender<framebuffer::DisplayState>,
pub readonly_mode: bool
}

Expand Down
5 changes: 5 additions & 0 deletions bin/static/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ th[scope='row'] {
}

tr.current {
background-color: #53fe7b;
font-weight: bold;
}

tr.warning {
background-color: #fe537b;
font-weight: bold;
}
Expand Down
3 changes: 3 additions & 0 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ tokio = { version = "1.35.1", features = ["full"] }
futures-core = "0.3.30"
futures = "0.3.30"
serde = { version = "1.0.197", features = ["derive"] }

[features]
debug = []
11 changes: 11 additions & 0 deletions lib/src/analysis/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ use crate::{diag::MessagesContainer, gsmtap_parser};

use super::{imsi_provided::ImsiProvidedAnalyzer, information_element::InformationElement, lte_downgrade::LteSib6And7DowngradeAnalyzer, null_cipher::NullCipherAnalyzer};

#[cfg(feature="debug")]
use log::warn;

#[cfg(feature="debug")]
use super::test_analyzer::TestAnalyzer;

/// Qualitative measure of how severe a Warning event type is.
/// The levels should break down like this:
/// * Low: if combined with a large number of other Warnings, user should investigate
Expand Down Expand Up @@ -102,6 +108,11 @@ impl Harness {
harness.add_analyzer(Box::new(LteSib6And7DowngradeAnalyzer{}));
harness.add_analyzer(Box::new(ImsiProvidedAnalyzer{}));
harness.add_analyzer(Box::new(NullCipherAnalyzer{}));

#[cfg(feature="debug")] {
warn!("Loading test analyzers!");
harness.add_analyzer(Box::new(TestAnalyzer{count:0}));
}
harness
}

Expand Down
1 change: 1 addition & 0 deletions lib/src/analysis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pub mod information_element;
pub mod lte_downgrade;
pub mod imsi_provided;
pub mod null_cipher;
pub mod test_analyzer;
45 changes: 45 additions & 0 deletions lib/src/analysis/test_analyzer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use std::borrow::Cow;

use telcom_parser::lte_rrc::{PCCH_MessageType, PCCH_MessageType_c1, PagingUE_Identity};

use super::analyzer::{Analyzer, Event, EventType, Severity};
use super::information_element::{InformationElement, LteInformationElement};

pub struct TestAnalyzer{
pub count: i32,
}

impl Analyzer for TestAnalyzer{
fn get_name(&self) -> Cow<str> {
Cow::from("Example Analyzer")
}

fn get_description(&self) -> Cow<str> {
Cow::from("Always returns true, if you are seeing this you are either a developer or you are about to have problems.")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol

}

fn analyze_information_element(&mut self, ie: &InformationElement) -> Option<Event> {
self.count += 1;
if self.count % 100 == 0 {
return Some(Event {
event_type: EventType::Informational ,
message: "multiple of 100 events processed".to_string(),
})
}
let InformationElement::LTE(LteInformationElement::PCCH(pcch_msg)) = ie else {
return None;
};
let PCCH_MessageType::C1(PCCH_MessageType_c1::Paging(paging)) = &pcch_msg.message else {
return None;
};
for record in &paging.paging_record_list.as_ref()?.0 {
if let PagingUE_Identity::S_TMSI(_) = record.ue_identity {
return Some(Event {
event_type: EventType::QualitativeWarning { severity: Severity::Low },
message: "TMSI was provided to cell".to_string(),
})
}
}
None
}
}
2 changes: 1 addition & 1 deletion make.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
cargo build --release --target="armv7-unknown-linux-gnueabihf"
cargo build --release --target="armv7-unknown-linux-gnueabihf" #--features debug
adb push target/armv7-unknown-linux-gnueabihf/release/rayhunter-daemon /data/rayhunter/rayhunter-daemon
adb shell '/bin/rootshell -c "/etc/init.d/rayhunter_daemon restart"'
Loading