use std::ffi::{CStr, CString};
use crate::list::{ScamperList, ScamperCycle};
use crate::trace::ScamperTrace;
use crate::ping::ScamperPing;
use crate::tracelb::ScamperTracelb;
use crate::dealias::ScamperDealias;
use crate::host::ScamperHost;
use crate::http::ScamperHttp;
use crate::tbit::ScamperTbit;
use crate::sniff::ScamperSniff;
use crate::udpprobe::ScamperUdpprobe;
use crate::owamp::ScamperOwamp;
use crate::sting::ScamperSting;
use crate::neighbourdisc::ScamperNeighbourdisc;
use crate::ffi::scamper_file::{self, ScamperFileT, ScamperFileFilterT, ScamperFileReadbufT,
SCAMPER_FILE_OBJ_LIST, SCAMPER_FILE_OBJ_CYCLE_START, SCAMPER_FILE_OBJ_CYCLE_DEF,
SCAMPER_FILE_OBJ_CYCLE_STOP, SCAMPER_FILE_OBJ_TRACE, SCAMPER_FILE_OBJ_PING,
SCAMPER_FILE_OBJ_TRACELB, SCAMPER_FILE_OBJ_DEALIAS, SCAMPER_FILE_OBJ_NEIGHBOURDISC,
SCAMPER_FILE_OBJ_TBIT, SCAMPER_FILE_OBJ_STING, SCAMPER_FILE_OBJ_SNIFF,
SCAMPER_FILE_OBJ_HOST, SCAMPER_FILE_OBJ_HTTP, SCAMPER_FILE_OBJ_UDPPROBE,
SCAMPER_FILE_OBJ_OWAMP};
use crate::ffi::scamper_list::{self, ScamperListT, ScamperCycleT};
use crate::ffi::scamper_trace::ScamperTraceT;
use crate::ffi::scamper_ping::ScamperPingT;
use crate::ffi::scamper_tracelb::ScamperTracelbT;
use crate::ffi::scamper_dealias::ScamperDealiasT;
use crate::ffi::scamper_host::ScamperHostT;
use crate::ffi::scamper_http::ScamperHttpT;
use crate::ffi::scamper_tbit::ScamperTbitT;
use crate::ffi::scamper_sniff::ScamperSniffT;
use crate::ffi::scamper_udpprobe::ScamperUdpprobeT;
use crate::ffi::scamper_owamp::ScamperOwampT;
use crate::ffi::scamper_sting::ScamperStingT;
use crate::ffi::scamper_neighbourdisc::ScamperNeighbourdiscT;
pub enum ScamperObject {
List(ScamperList),
CycleStart(ScamperCycle),
CycleDef(ScamperCycle),
CycleStop(ScamperCycle),
Trace(ScamperTrace),
Ping(ScamperPing),
Tracelb(ScamperTracelb),
Dealias(ScamperDealias),
Neighbourdisc(ScamperNeighbourdisc),
Tbit(ScamperTbit),
Sting(ScamperSting),
Sniff(ScamperSniff),
Host(ScamperHost),
Http(ScamperHttp),
Udpprobe(ScamperUdpprobe),
Owamp(ScamperOwamp),
}
impl ScamperObject {
pub(crate) fn write_raw(&self) -> Option<(u16, *mut libc::c_void)> {
match self {
ScamperObject::List(_) => None,
ScamperObject::CycleDef(_) => None,
ScamperObject::CycleStart(c) => Some((SCAMPER_FILE_OBJ_CYCLE_START, c.as_ptr() as _)),
ScamperObject::CycleStop(c) => Some((SCAMPER_FILE_OBJ_CYCLE_STOP, c.as_ptr() as _)),
ScamperObject::Trace(t) => Some((SCAMPER_FILE_OBJ_TRACE, t.inner as _)),
ScamperObject::Ping(p) => Some((SCAMPER_FILE_OBJ_PING, p.inner as _)),
ScamperObject::Tracelb(t) => Some((SCAMPER_FILE_OBJ_TRACELB, t.inner as _)),
ScamperObject::Dealias(d) => Some((SCAMPER_FILE_OBJ_DEALIAS, d.inner as _)),
ScamperObject::Neighbourdisc(n) => Some((SCAMPER_FILE_OBJ_NEIGHBOURDISC, n.inner as _)),
ScamperObject::Tbit(t) => Some((SCAMPER_FILE_OBJ_TBIT, t.inner as _)),
ScamperObject::Sting(s) => Some((SCAMPER_FILE_OBJ_STING, s.inner as _)),
ScamperObject::Sniff(s) => Some((SCAMPER_FILE_OBJ_SNIFF, s.inner as _)),
ScamperObject::Host(h) => Some((SCAMPER_FILE_OBJ_HOST, h.inner as _)),
ScamperObject::Http(h) => Some((SCAMPER_FILE_OBJ_HTTP, h.inner as _)),
ScamperObject::Udpprobe(u) => Some((SCAMPER_FILE_OBJ_UDPPROBE, u.inner as _)),
ScamperObject::Owamp(o) => Some((SCAMPER_FILE_OBJ_OWAMP, o.inner as _)),
}
}
}
pub struct ScamperReadbuf {
pub(crate) inner: *mut ScamperFileReadbufT,
}
impl ScamperReadbuf {
pub fn new() -> Option<Self> {
let ptr = unsafe { scamper_file::scamper_file_readbuf_alloc() };
if ptr.is_null() { None } else { Some(ScamperReadbuf { inner: ptr }) }
}
pub fn add(&self, data: &[u8]) -> bool {
let rc = unsafe {
scamper_file::scamper_file_readbuf_add(
self.inner,
data.as_ptr() as *const libc::c_void,
data.len(),
)
};
rc == 0
}
}
impl Drop for ScamperReadbuf {
fn drop(&mut self) {
unsafe { scamper_file::scamper_file_readbuf_free(self.inner) };
}
}
unsafe impl Send for ScamperReadbuf {}
unsafe impl Sync for ScamperReadbuf {}
pub struct ScamperFile {
sf: *mut ScamperFileT,
filter: *mut ScamperFileFilterT,
mode: u8,
}
impl ScamperFile {
pub fn open(filename: &str, mode: char, kind: Option<&str>) -> Result<Self, String> {
if mode != 'r' && mode != 'w' {
return Err(format!("invalid mode: {}", mode));
}
let inferred_kind;
let kind = match kind {
Some(k) => k,
None if mode == 'r' => "warts",
None => {
inferred_kind = if filename.ends_with(".gz") {
"warts.gz"
} else if filename.ends_with(".bz2") {
"warts.bz2"
} else if filename.ends_with(".xz") {
"warts.xz"
} else if filename.ends_with(".json") {
"json"
} else if filename.ends_with(".txt") {
"text"
} else {
"warts"
};
inferred_kind
}
};
let c_filename = CString::new(filename).map_err(|e| e.to_string())?;
let c_kind = CString::new(kind).map_err(|e| e.to_string())?;
let sf = unsafe {
scamper_file::scamper_file_open(c_filename.as_ptr(), mode as i8, c_kind.as_ptr())
};
if sf.is_null() {
return Err(format!("could not open file: {}", filename));
}
Ok(ScamperFile { sf, filter: std::ptr::null_mut(), mode: mode as u8 })
}
pub fn filetype(&self) -> String {
let mut buf = [0i8; 128];
unsafe { scamper_file::scamper_file_type_tostr(self.sf, buf.as_mut_ptr(), buf.len()) };
let cstr = unsafe { CStr::from_ptr(buf.as_ptr()) };
cstr.to_string_lossy().into_owned()
}
pub fn filename(&self) -> Option<String> {
let ptr = unsafe { scamper_file::scamper_file_getfilename(self.sf) };
if ptr.is_null() { None } else {
Some(unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned())
}
}
pub fn set_filter(&mut self, types: &[u16]) -> Result<(), String> {
if self.mode != b'r' {
return Err("cannot set filter on non-readable file".into());
}
if types.is_empty() {
return Err("no types specified".into());
}
let filter = unsafe {
scamper_file::scamper_file_filter_alloc(types.as_ptr(), types.len() as u16)
};
if filter.is_null() {
return Err("could not allocate filter".into());
}
if !self.filter.is_null() {
unsafe { scamper_file::scamper_file_filter_free(self.filter) };
}
self.filter = filter;
Ok(())
}
pub fn close(&mut self) {
if !self.sf.is_null() {
unsafe { scamper_file::scamper_file_close(self.sf) };
self.sf = std::ptr::null_mut();
}
}
pub fn read(&mut self) -> Option<ScamperObject> {
if self.mode != b'r' { return None; }
let mut o_type: u16 = 0;
let mut o_data: *mut libc::c_void = std::ptr::null_mut();
let rc = unsafe {
scamper_file::scamper_file_read(self.sf, self.filter, &mut o_type, &mut o_data)
};
if rc != 0 || o_data.is_null() { return None; }
unsafe { parse_scamper_obj(o_type, o_data) }
}
pub fn write(&mut self, obj: &ScamperObject) -> Result<(), String> {
if self.mode != b'w' {
return Err("file not opened in write mode".into());
}
let (o_type, o_data) = match obj.write_raw() {
Some(x) => x,
None => return Ok(()), };
let rc = unsafe { scamper_file::scamper_file_write_obj(self.sf, o_type, o_data) };
if rc != 0 {
return Err(format!("could not write object type {}", o_type));
}
Ok(())
}
pub fn is_read(&self) -> bool { self.mode == b'r' }
pub fn is_write(&self) -> bool { self.mode == b'w' }
}
pub(crate) unsafe fn parse_scamper_obj(o_type: u16, o_data: *mut libc::c_void) -> Option<ScamperObject> {
match o_type {
SCAMPER_FILE_OBJ_LIST => {
let c_list = o_data as *mut ScamperListT;
let obj = unsafe { ScamperList::from_ptr(c_list) }.map(ScamperObject::List);
unsafe { scamper_list::scamper_list_free(c_list) };
obj
}
SCAMPER_FILE_OBJ_CYCLE_START => {
let c_cycle = o_data as *mut ScamperCycleT;
let obj = unsafe { ScamperCycle::from_ptr(c_cycle) }.map(ScamperObject::CycleStart);
unsafe { scamper_list::scamper_cycle_free(c_cycle) };
obj
}
SCAMPER_FILE_OBJ_CYCLE_DEF => {
let c_cycle = o_data as *mut ScamperCycleT;
let obj = unsafe { ScamperCycle::from_ptr(c_cycle) }.map(ScamperObject::CycleDef);
unsafe { scamper_list::scamper_cycle_free(c_cycle) };
obj
}
SCAMPER_FILE_OBJ_CYCLE_STOP => {
let c_cycle = o_data as *mut ScamperCycleT;
let obj = unsafe { ScamperCycle::from_ptr(c_cycle) }.map(ScamperObject::CycleStop);
unsafe { scamper_list::scamper_cycle_free(c_cycle) };
obj
}
SCAMPER_FILE_OBJ_TRACE => {
unsafe { ScamperTrace::from_ptr(o_data as *mut ScamperTraceT) }.map(ScamperObject::Trace)
}
SCAMPER_FILE_OBJ_PING => {
unsafe { ScamperPing::from_ptr(o_data as *mut ScamperPingT) }.map(ScamperObject::Ping)
}
SCAMPER_FILE_OBJ_TRACELB => {
unsafe { ScamperTracelb::from_ptr(o_data as *mut ScamperTracelbT) }.map(ScamperObject::Tracelb)
}
SCAMPER_FILE_OBJ_DEALIAS => {
unsafe { ScamperDealias::from_ptr(o_data as *mut ScamperDealiasT) }.map(ScamperObject::Dealias)
}
SCAMPER_FILE_OBJ_NEIGHBOURDISC => {
unsafe { ScamperNeighbourdisc::from_ptr(o_data as *mut ScamperNeighbourdiscT) }.map(ScamperObject::Neighbourdisc)
}
SCAMPER_FILE_OBJ_TBIT => {
unsafe { ScamperTbit::from_ptr(o_data as *mut ScamperTbitT) }.map(ScamperObject::Tbit)
}
SCAMPER_FILE_OBJ_STING => {
unsafe { ScamperSting::from_ptr(o_data as *mut ScamperStingT) }.map(ScamperObject::Sting)
}
SCAMPER_FILE_OBJ_SNIFF => {
unsafe { ScamperSniff::from_ptr(o_data as *mut ScamperSniffT) }.map(ScamperObject::Sniff)
}
SCAMPER_FILE_OBJ_HOST => {
unsafe { ScamperHost::from_ptr(o_data as *mut ScamperHostT) }.map(ScamperObject::Host)
}
SCAMPER_FILE_OBJ_HTTP => {
unsafe { ScamperHttp::from_ptr(o_data as *mut ScamperHttpT) }.map(ScamperObject::Http)
}
SCAMPER_FILE_OBJ_UDPPROBE => {
unsafe { ScamperUdpprobe::from_ptr(o_data as *mut ScamperUdpprobeT) }.map(ScamperObject::Udpprobe)
}
SCAMPER_FILE_OBJ_OWAMP => {
unsafe { ScamperOwamp::from_ptr(o_data as *mut ScamperOwampT) }.map(ScamperObject::Owamp)
}
_ => None,
}
}
impl Drop for ScamperFile {
fn drop(&mut self) {
if !self.filter.is_null() {
unsafe { scamper_file::scamper_file_filter_free(self.filter) };
}
if !self.sf.is_null() {
unsafe { scamper_file::scamper_file_close(self.sf) };
}
}
}
impl Iterator for ScamperFile {
type Item = ScamperObject;
fn next(&mut self) -> Option<ScamperObject> {
self.read()
}
}
unsafe impl Send for ScamperFile {}
unsafe impl Sync for ScamperFile {}