Skip to content

Commit

Permalink
intercept: update cargo structure to create two binaries
Browse files Browse the repository at this point in the history
  • Loading branch information
rizsotto committed Feb 16, 2024
1 parent 5906ab2 commit bfaa231
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 218 deletions.
11 changes: 10 additions & 1 deletion source/intercept_rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,14 @@ crossbeam-channel = "0.5"
rand = "0.8.5"
chrono = "0.4.33"

[lib]
name = "intercept"
path = "src/lib.rs"

[[bin]]
name = "intercept"
path = "src/main.rs"

[[bin]]
name = "intercept"
name = "wrapper"
path = "src/wrapper/main.rs"
101 changes: 101 additions & 0 deletions source/intercept_rs/src/collector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/* Copyright (C) 2012-2023 by László Nagy
This file is part of Bear.
Bear is a tool to generate compilation database for clang tooling.
Bear is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bear is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

use std::net::{TcpListener, TcpStream};

use crossbeam::channel::{Receiver, Sender};
use crossbeam_channel::bounded;

use super::ipc::{Envelope, SessionLocator};

trait EventCollector {
fn address(&self) -> Result<SessionLocator, anyhow::Error>;
fn collect(&self, destination: Sender<Envelope>) -> Result<(), anyhow::Error>;
fn stop(&self) -> Result<(), anyhow::Error>;
}

struct EventCollectorOnTcp {
control_input: Sender<bool>,
control_output: Receiver<bool>,
listener: TcpListener,
}

impl EventCollectorOnTcp {
pub fn new() -> Result<Self, anyhow::Error> {
let (control_input, control_output) = bounded(0);
let listener = TcpListener::bind("127.0.0.1:0")?;

let result = EventCollectorOnTcp { control_input, control_output, listener };

Ok(result)
}

pub fn send(
&self,
mut socket: TcpStream,
destination: Sender<Envelope>,
) -> Result<(), anyhow::Error> {
let envelope = Envelope::read_from(&mut socket)?;
destination.send(envelope)?;

Ok(())
}
}

impl EventCollector for EventCollectorOnTcp {
fn address(&self) -> Result<SessionLocator, anyhow::Error> {
let local_addr = self.listener.local_addr()?;
let locator = SessionLocator(local_addr.to_string());
Ok(locator)
}

fn collect(&self, destination: Sender<Envelope>) -> Result<(), anyhow::Error> {
loop {
if let Ok(shutdown) = self.control_output.try_recv() {
if shutdown {
break;
}
}

match self.listener.accept() {
Ok((stream, _)) => {
println!("Got a connection");
// ... (process the connection in a separate thread or task)
self.send(stream, destination.clone())?;
}
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
// No new connection available, continue checking for shutdown
continue;
}
Err(e) => {
println!("Error: {}", e);
break;
}
}
}

println!("Server shutting down");
Ok(())
}

fn stop(&self) -> Result<(), anyhow::Error> {
self.control_input.send(true)?;
Ok(())
}
}
105 changes: 105 additions & 0 deletions source/intercept_rs/src/ipc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/* Copyright (C) 2012-2023 by László Nagy
This file is part of Bear.
Bear is a tool to generate compilation database for clang tooling.
Bear is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bear is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

use std::collections::HashMap;
use std::io::{Read, Write};
use std::path::PathBuf;

use chrono::Utc;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct SessionLocator(pub String);

// Reporter id is a unique identifier for a reporter.
//
// It is used to identify the process that sends the execution report.
// Because the OS PID is not unique across a single build (PIDs are
// recycled), we need to use a new unique identifier to identify the process.
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct ReporterId(pub u64);

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct ProcessId(pub u32);

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Execution {
pub executable: PathBuf,
pub arguments: Vec<String>,
pub working_dir: PathBuf,
pub environment: HashMap<String, String>,
}

// Represent a relevant life cycle event of a process.
//
// Currently, it's only the process life cycle events (start, signal,
// terminate), but can be extended later with performance related
// events like monitoring the CPU usage or the memory allocation if
// this information is available.
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub enum Event {
Started {
pid: ProcessId,
ppid: ProcessId,
execution: Execution,
},
Terminated {
status: i64
},
Signaled {
signal: i32,
},
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Envelope {
pub rid: ReporterId,
pub timestamp: u64,
pub event: Event,
}

impl Envelope {
pub fn new(rid: &ReporterId, event: Event) -> Self {
let timestamp = Utc::now().timestamp_millis() as u64;
Envelope { rid: rid.clone(), timestamp, event }
}

pub fn read_from(mut reader: impl Read) -> Result<Self, anyhow::Error> {
let mut length_bytes = [0; 4];
reader.read_exact(&mut length_bytes)?;
let length = u32::from_be_bytes(length_bytes) as usize;

let mut buffer = vec![0; length];
reader.read_exact(&mut buffer)?;
let envelope = serde_json::from_slice(buffer.as_ref())?;

Ok(envelope)
}

pub fn write_into(&self, mut writer: impl Write) -> Result<(), anyhow::Error> {
let serialized_envelope = serde_json::to_string(&self)?;
let bytes = serialized_envelope.into_bytes();
let length = bytes.len() as u32;

writer.write_all(&length.to_be_bytes())?;
writer.write_all(&bytes)?;

Ok(())
}
}
Loading

0 comments on commit bfaa231

Please sign in to comment.