diff options
| -rw-r--r-- | Cargo.toml | 5 | ||||
| -rw-r--r-- | build.rs | 37 | ||||
| -rwxr-xr-x | c_lib/libfieldstat4.so | bin | 0 -> 603176 bytes | |||
| -rw-r--r-- | src/c_lang/fs4.rs | 599 | ||||
| -rw-r--r-- | src/c_lang/fs4_binding.rs | 961 | ||||
| -rw-r--r-- | src/c_lang/mod.rs | 2 | ||||
| -rw-r--r-- | src/lib.rs | 4 | ||||
| -rw-r--r-- | src/session/tcp_reassembly.rs | 1190 | ||||
| -rw-r--r-- | src/session/tcp_reassembly_with_deque.rs | 1069 |
9 files changed, 2941 insertions, 926 deletions
@@ -7,3 +7,8 @@ edition = "2021" [dependencies] nom = "7" +libc = "0.2.148" + +[build-dependencies] +bindgen = "0.65.1" + diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..c7fc090 --- /dev/null +++ b/build.rs @@ -0,0 +1,37 @@ +use std::env; + +// fn main() { + +// } + +fn main() { + // Tell cargo to look for shared libraries in the specified directory + let dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + println!("cargo:rustc-link-search=native={}/c_lib", dir); + println!("cargo:rustc-link-lib=fieldstat4"); + + // // Tell cargo to invalidate the built crate whenever the wrapper changes + // println!("cargo:rerun-if-changed=wrapper.h"); + + // // The bindgen::Builder is the main entry point + // // to bindgen, and lets you build up options for + // // the resulting bindings. + // let bindings = bindgen::Builder::default() + // // The input header we would like to generate + // // bindings for. + // .header("c_include/wrapper.h") + // // Tell cargo to invalidate the built crate whenever any of the + // // included header files changed. + // .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + // // Finish the builder and generate the bindings. + // .generate() + // // Unwrap the Result and panic on failure. + // .expect("Unable to generate bindings"); + + // // Write the bindings to the $OUT_DIR/bindings.rs file. + // let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + // println!("out_path = {:?}", out_path); + // bindings + // .write_to_file(out_path.join("bindings.rs")) + // .expect("Couldn't write bindings!"); +}
\ No newline at end of file diff --git a/c_lib/libfieldstat4.so b/c_lib/libfieldstat4.so Binary files differnew file mode 100755 index 0000000..f658cb1 --- /dev/null +++ b/c_lib/libfieldstat4.so diff --git a/src/c_lang/fs4.rs b/src/c_lang/fs4.rs new file mode 100644 index 0000000..6668ba7 --- /dev/null +++ b/src/c_lang/fs4.rs @@ -0,0 +1,599 @@ + +use std::ffi::{CString, CStr}; +use std::os::raw::{c_longlong, c_char}; +use std::fmt::Debug; +use std::marker::PhantomData; +use std::mem; +use libc; + +use super::fs4_binding; + + +pub struct Fieldstat { + content: *mut fs4_binding::fieldstat, +} + +#[derive(Clone, Debug)] +pub enum FieldstatTagType { + LongLong, + Double, + String, +} + +pub enum SampleMode { + Comprehensive, + TopK, +} + +pub enum CounterMergeMode { + BySum, + ByMax, + ByMin, +} + +pub enum MetricType { + Counter, + HLL, + Histogram, +} + +#[derive(Debug, Clone)] +pub enum FieldstatErr { + WrongCube, + WrongCell, + WrongMetric, + WrongCubeOrParameter, // todo: 现在C 上不做区别,抽空调一下 + // todo: anyhow 替代result + // todo: 删fs4_binding 里的东西 + // todo: 改名字就叫fieldstat + WrongParameter, + CubeIsFull, + DuplicateKey, +} + +impl FieldstatTagType { + fn as_c_corresponding_type(&self) -> fs4_binding::fs_tag_type { + match self { + FieldstatTagType::LongLong => 0 as fs4_binding::fs_tag_type, + FieldstatTagType::Double => 1 as fs4_binding::fs_tag_type, + FieldstatTagType::String => 2 as fs4_binding::fs_tag_type, + } + } +} + +pub struct FieldstatTag<T: Taggable> { + content: fs4_binding::fieldstat_tag, + value_type: FieldstatTagType, + + phantom: PhantomData<T>, +} + +pub trait Taggable: Clone + Debug{ + type Output; + fn type_id(&self) -> FieldstatTagType; + fn into_c_corresponding(self) -> fs4_binding::fieldstat_tag__bindgen_ty_1; +} + +impl Taggable for i64 { + type Output = i64; + + fn type_id(&self) -> FieldstatTagType { + FieldstatTagType::LongLong + } + fn into_c_corresponding(self) -> fs4_binding::fieldstat_tag__bindgen_ty_1 { + fs4_binding::fieldstat_tag__bindgen_ty_1 { + value_longlong: self as c_longlong, + } + } +} + +impl Taggable for f64 { + type Output = f64; + + fn type_id(&self) -> FieldstatTagType { + FieldstatTagType::Double + } + fn into_c_corresponding(self) -> fs4_binding::fieldstat_tag__bindgen_ty_1 { + fs4_binding::fieldstat_tag__bindgen_ty_1 { + value_double: self as f64 + } + } +} + +impl Taggable for String { + type Output = String; + + fn type_id(&self) -> FieldstatTagType { + FieldstatTagType::String + } + fn into_c_corresponding(self) -> fs4_binding::fieldstat_tag__bindgen_ty_1 { + fs4_binding::fieldstat_tag__bindgen_ty_1 { + value_str: CString::new(self).unwrap().into_raw() as *mut c_char, + } + } +} + +impl<T: Taggable> FieldstatTag<T> { + fn new(name: &str, value: T) -> Self { + let c_string = CString::new(name).unwrap(); + let typeid = value.type_id(); + Self { + content: fs4_binding::fieldstat_tag { + key: c_string.into_raw(), + type_: value.type_id().as_c_corresponding_type(), + __bindgen_anon_1: value.into_c_corresponding(), + }, + value_type: typeid, + + phantom: PhantomData, + } + } + + fn value_type(&self) -> FieldstatTagType { + self.value_type.clone() + } + + fn key(&self) -> String { + unsafe { + let rust_str = CStr::from_ptr(self.content.key).to_owned(); + rust_str.to_str().unwrap().to_string() + } + } +} + +impl FieldstatTag<i64> +{ + fn value(&self) -> i64 { + unsafe { + self.content.__bindgen_anon_1.value_longlong + } + } +} + +impl FieldstatTag<f64> +{ + fn value(&self) -> f64 { + unsafe { + self.content.__bindgen_anon_1.value_double + } + } +} + +impl FieldstatTag<String> +{ + fn value(&self) -> String { + unsafe { + let rust_str = CStr::from_ptr(self.content.__bindgen_anon_1.value_str).to_owned(); + rust_str.to_str().unwrap().to_string() + } + } +} + + +pub enum FieldstatTagWrapper { + LongLong(FieldstatTag<i64>), + Double(FieldstatTag<f64>), + String(FieldstatTag<String>), +} + +impl Fieldstat { + pub fn new() -> Self { + Self { + content: unsafe { fs4_binding::fieldstat_new() }, + } + } + pub fn register_counter(&mut self, name: &str, cube_id: i64, mode: CounterMergeMode) -> Result<i32, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_register_counter( + self.content, + cube_id as std::os::raw::c_int, + CString::new(name).unwrap().into_raw(), + mode as fs4_binding::counter_mode, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + _ => Ok(ret), + } + } + } + pub fn register_hll(&mut self, name: &str, cube_id: i64, precision: u8) -> Result<i32, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_register_hll( + self.content, + cube_id as std::os::raw::c_int, + CString::new(name).unwrap().into_raw(), + precision as std::os::raw::c_uchar, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCubeOrParameter), + _ => Ok(ret), + } + } + } + pub fn register_histogram(&mut self, name: &str, cube_id: i64, + lowest_trackable_value: i64, highest_trackable_value: i64, significant_figures: i32) -> Result<i32, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_register_hist( + self.content, + cube_id as std::os::raw::c_int, + CString::new(name).unwrap().into_raw(), + lowest_trackable_value as std::os::raw::c_longlong, + highest_trackable_value as std::os::raw::c_longlong, + significant_figures as std::os::raw::c_int, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCubeOrParameter), + _ => Ok(ret), + } + } + } + pub fn new_with_same_config(&self) -> Self { + Self { + content: unsafe { fs4_binding::fieldstat_dup(self.content) }, + } + } + pub fn register_cube<T: Taggable>(&mut self, shared_tags: &[FieldstatTag<T>], mode: SampleMode, max_n_cell: usize) -> Result<i32, FieldstatErr> { + let c_mode = match mode { + SampleMode::Comprehensive => fs4_binding::sampling_mode_SAMPLING_MODE_COMPREHENSIVE, + SampleMode::TopK => fs4_binding::sampling_mode_SAMPLING_MODE_TOPK, + }; + let mut c_tag_structs = Vec::with_capacity(shared_tags.len()); + for tag in shared_tags { + c_tag_structs.push(tag.content); + } + + unsafe { + let ret = fs4_binding::fieldstat_register_cube( + self.content, + c_tag_structs.as_ptr(), + shared_tags.len(), + c_mode, + max_n_cell); + + match ret { + -1 => Err(FieldstatErr::WrongParameter), + -2 => Err(FieldstatErr::DuplicateKey), + _ => Ok(ret), + } + } + } + pub fn unregister_cube(&mut self, cube_id: i64) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_unregister_cube(self.content, cube_id as std::os::raw::c_int); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + _ => Ok(()), + } + } + } + pub fn get_cube_version(&self, cube_id: i64) -> Result<i64, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_get_cube_version(self.content, cube_id as std::os::raw::c_int); + + match ret { + -1 | -2 | -3 => Err(FieldstatErr::WrongCube), + _ => Ok(ret), + } + } + } + pub fn cube_add<T: Taggable>(&mut self, cube_id: i64, tags: &[FieldstatTag<T>], value: i64) -> Result<i32, FieldstatErr> { + let mut c_tag_structs = Vec::with_capacity(tags.len()); + for tag in tags { + c_tag_structs.push(tag.content); + } + + unsafe { + let ret = fs4_binding::fieldstat_cube_add( + self.content, + cube_id as std::os::raw::c_int, + c_tag_structs.as_ptr(), + tags.len(), + value as std::os::raw::c_longlong, + ); + + match ret { + -1 => Err(FieldstatErr::CubeIsFull), + -2 => Err(FieldstatErr::WrongCell), + _ => Ok(ret), + } + } + } + pub fn counter_incrby(&mut self, cube_id: i32, metric_id: i32, cell_id: i32, increment: i64) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_counter_incrby( + self.content, + cube_id as std::os::raw::c_int, + metric_id as std::os::raw::c_int, + cell_id as std::os::raw::c_int, + increment as std::os::raw::c_longlong, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + -2 => Err(FieldstatErr::WrongMetric), + -3 => Err(FieldstatErr::WrongCell), + -4 => Err(FieldstatErr::WrongParameter), + _ => Ok(()), + } + } + } + pub fn counter_set(&mut self, cube_id: i32, metric_id: i32, cell_id: i32, value: i64) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_counter_set( + self.content, + cube_id as std::os::raw::c_int, + metric_id as std::os::raw::c_int, + cell_id as std::os::raw::c_int, + value as std::os::raw::c_longlong, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + -2 => Err(FieldstatErr::WrongMetric), + -3 => Err(FieldstatErr::WrongCell), + -4 => Err(FieldstatErr::WrongParameter), + _ => Ok(()), + } + } + } + pub fn hll_add(&mut self, cube_id: i32, metric_id: i32, cell_id: i32, key: &str) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_hll_add( + self.content, + cube_id as std::os::raw::c_int, + metric_id as std::os::raw::c_int, + cell_id as std::os::raw::c_int, + CString::new(key).unwrap().into_raw(), + key.len(), + ); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + -2 => Err(FieldstatErr::WrongMetric), + -3 => Err(FieldstatErr::WrongCell), + -4 => Err(FieldstatErr::WrongParameter), + _ => Ok(()), + } + } + } + pub fn histogram_record(&mut self, cube_id: i32, metric_id: i32, cell_id: i32, value: i64) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_hist_record( + self.content, + cube_id as std::os::raw::c_int, + metric_id as std::os::raw::c_int, + cell_id as std::os::raw::c_int, + value as std::os::raw::c_longlong, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + -2 => Err(FieldstatErr::WrongMetric), + -3 => Err(FieldstatErr::WrongCell), + -4 => Err(FieldstatErr::WrongParameter), + _ => Ok(()), + } + } + } + pub fn reset(&mut self) { + unsafe { + fs4_binding::fieldstat_reset(self.content); + } + } + pub fn get_cell_version(&self) -> u64 { + unsafe { + fs4_binding::fieldstat_get_cell_version(self.content) + } + } + pub fn merge(&mut self, other: &Fieldstat) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_merge(self.content, other.content); + + match ret { + -1 => Err(FieldstatErr::WrongParameter), + _ => Ok(()), + } + } + } + pub fn serialize(&self) -> Vec<u8> { + unsafe { + let mut blob_out: *mut ::std::os::raw::c_char = std::ptr::null_mut(); + let mut blob_size_out: usize = 0; + + fs4_binding::fieldstat_serialize(self.content, &mut blob_out, &mut blob_size_out); + let vec = Vec::from_raw_parts(blob_out as *mut u8, blob_size_out, blob_size_out); + + libc::free(blob_out as *mut libc::c_void); + vec + } + } + pub fn deserialize(&mut self, blob: &[u8]) -> Option<Self> { + unsafe { + let ret = fs4_binding::fieldstat_deserialize(blob.as_ptr() as *const ::std::os::raw::c_char, blob.len()); + + if ret == std::ptr::null_mut() { + None + } else { + Some(Self { + content: ret, + }) + } + } + } + + /* ---------------------------------- query --------------------------------- */ + pub fn get_cubes(&self) -> Vec<i32> { + unsafe { + let mut cubes: *mut i32 = std::ptr::null_mut(); + // int *cube = NULL; + let mut n_cubes: i32 = 0; + + fs4_binding::fieldstat_get_cubes(self.content, &mut cubes, &mut n_cubes); + let vec = Vec::from_raw_parts(cubes, n_cubes as usize, n_cubes as usize); + + libc::free(cubes as *mut libc::c_void); + vec + } + } + pub fn get_max_metric_id(&self, cube_id: i32) -> Result<i32, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_get_max_metric_id(self.content, cube_id as std::os::raw::c_int); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + _ => Ok(ret), + } + } + } + pub fn get_metric_name(&self, cube_id: i32, metric_id: i32) -> Result<String, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_get_metric_name(self.content, cube_id as std::os::raw::c_int, metric_id as std::os::raw::c_int); + if ret == std::ptr::null_mut() { + Err(FieldstatErr::WrongMetric) + } else { + let rust_str = CStr::from_ptr(ret).to_owned(); + Ok(rust_str.to_str().unwrap().to_string()) + } + } + } + pub fn get_metric_type(&self, cube_id: i32, metric_id: i32) -> Result<MetricType, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_get_metric_type(self.content, cube_id as std::os::raw::c_int, metric_id as std::os::raw::c_int); + + match ret { + fs4_binding::metric_type_METRIC_TYPE_COUNTER => Ok(MetricType::Counter), + fs4_binding::metric_type_METRIC_TYPE_HLL => Ok(MetricType::HLL), + fs4_binding::metric_type_METRIC_TYPE_HISTOGRAM => Ok(MetricType::Histogram), + _ => Err(FieldstatErr::WrongMetric), + } + } + } + pub fn cube_read_cell(&self, cube_id: i32) -> Option<Vec< (i32, Vec<FieldstatTagWrapper>)>> { + unsafe { + let mut cell_id: *mut std::os::raw::c_int = std::ptr::null_mut(); + let mut tags: *mut fs4_binding::fieldstat_tag_list = std::ptr::null_mut(); + let mut n_cell: usize = 0; + + fs4_binding::fieldstat_cube_read_cell(self.content, + cube_id as std::os::raw::c_int, + &mut cell_id, + &mut tags, + &mut n_cell); + + if n_cell == 0 { + return None; + } + + let mut ret = Vec::with_capacity(n_cell); + let tags_list_vec = Vec::from_raw_parts(tags, n_cell, n_cell); + let cell_id_vec = Vec::from_raw_parts(cell_id, n_cell, n_cell); + + for i in 0..n_cell { + let tag_vec = fieldstat_tag_list_to_vec(tags_list_vec.get_unchecked(i)); + ret.push((cell_id_vec[i], tag_vec)); + } + + libc::free(cell_id as *mut libc::c_void); + fs4_binding::fieldstat_tag_list_arr_free(tags, n_cell); + + Some(ret) + } + } + +} + +impl Drop for Fieldstat { + fn drop(&mut self) { + unsafe { + fs4_binding::fieldstat_free(self.content); + } + } +} + +fn fieldstat_tag_list_to_vec(tag_list_p: *const fs4_binding::fieldstat_tag_list) + -> Vec<FieldstatTagWrapper> { + unsafe { + let tag_p_vec = Vec::from_raw_parts((*tag_list_p).tag, (*tag_list_p).n_tag, (*tag_list_p).n_tag); + let mut ret = Vec::with_capacity(tag_p_vec.len()); + for item in tag_p_vec { + let value_type = match item.type_ { + fs4_binding::fs_tag_type_TAG_INTEGER => { + FieldstatTagType::LongLong + }, + fs4_binding::fs_tag_type_TAG_DOUBLE => { + FieldstatTagType::Double + }, + fs4_binding::fs_tag_type_TAG_CSTRING => { + FieldstatTagType::String + }, + _ => panic!("unknown tag type"), + }; + + ret.push(match value_type { + FieldstatTagType::LongLong => FieldstatTagWrapper::LongLong( + FieldstatTag { content: item, value_type: value_type, phantom: PhantomData }), + FieldstatTagType::Double => FieldstatTagWrapper::Double( + FieldstatTag { content: item, value_type: value_type, phantom: PhantomData }), + FieldstatTagType::String => FieldstatTagWrapper::String( + FieldstatTag { content: item, value_type: value_type, phantom: PhantomData }), + }); + } + ret + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn new_tag_int() { + let tag = FieldstatTag::new("test", 1); + assert_eq!(tag.key(), "test"); + assert_eq!(tag.value(), 1); + } + + #[test] + fn new_tag_float() { + let tag = FieldstatTag::new("test", 1.0); + assert_eq!(tag.key(), "test"); + assert_eq!(tag.value(), 1.0); + } + + #[test] + fn new_tag_str() { + let tag = FieldstatTag::new("test", "hello1".to_string()); + assert_eq!(tag.key(), "test"); + assert_eq!(tag.value(), "hello1"); + } + + #[test] + fn query_cell() { + let mut fs = Fieldstat::new(); + let shared_tags = vec![ + FieldstatTag::new("tag1", 1), + ]; + let cell_tag = vec![ + FieldstatTag::new("tag cell", 123), + ]; + + fs.register_cube(shared_tags.as_slice(), SampleMode::Comprehensive, 100).unwrap(); + fs.cube_add(0, cell_tag.as_slice(), 1).unwrap(); + + let cell = fs.cube_read_cell(0).unwrap(); + assert_eq!(cell.len(), 1); + assert_eq!(cell[0].0, 0); // cell id + assert_eq!(cell[0].1.len(), 1); + if let FieldstatTagWrapper::LongLong(tag) = &cell[0].1[0] { + assert_eq!(tag.key(), "tag cell"); + assert_eq!(tag.value(), 123); + } else { + panic!("wrong tag type"); + } + } +}
\ No newline at end of file diff --git a/src/c_lang/fs4_binding.rs b/src/c_lang/fs4_binding.rs new file mode 100644 index 0000000..a425487 --- /dev/null +++ b/src/c_lang/fs4_binding.rs @@ -0,0 +1,961 @@ +#![allow(warnings)] + +/* automatically generated by rust-bindgen 0.65.1 */ + +pub type off_t = __off_t; +pub type fpos_t = __fpos_t; +extern "C" { + pub static mut stdin: *mut FILE; +} +extern "C" { + pub static mut stdout: *mut FILE; +} +extern "C" { + pub static mut stderr: *mut FILE; +} +extern "C" { + pub fn remove(__filename: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn rename( + __old: *const ::std::os::raw::c_char, + __new: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn renameat( + __oldfd: ::std::os::raw::c_int, + __old: *const ::std::os::raw::c_char, + __newfd: ::std::os::raw::c_int, + __new: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn tmpfile() -> *mut FILE; +} +extern "C" { + pub fn tmpnam(__s: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; +} +extern "C" { + pub fn tmpnam_r(__s: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; +} +extern "C" { + pub fn tempnam( + __dir: *const ::std::os::raw::c_char, + __pfx: *const ::std::os::raw::c_char, + ) -> *mut ::std::os::raw::c_char; +} +extern "C" { + pub fn fclose(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fflush(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fflush_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fopen( + __filename: *const ::std::os::raw::c_char, + __modes: *const ::std::os::raw::c_char, + ) -> *mut FILE; +} +extern "C" { + pub fn freopen( + __filename: *const ::std::os::raw::c_char, + __modes: *const ::std::os::raw::c_char, + __stream: *mut FILE, + ) -> *mut FILE; +} +extern "C" { + pub fn fdopen(__fd: ::std::os::raw::c_int, __modes: *const ::std::os::raw::c_char) + -> *mut FILE; +} +extern "C" { + pub fn fmemopen( + __s: *mut ::std::os::raw::c_void, + __len: usize, + __modes: *const ::std::os::raw::c_char, + ) -> *mut FILE; +} +extern "C" { + pub fn open_memstream( + __bufloc: *mut *mut ::std::os::raw::c_char, + __sizeloc: *mut usize, + ) -> *mut FILE; +} +extern "C" { + pub fn setbuf(__stream: *mut FILE, __buf: *mut ::std::os::raw::c_char); +} +extern "C" { + pub fn setvbuf( + __stream: *mut FILE, + __buf: *mut ::std::os::raw::c_char, + __modes: ::std::os::raw::c_int, + __n: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn setbuffer(__stream: *mut FILE, __buf: *mut ::std::os::raw::c_char, __size: usize); +} +extern "C" { + pub fn setlinebuf(__stream: *mut FILE); +} +extern "C" { + pub fn fprintf( + __stream: *mut FILE, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn printf(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn sprintf( + __s: *mut ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn vfprintf( + __s: *mut FILE, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn vprintf( + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn vsprintf( + __s: *mut ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn snprintf( + __s: *mut ::std::os::raw::c_char, + __maxlen: ::std::os::raw::c_ulong, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn vsnprintf( + __s: *mut ::std::os::raw::c_char, + __maxlen: ::std::os::raw::c_ulong, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn vdprintf( + __fd: ::std::os::raw::c_int, + __fmt: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn dprintf( + __fd: ::std::os::raw::c_int, + __fmt: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fscanf( + __stream: *mut FILE, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn scanf(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn sscanf( + __s: *const ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "\u{1}__isoc99_fscanf"] + pub fn fscanf1( + __stream: *mut FILE, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "\u{1}__isoc99_scanf"] + pub fn scanf1(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "\u{1}__isoc99_sscanf"] + pub fn sscanf1( + __s: *const ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn vfscanf( + __s: *mut FILE, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn vscanf( + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn vsscanf( + __s: *const ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "\u{1}__isoc99_vfscanf"] + pub fn vfscanf1( + __s: *mut FILE, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "\u{1}__isoc99_vscanf"] + pub fn vscanf1( + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "\u{1}__isoc99_vsscanf"] + pub fn vsscanf1( + __s: *const ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fgetc(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn getc(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn getchar() -> ::std::os::raw::c_int; +} +extern "C" { + pub fn getc_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn getchar_unlocked() -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fgetc_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fputc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn putc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn putchar(__c: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fputc_unlocked(__c: ::std::os::raw::c_int, __stream: *mut FILE) + -> ::std::os::raw::c_int; +} +extern "C" { + pub fn putc_unlocked(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn putchar_unlocked(__c: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn getw(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn putw(__w: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fgets( + __s: *mut ::std::os::raw::c_char, + __n: ::std::os::raw::c_int, + __stream: *mut FILE, + ) -> *mut ::std::os::raw::c_char; +} +extern "C" { + pub fn __getdelim( + __lineptr: *mut *mut ::std::os::raw::c_char, + __n: *mut usize, + __delimiter: ::std::os::raw::c_int, + __stream: *mut FILE, + ) -> __ssize_t; +} +extern "C" { + pub fn getdelim( + __lineptr: *mut *mut ::std::os::raw::c_char, + __n: *mut usize, + __delimiter: ::std::os::raw::c_int, + __stream: *mut FILE, + ) -> __ssize_t; +} +extern "C" { + pub fn getline( + __lineptr: *mut *mut ::std::os::raw::c_char, + __n: *mut usize, + __stream: *mut FILE, + ) -> __ssize_t; +} +extern "C" { + pub fn fputs(__s: *const ::std::os::raw::c_char, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn puts(__s: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn ungetc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fread( + __ptr: *mut ::std::os::raw::c_void, + __size: ::std::os::raw::c_ulong, + __n: ::std::os::raw::c_ulong, + __stream: *mut FILE, + ) -> ::std::os::raw::c_ulong; +} +extern "C" { + pub fn fwrite( + __ptr: *const ::std::os::raw::c_void, + __size: ::std::os::raw::c_ulong, + __n: ::std::os::raw::c_ulong, + __s: *mut FILE, + ) -> ::std::os::raw::c_ulong; +} +extern "C" { + pub fn fread_unlocked( + __ptr: *mut ::std::os::raw::c_void, + __size: usize, + __n: usize, + __stream: *mut FILE, + ) -> usize; +} +extern "C" { + pub fn fwrite_unlocked( + __ptr: *const ::std::os::raw::c_void, + __size: usize, + __n: usize, + __stream: *mut FILE, + ) -> usize; +} +extern "C" { + pub fn fseek( + __stream: *mut FILE, + __off: ::std::os::raw::c_long, + __whence: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn ftell(__stream: *mut FILE) -> ::std::os::raw::c_long; +} +extern "C" { + pub fn rewind(__stream: *mut FILE); +} +extern "C" { + pub fn fseeko( + __stream: *mut FILE, + __off: __off_t, + __whence: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn ftello(__stream: *mut FILE) -> __off_t; +} +extern "C" { + pub fn fgetpos(__stream: *mut FILE, __pos: *mut fpos_t) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fsetpos(__stream: *mut FILE, __pos: *const fpos_t) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn clearerr(__stream: *mut FILE); +} +extern "C" { + pub fn feof(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn ferror(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn clearerr_unlocked(__stream: *mut FILE); +} +extern "C" { + pub fn feof_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn ferror_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perror(__s: *const ::std::os::raw::c_char); +} +extern "C" { + pub static mut sys_nerr: ::std::os::raw::c_int; +} +extern "C" { + pub static sys_errlist: [*const ::std::os::raw::c_char; 0usize]; +} +extern "C" { + pub fn fileno(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fileno_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn popen( + __command: *const ::std::os::raw::c_char, + __modes: *const ::std::os::raw::c_char, + ) -> *mut FILE; +} +extern "C" { + pub fn pclose(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn ctermid(__s: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; +} +extern "C" { + pub fn flockfile(__stream: *mut FILE); +} +extern "C" { + pub fn ftrylockfile(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn funlockfile(__stream: *mut FILE); +} +extern "C" { + pub fn __uflow(arg1: *mut FILE) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn __overflow(arg1: *mut FILE, arg2: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +pub type wchar_t = ::std::os::raw::c_int; +#[repr(C)] +#[repr(align(16))] +#[derive(Debug, Copy, Clone)] +pub struct max_align_t { + pub __clang_max_align_nonce1: ::std::os::raw::c_longlong, + pub __bindgen_padding_0: u64, + pub __clang_max_align_nonce2: u128, +} +#[test] +fn bindgen_test_layout_max_align_t() { + const UNINIT: ::std::mem::MaybeUninit<max_align_t> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<max_align_t>(), + 32usize, + concat!("Size of: ", stringify!(max_align_t)) + ); + assert_eq!( + ::std::mem::align_of::<max_align_t>(), + 16usize, + concat!("Alignment of ", stringify!(max_align_t)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).__clang_max_align_nonce1) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(max_align_t), + "::", + stringify!(__clang_max_align_nonce1) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).__clang_max_align_nonce2) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(max_align_t), + "::", + stringify!(__clang_max_align_nonce2) + ) + ); +} +pub const metric_type_METRIC_TYPE_COUNTER: metric_type = 0; +pub const metric_type_METRIC_TYPE_HLL: metric_type = 1; +pub const metric_type_METRIC_TYPE_HISTOGRAM: metric_type = 2; +pub type metric_type = ::std::os::raw::c_uint; +pub const fs_tag_type_TAG_INTEGER: fs_tag_type = 0; +pub const fs_tag_type_TAG_DOUBLE: fs_tag_type = 1; +pub const fs_tag_type_TAG_CSTRING: fs_tag_type = 2; +pub type fs_tag_type = ::std::os::raw::c_uint; +pub const sampling_mode_SAMPLING_MODE_COMPREHENSIVE: sampling_mode = 0; +pub const sampling_mode_SAMPLING_MODE_TOPK: sampling_mode = 1; +pub type sampling_mode = ::std::os::raw::c_uint; +pub const counter_mode_COUNTER_MERGE_BY_SUM: counter_mode = 0; +pub const counter_mode_COUNTER_MERGE_BY_MAX: counter_mode = 1; +pub const counter_mode_COUNTER_MERGE_BY_MIN: counter_mode = 2; +pub type counter_mode = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct fieldstat_tag { + pub key: *const ::std::os::raw::c_char, + pub type_: fs_tag_type, + pub __bindgen_anon_1: fieldstat_tag__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union fieldstat_tag__bindgen_ty_1 { + pub value_longlong: ::std::os::raw::c_longlong, + pub value_double: f64, + pub value_str: *const ::std::os::raw::c_char, +} +#[test] +fn bindgen_test_layout_fieldstat_tag__bindgen_ty_1() { + const UNINIT: ::std::mem::MaybeUninit<fieldstat_tag__bindgen_ty_1> = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<fieldstat_tag__bindgen_ty_1>(), + 8usize, + concat!("Size of: ", stringify!(fieldstat_tag__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::<fieldstat_tag__bindgen_ty_1>(), + 8usize, + concat!("Alignment of ", stringify!(fieldstat_tag__bindgen_ty_1)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).value_longlong) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(fieldstat_tag__bindgen_ty_1), + "::", + stringify!(value_longlong) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).value_double) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(fieldstat_tag__bindgen_ty_1), + "::", + stringify!(value_double) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).value_str) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(fieldstat_tag__bindgen_ty_1), + "::", + stringify!(value_str) + ) + ); +} +#[test] +fn bindgen_test_layout_fieldstat_tag() { + const UNINIT: ::std::mem::MaybeUninit<fieldstat_tag> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<fieldstat_tag>(), + 24usize, + concat!("Size of: ", stringify!(fieldstat_tag)) + ); + assert_eq!( + ::std::mem::align_of::<fieldstat_tag>(), + 8usize, + concat!("Alignment of ", stringify!(fieldstat_tag)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).key) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(fieldstat_tag), + "::", + stringify!(key) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(fieldstat_tag), + "::", + stringify!(type_) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct fieldstat { + _unused: [u8; 0], +} +extern "C" { + pub fn fieldstat_new() -> *mut fieldstat; +} +extern "C" { + pub fn fieldstat_free(instance: *mut fieldstat); +} +extern "C" { + pub fn fieldstat_dup(instance: *const fieldstat) -> *mut fieldstat; +} +extern "C" { + pub fn fieldstat_register_cube( + instance: *mut fieldstat, + shared_tags: *const fieldstat_tag, + n_tag: usize, + mode: sampling_mode, + max_n_cell: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_unregister_cube( + instance: *mut fieldstat, + cube_id: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_get_cube_version( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_longlong; +} +extern "C" { + pub fn fieldstat_register_counter( + instance: *mut fieldstat, + cube_id: ::std::os::raw::c_int, + field_name: *const ::std::os::raw::c_char, + mode: counter_mode, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_register_hll( + instance: *mut fieldstat, + cube_id: ::std::os::raw::c_int, + field_name: *const ::std::os::raw::c_char, + precision: ::std::os::raw::c_uchar, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_register_hist( + instance: *mut fieldstat, + cube_id: ::std::os::raw::c_int, + field_name: *const ::std::os::raw::c_char, + lowest_trackable_value: ::std::os::raw::c_longlong, + highest_trackable_value: ::std::os::raw::c_longlong, + significant_figures: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_cube_add( + instance: *mut fieldstat, + cube_id: ::std::os::raw::c_int, + tags: *const fieldstat_tag, + n_tag: usize, + increment: ::std::os::raw::c_longlong, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_cube_remove( + instance: *mut fieldstat, + cube_id: ::std::os::raw::c_int, + tags: *const fieldstat_tag, + n_tag: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_counter_incrby( + instance: *mut fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + cell_id: ::std::os::raw::c_int, + increment: ::std::os::raw::c_longlong, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_counter_set( + instance: *mut fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + cell_id: ::std::os::raw::c_int, + value: ::std::os::raw::c_longlong, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_hll_add( + instance: *mut fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + cell_id: ::std::os::raw::c_int, + key: *const ::std::os::raw::c_char, + key_len: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_hist_record( + instance: *mut fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + cell_id: ::std::os::raw::c_int, + value: ::std::os::raw::c_longlong, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_reset(instance: *mut fieldstat); +} +extern "C" { + pub fn fieldstat_get_cell_version(instance: *const fieldstat) -> ::std::os::raw::c_ulong; +} +extern "C" { + pub fn fieldstat_merge(instance: *mut fieldstat, src: *mut fieldstat) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_deserialize( + blob: *const ::std::os::raw::c_char, + blob_size: usize, + ) -> *mut fieldstat; +} +extern "C" { + pub fn fieldstat_serialize( + instance: *const fieldstat, + blob_out: *mut *mut ::std::os::raw::c_char, + blob_size_out: *mut usize, + ) -> ::std::os::raw::c_int; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct fieldstat_tag_list { + pub tag: *mut fieldstat_tag, + pub n_tag: usize, +} +#[test] +fn bindgen_test_layout_fieldstat_tag_list() { + const UNINIT: ::std::mem::MaybeUninit<fieldstat_tag_list> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<fieldstat_tag_list>(), + 16usize, + concat!("Size of: ", stringify!(fieldstat_tag_list)) + ); + assert_eq!( + ::std::mem::align_of::<fieldstat_tag_list>(), + 8usize, + concat!("Alignment of ", stringify!(fieldstat_tag_list)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).tag) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(fieldstat_tag_list), + "::", + stringify!(tag) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).n_tag) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(fieldstat_tag_list), + "::", + stringify!(n_tag) + ) + ); +} +extern "C" { + pub fn fieldstat_get_cubes( + instance: *const fieldstat, + cube_ids: *mut *mut ::std::os::raw::c_int, + n_cube: *mut ::std::os::raw::c_int, + ); +} +extern "C" { + pub fn fieldstat_get_max_metric_id( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_get_metric_name( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn fieldstat_get_metric_type( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + ) -> metric_type; +} +extern "C" { + pub fn fieldstat_cube_read_cell( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + cell_ids: *mut *mut ::std::os::raw::c_int, + tag_list: *mut *mut fieldstat_tag_list, + n_cell: *mut usize, + ); +} +extern "C" { + pub fn fieldstat_get_cells( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + cell_ids: *mut *mut ::std::os::raw::c_int, + tag_list: *mut *mut fieldstat_tag_list, + n_cell: *mut usize, + ); +} +extern "C" { + pub fn fieldstat_get_shared_tags( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + ) -> *mut fieldstat_tag_list; +} +extern "C" { + pub fn fieldstat_find_cube( + instance: *const fieldstat, + shared_tags: *const fieldstat_tag, + n_shared_tags: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_get_max_cell_id( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn fieldstat_counter_get( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + cell_id: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_longlong; +} +extern "C" { + pub fn fieldstat_hll_get( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + cell_id: ::std::os::raw::c_int, + ) -> f64; +} +extern "C" { + pub fn fieldstat_hist_value_at_percentile( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + cell_id: ::std::os::raw::c_int, + percentile: f64, + ) -> ::std::os::raw::c_longlong; +} +extern "C" { + pub fn fieldstat_hist_count_le_value( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + cell_id: ::std::os::raw::c_int, + value: ::std::os::raw::c_longlong, + ) -> ::std::os::raw::c_longlong; +} +extern "C" { + pub fn fieldstat_get_serialized_blob( + instance: *const fieldstat, + cube_id: ::std::os::raw::c_int, + metric_id: ::std::os::raw::c_int, + cell_id: ::std::os::raw::c_int, + blob: *mut *mut ::std::os::raw::c_char, + blob_size: *mut usize, + ); +} +extern "C" { + pub fn fieldstat_tag_list_arr_free(tag_list: *mut fieldstat_tag_list, n_cell: usize); +} +pub type __builtin_va_list = [__va_list_tag; 1usize]; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __va_list_tag { + pub gp_offset: ::std::os::raw::c_uint, + pub fp_offset: ::std::os::raw::c_uint, + pub overflow_arg_area: *mut ::std::os::raw::c_void, + pub reg_save_area: *mut ::std::os::raw::c_void, +} +#[test] +fn bindgen_test_layout___va_list_tag() { + const UNINIT: ::std::mem::MaybeUninit<__va_list_tag> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<__va_list_tag>(), + 24usize, + concat!("Size of: ", stringify!(__va_list_tag)) + ); + assert_eq!( + ::std::mem::align_of::<__va_list_tag>(), + 8usize, + concat!("Alignment of ", stringify!(__va_list_tag)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).gp_offset) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__va_list_tag), + "::", + stringify!(gp_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).fp_offset) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(__va_list_tag), + "::", + stringify!(fp_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).overflow_arg_area) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__va_list_tag), + "::", + stringify!(overflow_arg_area) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).reg_save_area) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__va_list_tag), + "::", + stringify!(reg_save_area) + ) + ); +} diff --git a/src/c_lang/mod.rs b/src/c_lang/mod.rs new file mode 100644 index 0000000..a7683a2 --- /dev/null +++ b/src/c_lang/mod.rs @@ -0,0 +1,2 @@ +// pub(crate) mod fs4; +// pub(super) mod fs4_binding;
\ No newline at end of file @@ -1,5 +1,7 @@ #![allow(dead_code)] + pub mod packet; pub mod protocol; -pub mod session;
\ No newline at end of file +pub mod session; +pub mod c_lang;
\ No newline at end of file diff --git a/src/session/tcp_reassembly.rs b/src/session/tcp_reassembly.rs index f812739..5a2db08 100644 --- a/src/session/tcp_reassembly.rs +++ b/src/session/tcp_reassembly.rs @@ -1,1056 +1,396 @@ -use std::collections::VecDeque; -use std::f32::consts::E; -use std::net::{Ipv4Addr}; +use std::collections::BTreeMap; use std::num::Wrapping; -use crate::protocol::ipv4::IPv4Header; -use crate::protocol::ipv6::IPv6Header; -use crate::protocol::udp::UdpHeader; -use crate::protocol::ethernet::EthernetFrame; -use crate::protocol::tcp::{TcpHeader}; -use crate::protocol::dns::DNS_MESSAGE; -use crate::protocol::http::HTTP_MESSAGE; -use crate::packet::packet::Encapsulation; -use crate::packet::packet::Packet as RawPacket; - -const DEFAULT_MAX_PACKETS: usize = 128; - #[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum TcpSegmentDescription { +pub enum Description { // has packet - Normal, + Ok, TooManyPacket, - FinTrigger, - - // no packet - Unordered, - DuplicateSeq, - OldPacket, - NoSegment, - NotIp4Tcp, - - HandshakeFail(String), - SynAckOk, - Reopen, // todo -} - -// since the pub encapsulation has many reference of the original packet buffer, we have to copy them first -#[allow(non_camel_case_types)] -#[derive(Debug, Clone)] -enum CopiedEncapsulation { - L2_ETH(EthernetFrame, Vec<u8>), - L3_IP4(IPv4Header, Vec<u8>), - L3_IP6(IPv6Header, Vec<u8>), - L4_TCP(TcpHeader, Vec<u8>), - L4_UDP(UdpHeader, Vec<u8>), - L7_DNS(DNS_MESSAGE, Vec<u8>), - L7_HTTP(HTTP_MESSAGE, Vec<u8>), - Unsupported(Vec<u8>), -} - -#[derive(Debug, Clone)] -pub(crate) struct CopiedRawPacket { - encapsulation: Vec<CopiedEncapsulation>, - - orig_data: Vec<u8>, - orig_len: u32, -} - -impl CopiedRawPacket { - fn header(&self) -> TcpHeader { - for encapsulation in &self.encapsulation { - match encapsulation { - CopiedEncapsulation::L4_TCP(header, _) => return header.clone(), - _ => {} - } - } - panic!("not a tcp packet"); - } - fn payload(&self) -> &[u8] { - for encapsulation in &self.encapsulation { - match encapsulation { - CopiedEncapsulation::L4_TCP(_, payload) => return payload.as_slice(), - _ => {} - } - } - panic!("not a tcp packet"); - } - fn replace_payload(&mut self, payload: Vec<u8>) { - for encapsulation in &mut self.encapsulation { - match encapsulation { - CopiedEncapsulation::L4_TCP(_, p) => { - *p = payload; - return; - } - _ => {} - } - } - panic!("not a tcp packet"); - } -} - -impl From<Encapsulation<'_>> for CopiedEncapsulation { - fn from(encap: Encapsulation<'_>) -> Self { - match encap { - Encapsulation::L2_ETH(l2, bytes) => CopiedEncapsulation::L2_ETH(l2, bytes.to_vec()), - Encapsulation::L3_IP4(ipv4, bytes) => CopiedEncapsulation::L3_IP4(ipv4, bytes.to_vec()), - Encapsulation::L3_IP6(ipv6, bytes) => CopiedEncapsulation::L3_IP6(ipv6, bytes.to_vec()), - Encapsulation::L4_TCP(tcp, bytes) => CopiedEncapsulation::L4_TCP(tcp, bytes.to_vec()), - Encapsulation::L4_UDP(udp, bytes) => CopiedEncapsulation::L4_UDP(udp, bytes.to_vec()), - Encapsulation::L7_DNS(dns, bytes) => CopiedEncapsulation::L7_DNS(dns, bytes.to_vec()), - Encapsulation::L7_HTTP(http, bytes) => CopiedEncapsulation::L7_HTTP(http, bytes.to_vec()), - Encapsulation::Unsupported(bytes) => CopiedEncapsulation::Unsupported(bytes.to_vec()), - } - } -} - -impl From<&RawPacket<'_>> for CopiedRawPacket { - fn from(packet: &RawPacket) -> Self { - CopiedRawPacket { - encapsulation: packet.encapsulation.clone().into_iter().map(CopiedEncapsulation::from).collect(), - orig_data: packet.orig_data.to_vec(), - orig_len: packet.orig_len, - } - } -} - -fn raw_packet_convert_to_my_packet(raw_packet: &RawPacket<'_>) -> Result<TcpPacket, TcpSegmentDescription> { - let mut payload = Vec::new(); - let mut ipv4_header = Option::None; - let mut tcp_header = Option::None; - for encapsulation in &raw_packet.encapsulation { - match encapsulation { - Encapsulation::L3_IP4(ipv4, _) => { - ipv4_header = Some(ipv4); - } - Encapsulation::L4_TCP(tcp, data) => { - tcp_header = Some(tcp); - payload = data.to_vec(); - } - _ => {} - } - } - if ipv4_header.is_none() || tcp_header.is_none() { - return Err(TcpSegmentDescription::NotIp4Tcp); - } - - Ok(TcpPacket { - payload, - src_ip: ipv4_header.unwrap().source_address, - dst_ip: ipv4_header.unwrap().dest_address, - src_port: tcp_header.unwrap().source_port, - dst_port: tcp_header.unwrap().dest_port, - seq_num: tcp_header.unwrap().seq_num, - ack_num: tcp_header.unwrap().ack_num, - raw_packet: CopiedRawPacket::from(raw_packet), - }) + Timeout, + WindowFull, } -/* -------------------------------------------------------------------------- */ -/* stream */ -/* -------------------------------------------------------------------------- */ - #[derive(Debug, Clone)] -struct TcpPacket { - payload : Vec<u8>, - src_ip: Ipv4Addr, - dst_ip: Ipv4Addr, - src_port: u16, - dst_port: u16, - seq_num: u32, - ack_num: u32, - - raw_packet: CopiedRawPacket, -} - -enum TcpFlags { - FIN = 0x01, - SYN = 0x02, - RST = 0x04, - PSH = 0x08, - ACK = 0x10, - URG = 0x20, -} - -impl TcpPacket { - fn get_sequence(&self) -> u32 { - self.seq_num - } - fn get_acknowledgement(&self) -> u32 { - self.ack_num - } - fn payload(&self) -> &[u8] { - self.payload.as_slice() - } - fn has_flag(&self, flag: TcpFlags) -> bool { - let header = self.raw_packet.header(); - match flag { - TcpFlags::URG => header.flag_urg, - TcpFlags::ACK => header.flag_ack, - TcpFlags::PSH => header.flag_psh, - TcpFlags::RST => header.flag_rst, - TcpFlags::SYN => header.flag_syn, - TcpFlags::FIN => header.flag_fin, - } - } -} - -#[derive(Debug)] -struct TcpSegment { - rel_seq: Wrapping<u32>, // todo: wrapping 主要是解决回绕问题https://blog.csdn.net/LU_ZHAO/article/details/105010778.当前没有实现,不过最好测一下 - -// todo: 带回绕的实际值查询、加减、设置和判断,难点是判断,来了一个新的seq number,我可能就要试一下是不是在回绕的范围内,如果把它当成回绕量,判断发现比上一个seq number 大,且大得很有限,就处理为回绕。 -// 看看其他代码怎么处理的. -// 注意输出到raw packet的时候还要再转一下。 +struct Segment { + rel_seq: Wrapping<u32>, // todo: wrapping 主要是解决回绕问题https://blog.csdn.net/LU_ZHAO/article/details/105010778.这个实现感觉不完全,看看别人怎么搞的 payload: Vec<u8>, - - tcp_header: TcpHeader, - - raw_packet: CopiedRawPacket, - rel_ack: Wrapping<u32>, // todo: 干掉它 } -impl TcpSegment { - /// Return the offset of the overlapping area if `self` (as left) overlaps on `right` - fn overlap_offset(&self, right: &TcpSegment) -> Option<usize> { - let next_seq = self.rel_seq + Wrapping(self.payload.len() as u32); - if next_seq > right.rel_seq { - let overlap_offset = (right.rel_seq - self.rel_seq).0 as usize; - Some(overlap_offset) +impl Segment { + fn offset_part(&self, offset: Wrapping<u32>) -> &[u8] { + let this_right = self.rel_seq + Wrapping(self.payload.len() as u32); + if this_right <= offset { + return &[]; } else { - None - } - } - - /// Splits the segment into two at the given offset. - /// - /// # Panics - /// - /// Panics if `offset > self.payload.len()` - fn split_off(&mut self, offset: usize) -> TcpSegment { - assert!(offset < self.payload.len()); - let remaining = self.payload.split_off(offset); - let rel_seq = self.rel_seq + Wrapping(offset as u32); - TcpSegment { - payload: remaining, - rel_seq, - rel_ack: self.rel_ack, - raw_packet: self.raw_packet.clone(), - tcp_header: self.tcp_header.clone(), + let overlap_size = (offset - self.rel_seq).0 as usize; + return &self.payload[overlap_size..]; } } } #[derive(Debug)] -struct TcpPeer { +pub struct Stream { // Initial Seq number (absolute) isn: Wrapping<u32>, - // Initial Ack number (absolute) - ian: Wrapping<u32>, + // Next Seq number, isn + (sum of all sent segments lengths) next_rel_seq: Wrapping<u32>, + min_rel_seq: Wrapping<u32>, // modified when clear() // The current list of segments that this peer is about to sent (ordered by rel_seq) - segments: VecDeque<TcpSegment>, - addr: Ipv4Addr, - port: u16, -} - -impl TcpPeer { - fn insert_sorted(&mut self, s: TcpSegment) { - for (n, item) in self.segments.iter().enumerate() { - if item.rel_seq > s.rel_seq { - self.segments.insert(n, s); - return; - } - } - self.segments.push_back(s); - } -} - -#[derive(Debug)] -struct TcpStream { - pub client: TcpPeer, - pub server: TcpPeer, - in_connection: bool, -} - - -#[derive(Debug)] -pub struct TcpConnection { - stream: TcpStream, + segments: BTreeMap<u32, Segment>, max_packets: usize, + window_size: usize, + timeout: u64, + + used_window_size: usize, + last_ts: Option<u64>, } -impl TcpPeer { - fn new(addr: &Ipv4Addr, port: u16) -> Self { - TcpPeer { - isn: Wrapping(0), - ian: Wrapping(0), - next_rel_seq: Wrapping(0), - segments: VecDeque::new(), - addr: *addr, - port, - } - } -} - -impl TcpStream { - pub fn new(packet: &TcpPacket) -> Self { - TcpStream { - client: TcpPeer::new(&packet.src_ip, packet.src_port), - server: TcpPeer::new(&packet.dst_ip, packet.dst_port), - in_connection: true, +impl Stream { + pub fn new(isn: u32, window_size: usize, max_packets: usize, timeout: u64) -> Self { + // fn new(isn: u32, max_n_packet, window_size, timeout) -> Self { + Stream { + isn: Wrapping(isn), + next_rel_seq: Wrapping(1), + segments: BTreeMap::new(), + min_rel_seq: Wrapping(isn), + max_packets, + window_size, + timeout, + used_window_size: 0, + last_ts: None, } } - - fn handle_synsent(&mut self, tcp: TcpPacket) { - let seq = Wrapping(tcp.get_sequence()); - - self.client.isn = seq; - self.client.next_rel_seq = Wrapping(1); - self.server.ian = seq; - - if !tcp.payload().is_empty() { - println!("Data in handshake SYN"); - // https://stackoverflow.com/questions/37994131/send-tcp-syn-packet-with-payload - // it is possible to have data in SYN, just queue it(the src window size is 0 currently) - let segment = TcpSegment { - rel_seq: Wrapping(1), // just assume client has sent a ACK, and turn to ESTABLISHED. - payload: tcp.payload().to_vec(), - tcp_header: tcp.raw_packet.header(), - raw_packet: tcp.raw_packet, - rel_ack: Wrapping(1), - }; - queue_segment(&mut self.client, segment); + pub fn update(&mut self, offset: u32, payload: &[u8], time_stamp: u64) -> Description { + if self.segments.len() >= self.max_packets { + return Description::TooManyPacket; } - } - - fn handle_synrcv(&mut self, tcp: TcpPacket) -> Result<(), TcpSegmentDescription> { - // Server -- SYN+ACK --> Client - let (src, dst) = (&mut self.server, &mut self.client); - let seq = Wrapping(tcp.get_sequence()); - let ack = Wrapping(tcp.get_acknowledgement()); - if !tcp.has_flag(TcpFlags::SYN) || !tcp.has_flag(TcpFlags::ACK) { - return Err(TcpSegmentDescription::HandshakeFail("Not a SYN + ACK".to_string())); + if self.used_window_size + payload.len()> self.window_size { + return Description::WindowFull; } - // if we had data in SYN, add its length - let next_rel_seq = if dst.segments.is_empty() { - Wrapping(1) - } else { // - Wrapping(1) + Wrapping(dst.segments[0].payload.len() as u32) - }; - if ack != dst.isn + next_rel_seq { - return Err(TcpSegmentDescription::HandshakeFail("ack number is wrong".to_string())); - } - - src.isn = seq; - src.next_rel_seq = Wrapping(1); - dst.ian = seq; - - Ok(()) - } - - fn update_after_handshake(&mut self, - tcp: TcpPacket, - to_server: bool) -> (Option<Vec<TcpSegment>>, TcpSegmentDescription) { - let (origin, destination) = if to_server { - (&mut self.client, &mut self.server) + if self.last_ts.is_none() { + self.last_ts = Some(time_stamp); } else { - (&mut self.server, &mut self.client) - }; - - let rel_seq = Wrapping(tcp.get_sequence()) - origin.isn; - let rel_ack = Wrapping(tcp.get_acknowledgement()) - destination.isn; - let is_fin = tcp.has_flag(TcpFlags::FIN) || tcp.has_flag(TcpFlags::RST); // before borrowing tcp - - println!("update_after_handshake: payload len={}", tcp.payload().len()); - println!( - " Tcp rel seq {} ack {} next seq {}", - rel_seq, - rel_ack, - origin.next_rel_seq - ); - - let segment = TcpSegment { - rel_seq, - rel_ack, - payload: tcp.payload().to_vec(), // XXX data cloned here - tcp_header: tcp.raw_packet.header(), - raw_packet: tcp.raw_packet, - }; - queue_segment(origin, segment); - if is_fin { - // fin packet can also have payload, so we queued it first. Refer to: - // https://stackoverflow.com/questions/8702646/can-a-tcp-packet-with-the-fin-flag-also-have-data - let sent_pkt = flush_peer_segments(origin); - return (Some(sent_pkt), TcpSegmentDescription::FinTrigger); + let last_ts = self.last_ts.unwrap(); + if (time_stamp > last_ts) && (time_stamp - last_ts > self.timeout) { + return Description::Timeout; + } } - // todo: closed connection restart - let sent_pkt = send_peer_segments(origin); - if origin.segments.len() > DEFAULT_MAX_PACKETS { - let sent_pkt = flush_peer_segments(origin); - return (Some(sent_pkt), TcpSegmentDescription::TooManyPacket); - } + self.last_ts = Some(std::cmp::max(self.last_ts.unwrap(), time_stamp)); - if sent_pkt.is_err() { - return (None, sent_pkt.unwrap_err()); - } else { - return (Some(sent_pkt.unwrap()), TcpSegmentDescription::Normal); + if payload.is_empty() { + return Description::Ok; } - } -} - -fn queue_segment(peer: &mut TcpPeer, segment: TcpSegment) { - if segment.payload.is_empty() { - return; - } - //todo: 老代码有一个 EARLY_DETECT_OVERLAP 不知道干嘛的 - - if peer.segments.is_empty() { - println!("Pushing segment (front)"); - peer.segments.push_front(segment); - return; - } - - println!("Adding segment"); - peer.insert_sorted(segment); -} + let segment = Segment { + rel_seq: Wrapping(offset) - self.isn, + payload: payload.to_vec(), + }; + self.insert_sorted(segment); -// let the peer send segments in its queue, update ack numbers, and pop segments that were sent -fn send_peer_segments(peer: &mut TcpPeer) -> Result<Vec<TcpSegment>, TcpSegmentDescription> { - if peer.segments.is_empty() { - println!("No segment to send"); - return Err(TcpSegmentDescription::NoSegment); + Description::Ok } - let mut ret = Vec::new(); - let mut description = TcpSegmentDescription::Normal; - while !peer.segments.is_empty() { - let segment = &peer.segments[0]; - println!("send segment, payload: {:?}", segment.payload); - if segment.rel_seq > peer.next_rel_seq { // there is a gap - println!("Gap detected"); - description = TcpSegmentDescription::Unordered; - break; + // let the peer send segments in its queue, update ack numbers, and pop segments that were sent + pub fn pop(&mut self) -> Option<Vec<u8>> { + if self.segments.is_empty() { + println!("No segment to send"); + return None; } + let mut ret = Vec::new(); - if segment.rel_seq < peer.next_rel_seq { // caused by flush_peer_segments, or duplicate pkt, omit old segments - // todo: 感觉这里最好区别一下是不是因为flush_peer_segments导致的,虽然只影响错误码 - // 甚至会是over lap 导致的 - println!("Dropping segment"); - if (segment.rel_seq + Wrapping(segment.payload.len() as u32)) > peer.next_rel_seq { - println!("Segment overlaps next, payload before: {:?}", segment.payload); - let mut segment = peer.segments.pop_front().unwrap(); - let overlap_offset = (peer.next_rel_seq - segment.rel_seq).0; - segment.payload = segment.payload.split_off(overlap_offset as usize); - println!("Segment overlaps next, payload after: {:?}", segment.payload); - segment.rel_seq = peer.next_rel_seq; - peer.segments.push_front(segment); - assert!(!peer.segments.is_empty()); - } else if (segment.rel_seq + Wrapping(segment.payload.len() as u32)) == peer.next_rel_seq { - println!("Segment ends at next"); - peer.segments.pop_front(); - description = TcpSegmentDescription::DuplicateSeq; - } else { - peer.segments.pop_front(); - description = TcpSegmentDescription::OldPacket; - println!("Segment ends before next"); + while !self.segments.is_empty() { + if self.segments.first_entry().unwrap().get().rel_seq > self.next_rel_seq { + // there is a gap + println!("Gap detected"); + break; } - continue; - } - - // safety: segments is just tested above - let mut segment = peer.segments.pop_front().unwrap(); - - remove_overlapped(peer, &mut segment); - adjust_seq_numbers(peer, &segment); - println!("Sending segment, payload: {:?}", segment.payload); - segment.raw_packet.replace_payload(segment.payload.clone()); - ret.push(segment); - } - println!("ret len: {}", ret.len()); - if ret.len() == 0 { - return Err(description); - } - Ok(ret) -} - -fn flush_peer_segments(peer: &mut TcpPeer) -> Vec<TcpSegment> { - // 最终预期: - // 1. 队列全清空 - // 2. next seq 正常调整 - - // // 之后呢? - // 标记该Session为满释放异常,并声明一个新的变量,为“上次flush的时候,最大的rel seq” - // 之后,如果有新的segment进来,那么就判断,如果rel seq < 上次flush的最大rel seq,那么直接丢弃 - // 否则,就正常处理,放入队列中。 - - let mut ret = Vec::new(); - while !peer.segments.is_empty() { - // safety: segments is just tested above - let mut segment = peer.segments.pop_front().unwrap(); + let segment = self.segments.pop_first().unwrap().1; + let extention = segment.offset_part(self.next_rel_seq); + ret.extend_from_slice(extention); + self.next_rel_seq += Wrapping(extention.len() as u32); - remove_overlapped(peer, &mut segment); - if peer.segments.len() == 0 { // the last one has the biggest rel seq - peer.next_rel_seq = segment.rel_seq + Wrapping(segment.payload.len() as u32); + self.used_window_size -= segment.payload.len(); } + println!("ret len: {}", ret.len()); - ret.push(segment); - } - - ret -} - - // 情况1: [1,2,3] [4,5,6] - // [3, 4,5] - // 2: [1,2,3] - // [1,2,3] - // 3: [4,5,6] - // [4,5,6] - // 以上三种均为duplicate,直接丢弃 - // 4: [1,2,3] - // [1,2,3,4] - // 保留[1,2,3] [4] - // 5: [2,3] [6,7] - // [1,2,3,4,5,6] - // 保留[1,2,3,4,5,6] [7] -fn remove_overlapped(peer: &mut TcpPeer, segment: &mut TcpSegment) { - // loop while segment has overlap - while let Some(next) = peer.segments.front() { - if let Some(overlap_offset) = segment.overlap_offset(next) { - println!( - "overlaps next candidate (at offset={})", - overlap_offset - ); - // we will modify the subsequent segment (next) - // safety: element presence was tested in outer loop - let next = peer.segments.pop_front().unwrap(); - - // split next - let overlap_size = segment.payload.len() - overlap_offset; - let min_overlap_size = std::cmp::min(overlap_size, next.payload.len()); - // compare overlap area - if next.payload[..min_overlap_size] - != segment.payload[overlap_offset..overlap_offset + min_overlap_size] - { - println!("Overlap area differs!"); - } - if overlap_size >= next.payload.len() { - // subsequent segment starts after and is smaller, so drop it - drop(next); - continue; - } - // otherwise, split next into left and right, drop left and accept right - let mut left = next; - let right = left.split_off(overlap_size); - // to accept right, merge it into segment - segment.payload.extend_from_slice(&right.payload); + if ret.is_empty() { + return None; } else { - // println!("no overlap, break"); - break; + return Some(ret); } } -} - -fn adjust_seq_numbers(origin: &mut TcpPeer, segment: &TcpSegment) { - if !segment.payload.is_empty() { - // adding length is wrong in case of overlap - // origin.next_rel_seq += Wrapping(segment.payload.len() as u32); - origin.next_rel_seq = segment.rel_seq + Wrapping(segment.payload.len() as u32); - } - if segment.tcp_header.flag_fin { - // println!("Segment has FIN"); - origin.next_rel_seq += Wrapping(1); - } -} + pub fn clear(&mut self) -> Vec<Vec<u8>> { + let mut ret = Vec::new(); + + while !self.segments.is_empty() { + let segment = self.segments.pop_first().unwrap().1; -impl TcpConnection { - pub(crate) fn try_new(packet: &RawPacket) -> Result<Self, TcpSegmentDescription> { - let simple_packet = raw_packet_convert_to_my_packet(packet)?; - Self::_try_new(simple_packet) - } + if segment.rel_seq + Wrapping(segment.payload.len() as u32) <= self.next_rel_seq { + continue; + } - pub(crate) fn update(&mut self, packet: &RawPacket) -> (Option<Vec<CopiedRawPacket>>, TcpSegmentDescription) { - let simple_packet = raw_packet_convert_to_my_packet(packet); - if let Err(e) = simple_packet { - return (None, e); + let rel = segment.payload.len() as u32; + if segment.rel_seq > self.next_rel_seq || ret.is_empty() { + ret.push(segment.payload); + self.next_rel_seq = segment.rel_seq + Wrapping(rel); + } else { + if let Some(last) = ret.last_mut() { + let extention = segment.offset_part(self.next_rel_seq); + last.extend_from_slice(extention); + self.next_rel_seq += Wrapping(extention.len() as u32); + } + } } - self._update(simple_packet.unwrap()) - } - fn _try_new(packet: TcpPacket) -> Result<Self, TcpSegmentDescription> { - let mut connection = TcpConnection { - stream: TcpStream::new(&packet), - max_packets: DEFAULT_MAX_PACKETS, - }; + self.min_rel_seq = self.next_rel_seq; + self.used_window_size = 0; + + ret + } - if !packet.has_flag(TcpFlags::SYN) { - return Err(TcpSegmentDescription::HandshakeFail("Not a SYN".to_string())); - } - if packet.has_flag(TcpFlags::ACK) { - println!("First packet is SYN+ACK"); - return Err(TcpSegmentDescription::HandshakeFail("First packet is SYN+ACK".to_string())); - } - if packet.has_flag(TcpFlags::RST) { - return Err(TcpSegmentDescription::HandshakeFail("First packet is RST".to_string())); - } - if packet.has_flag(TcpFlags::FIN) { - return Err(TcpSegmentDescription::HandshakeFail("First packet is FIN".to_string())); + pub fn pullup(&mut self) -> &[u8] { + let ret = self.pop(); + if ret.is_none() { + return &[]; } + let ret = ret.unwrap(); + self.insert_sorted(Segment { + rel_seq: self.next_rel_seq, + payload: ret, + }); - connection.stream.handle_synsent(packet); - Ok(connection) + self.segments.iter().next().unwrap().1.payload.as_slice() } - fn _update(&mut self, tcp: TcpPacket) -> (Option<Vec<CopiedRawPacket>>, TcpSegmentDescription) { - let stream = &mut self.stream; - - - // get origin and destination - let to_server = tcp.dst_ip == stream.server.addr && - tcp.dst_port == stream.server.port; - println!("to_server: {}", to_server); - - if self.stream.in_connection { - let ret = self.stream.handle_synrcv(tcp); - if let Err(e) = ret { - return (None, e); - } - - self.stream.in_connection = false; - return (None, TcpSegmentDescription::SynAckOk); + fn insert_sorted(&mut self, s: Segment) { + if s.rel_seq < self.min_rel_seq { + return; } - let (segments, ret) = self.stream.update_after_handshake(tcp, to_server); - - if segments.is_none() { - return (None, ret); - } - - let ret_packet = segments.unwrap().into_iter(). - map(|segment| {segment.raw_packet}).collect(); - - return (Some(ret_packet), ret); + self.used_window_size += s.payload.len(); + self.segments.insert(s.rel_seq.0, s); // todo: 换成wrap 以后这里的key 要有新的比较逻辑 } } - #[cfg(test)] mod tests { - use std::vec; - use crate::protocol::ip::IPProtocol; - use super::*; - static SLICE_DUMMY:&[u8] = &[42,42,42]; - - #[derive(Debug, Clone)] - enum PeerRole { - Client, - Server, - } - #[derive(Debug, Clone)] - struct PeerInTest { - addr: Ipv4Addr, - /// println: port - port: u16, - role: PeerRole, - } - - fn new_raw<'a>(from: &PeerInTest, to: &PeerInTest, seq_num: u32, ack_num: u32, - has_ack: bool, has_syn: bool, has_rst: bool, has_fin: bool, segment: &'a [u8]) - -> RawPacket<'a> { - let src_ip = from.addr; - let dst_ip = to.addr; - let header = TcpHeader { - source_port: from.port, - dest_port: to.port, - seq_num, - ack_num, - data_offset: 0, - reserved: 0, - flag_urg: false, - flag_ack: has_ack, - flag_psh: false, - flag_rst: has_rst, - flag_syn: has_syn, - flag_fin: has_fin, - window: 65535, - checksum: 0, - urgent_ptr: 0, - options: None, - }; - - let ip_header = IPv4Header { - version: 4, - ihl: 5, - tos: 0, - length: 0, - id: 0, - flags: 0, - frag_offset: 0, - ttl: 0, - protocol: IPProtocol::TCP, - checksum: 0, - source_address: src_ip, - dest_address: dst_ip, - }; - - let encap1 : Encapsulation = Encapsulation::L3_IP4(ip_header, SLICE_DUMMY); - let encap2 : Encapsulation = Encapsulation::L4_TCP(header, segment); - let encap_vec = vec![encap1, encap2]; - - RawPacket { - orig_data: SLICE_DUMMY, - orig_len: SLICE_DUMMY.len() as u32, - encapsulation: encap_vec, - } - } - - const CLIENT: PeerInTest = PeerInTest { - addr: Ipv4Addr::new(192, 168, 1, 1), - port: 1234, - role: PeerRole::Client, - }; - const SERVER: PeerInTest = PeerInTest { - addr: Ipv4Addr::new(192, 168, 1, 2), - port: 80, - role: PeerRole::Server, - }; - #[test] - fn single_segment_ping_pong() { - const INIT_SEQ:u32 = 12345; - let packet_handshake1 = new_raw(&CLIENT, &SERVER, INIT_SEQ + 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, INIT_SEQ+1, true, true, false, false, &[]); - let ret = connection.update(&packet_handshake2); - assert!(ret.1 == TcpSegmentDescription::SynAckOk); - - let packet_established_from_client = new_raw(&CLIENT, &SERVER, INIT_SEQ+1, 1, true, false, false, false, &[1, 2, 3]); - let ret = connection.update(&packet_established_from_client); - println!("ret: {:?}", ret); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.unwrap()[0].payload() == &[1, 2, 3]); - - let packet_established_from_server = new_raw(&SERVER, &CLIENT, 1, INIT_SEQ+4, true, false, false, false, &[4, 5, 6]); - let ret = connection.update(&packet_established_from_server); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.unwrap()[0].payload() == &[4, 5, 6]); - - let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, INIT_SEQ+4, 4, true, false, false, false, &[7, 8, 9]); - let ret = connection.update(&packet_established_from_client2); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.unwrap()[0].payload() == &[7, 8, 9]); - } - - #[test] - fn several_ordered_consecutive_segments() { - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); - connection.update(&packet_handshake2); + fn several_ordered_segments() { + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(1, &[1, 2, 3], 0), Description::Ok); + assert_eq!(s.update(4, &[4, 5], 0), Description::Ok); + assert_eq!(s.update(6, &[6], 0), Description::Ok); - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1, 2, 3]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.unwrap()[0].payload() == &[1, 2, 3]); - let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 4, 1, true, false, false, false, &[4, 5, 6]); - let ret = connection.update(&packet_established_from_client2); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.unwrap()[0].payload() == &[4, 5, 6]); - let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 7, 1, true, false, false, false, &[7, 8, 9]); - let ret = connection.update(&packet_established_from_client3); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.unwrap()[0].payload() == &[7, 8, 9]); + assert_eq!(s.pullup(), &[1, 2, 3, 4, 5, 6]); + let expected_clear = vec![vec![1, 2, 3, 4, 5, 6]]; + assert_eq!(s.clear(), expected_clear); } #[test] - fn several_unordered_consecutive_segments() { - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); - connection.update(&packet_handshake2); + fn several_unordered_segments() { + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(6, &[6], 0), Description::Ok); + assert_eq!(s.update(1, &[1, 2, 3], 0), Description::Ok); + assert_eq!(s.update(4, &[4, 5], 0), Description::Ok); - let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 4, 1, true, false, false, false, &[4, 5, 6]); - let ret = connection.update(&packet_established_from_client2); - assert!(ret.1 == TcpSegmentDescription::Unordered); - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1, 2, 3]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[1, 2, 3]); - assert!(ret.0.unwrap()[1].payload() == &[4, 5, 6]); - let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 7, 1, true, false, false, false, &[7, 8, 9]); - let ret = connection.update(&packet_established_from_client3); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.unwrap()[0].payload() == &[7, 8, 9]); + assert_eq!(s.pullup(), &[1, 2, 3, 4, 5, 6]); + let expected_clear = vec![vec![1, 2, 3, 4, 5, 6]]; + assert_eq!(s.clear(), expected_clear); } #[test] - fn several_unordered_inconsecutive_segments() { - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); - connection.update(&packet_handshake2); - - let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 4, 1, true, false, false, false, &[4, 5, 6]); - let ret = connection.update(&packet_established_from_client2); - println!("ret: {:?}", ret); - assert!(ret.1 == TcpSegmentDescription::Unordered); - let packet_from_server = new_raw(&SERVER, &CLIENT, 1, 1, true, false, false, false, &[11, 12, 13]); - let ret = connection.update(&packet_from_server); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[11, 12, 13]); + fn with_hole() { + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(1, &[1, 2], 0), Description::Ok); // miss 3 + assert_eq!(s.update(4, &[4, 5], 0), Description::Ok); + assert_eq!(s.update(6, &[6], 0), Description::Ok); // miss 7 + assert_eq!(s.update(8, &[8, 9], 0), Description::Ok); - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1, 2, 3]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[1, 2, 3]); - assert!(ret.0.unwrap()[1].payload() == &[4, 5, 6]); - let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 7, 1, true, false, false, false, &[7, 8, 9]); - let ret = connection.update(&packet_established_from_client3); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.unwrap()[0].payload() == &[7, 8, 9]); + let expected_clear = vec![vec![1, 2], vec![4, 5, 6], vec![8, 9]]; + assert_eq!(s.clear(), expected_clear); } #[test] fn duplicate_packet() { - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); - connection.update(&packet_handshake2); + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(1, &[1, 2, 3], 0), Description::Ok); + assert_eq!(s.update(1, &[1, 2, 3], 0), Description::Ok); + assert_eq!(s.update(4, &[4, 5], 0), Description::Ok); - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1, 2, 3]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[1, 2, 3]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::DuplicateSeq); - assert!(ret.0.is_none()); + assert_eq!(s.pullup(), &[1, 2, 3, 4, 5]); + let expected_clear = vec![vec![1, 2, 3, 4, 5]]; + assert_eq!(s.clear(), expected_clear); } #[test] - fn too_many_packet() { - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); - connection.update(&packet_handshake2); - - // let first packet drop , so that the queue will be filled until full - for i in 1..DEFAULT_MAX_PACKETS + 1{ - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1 + i as u32, 1, true, false, false, false, &[1]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::Unordered); - } - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1 + DEFAULT_MAX_PACKETS as u32, 1, true, false, false, false, &[1]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::TooManyPacket); - assert!(ret.0.unwrap().len() == DEFAULT_MAX_PACKETS); - - // the first packet come unexpectedly, just throw it away - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::OldPacket); - assert!(ret.0.is_none()); - - // continue to send - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 2 + DEFAULT_MAX_PACKETS as u32, 1, true, false, false, false, &[2,3,4]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.unwrap()[0].payload() == &[2,3,4]); + fn pop_empty() { + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.pop(), None); } #[test] - fn segment_in_syn() { - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[1,2,3]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 4, true, true, false, false, &[]); - connection.update(&packet_handshake2); + fn pop_blocked_by_hole() { + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(1, &[1, 2], 0), Description::Ok); // miss 3 + assert_eq!(s.update(4, &[4, 5], 0), Description::Ok); - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 4, 1, true, false, false, false, &[4,5,6]); - let ret = connection.update(&packet_established_from_client); - println!("ret: {:?}", ret); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[1,2,3]); - assert!(ret.0.as_ref().unwrap()[1].payload() == &[4,5,6]); + assert_eq!(s.pop().unwrap(), &[1, 2]); + assert_eq!(s.pop(), None); + assert_eq!(s.pop(), None); + + assert_eq!(s.update(3, &[3], 0), Description::Ok); + assert_eq!(s.pop().unwrap(), &[3, 4, 5]); } #[test] - fn wrong_flag_during_handshake_syn() { - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, false, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1); - assert!(connection.is_err()); - assert!(connection.unwrap_err() == TcpSegmentDescription::HandshakeFail("Not a SYN".to_string())); - - - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, true, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1); - assert!(connection.is_err()); - assert!(connection.unwrap_err() == TcpSegmentDescription::HandshakeFail("First packet is RST".to_string())); + fn overlap_when_popped() { + // [1,2,3] -> popped + // [3,4,5,6] -> [4,5,6] + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(1, &[1, 2, 3], 0), Description::Ok); + assert_eq!(s.pop().unwrap(), &[1, 2, 3]); + assert_eq!(s.update(3, &[3, 4, 5, 6], 0), Description::Ok); + assert_eq!(s.pop().unwrap(), &[4, 5, 6]); } #[test] - fn wrong_flag_during_handshake_acksyn() { - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[1,2,3]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 3, true, true, false, false, &[]); // expected ack num is 4 - let ret = connection.update(&packet_handshake2); - assert!(ret.1 == TcpSegmentDescription::HandshakeFail("ack number is wrong".to_string())); - - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 4, false, true, false, false, &[]); // no ack - let ret = connection.update(&packet_handshake2); - assert!(ret.1 == TcpSegmentDescription::HandshakeFail("Not a SYN + ACK".to_string())); + fn overlap_as_old_packet() { + // [1,2,3,4,5,6] -> popped + // [2,3,4] -> drop(description: old packet) + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(1, &[1, 2, 3, 4, 5, 6], 0), Description::Ok); + assert_eq!(s.pop().unwrap(), &[1, 2, 3, 4, 5, 6]); + assert_eq!(s.update(2, &[2, 3, 4], 0), Description::Ok); + assert_eq!(s.pop(), None); } #[test] - fn not_tcp_ip_packet() { - let mut packet = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - packet.encapsulation.pop(); - let mut connection = TcpConnection::try_new(&packet); - assert!(connection.is_err()); - assert!(connection.unwrap_err() == TcpSegmentDescription::NotIp4Tcp); + fn overlap_change_next_one() { + // [2,3,4] -> wait + // [3,4,5] -> wait(join the first as [2,3,4,5]) + // [1] -> send [1 2,3,4,5] + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(2, &[2, 3, 4], 0), Description::Ok); + assert_eq!(s.update(3, &[3, 4, 5], 0), Description::Ok); + assert!(s.pop().is_none()); + + assert_eq!(s.update(1, &[1], 0), Description::Ok); + assert_eq!(s.pop().unwrap(), &[1, 2, 3, 4, 5]); } #[test] - fn fin_with_data() { - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); - connection.update(&packet_handshake2); - - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 2, 1, true, false, false, false, &[2,3]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::Unordered); + fn overlap_del_next_one() { + // [2,3,4,5] -> wait + // [3,4,5] -> del(overlapped) + // [1,2,3] -> send [1,2,3,4,5] + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(2, &[2, 3, 4, 5], 0), Description::Ok); + assert_eq!(s.update(3, &[3, 4, 5], 0), Description::Ok); + assert!(s.pop().is_none()); - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 4, 1, true, false, false, true, &[4,5,6]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::FinTrigger); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[2,3]); - assert!(ret.0.as_ref().unwrap()[1].payload() == &[4,5,6]); + assert_eq!(s.update(1, &[1, 2, 3], 0), Description::Ok); + assert_eq!(s.pop().unwrap(), &[1, 2, 3, 4, 5]); } #[test] - fn overlap_partially_sent_before() { - // [1,2,3] -> sent - // [3,4,5,6] -> [4,5,6] - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); - connection.update(&packet_handshake2); - - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1,2,3]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[1,2,3]); + fn overlap_surpass_all() { + // [2] -> wait + // [3] -> wait + // [1,2,3,4] -> send [1,2,3,4] + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(2, &[2], 0), Description::Ok); + assert_eq!(s.update(3, &[3], 0), Description::Ok); + assert!(s.pop().is_none()); - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 3, 1, true, false, false, false, &[3,4,5,6]); - let ret = connection.update(&packet_established_from_client); - println!("ret: {:?}", ret.0.as_ref().unwrap()[0].payload()); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[4,5,6]); // [3] overlap, only send [4,5,6] + assert_eq!(s.update(1, &[1, 2, 3, 4], 0), Description::Ok); + assert_eq!(s.pop().unwrap(), &[1, 2, 3, 4]); } #[test] - fn overlap_as_old_packet() { - // [1,2,3,4,5,6] -> sent - // [2,3,4] -> drop(description: old packet) - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); - connection.update(&packet_handshake2); - - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1,2,3,4,5,6]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[1,2,3,4,5,6]); + fn clear_and_omit_old_packet() { + // [2,3,4] -> wait + // [3,4,5] -> clear ( return [2,3,4,5] ) + // [1] -> omit + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(2, &[2, 3, 4], 0), Description::Ok); + assert_eq!(s.update(3, &[3, 4, 5], 0), Description::Ok); + assert_eq!(s.clear(), vec![vec![2, 3, 4, 5]]); - let packet_established_from_client = new_raw(&CLIENT, &SERVER, 2, 1, true, false, false, false, &[2,3,4]); - let ret = connection.update(&packet_established_from_client); - assert!(ret.1 == TcpSegmentDescription::OldPacket); - assert!(ret.0.is_none()); + assert_eq!(s.update(1, &[1], 0), Description::Ok); + assert_eq!(s.clear(), Vec::<Vec<u8>>::new()); // 返回空还是返回[1]? } #[test] - fn overlap_change_next_one() { - // [2,3,4] -> wait - // [3,4,5] -> wait(join the first as [2,3,4,5]) - // [1] -> send [1] [2,3,4,5] - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); - connection.update(&packet_handshake2); + fn clear_and_omit_old_packet_even_though_something_new() { // it's not a normal case. + // [2] -> wait + // [3] -> clear ( return [2,3] ) + // [1,2,3,4] -> omit + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(2, &[2], 0), Description::Ok); + assert_eq!(s.update(3, &[3], 0), Description::Ok); + assert_eq!(s.clear(), vec![vec![2, 3]]); - let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 2, 1, true, false, false, false, &[2,3,4]); - let packet_established_from_client1 = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1]); - let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 3, 1, true, false, false, false, &[3,4,5]); - let ret = connection.update(&packet_established_from_client2); - assert!(ret.1 == TcpSegmentDescription::Unordered); - let ret = connection.update(&packet_established_from_client3); - assert!(ret.1 == TcpSegmentDescription::Unordered); - let ret = connection.update(&packet_established_from_client1); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.as_ref().unwrap().len() == 2); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[1]); - assert!(ret.0.as_ref().unwrap()[1].payload() == &[2,3,4,5]); + assert_eq!(s.update(1, &[1, 2, 3, 4], 0), Description::Ok); + assert_eq!(s.clear(), Vec::<Vec<u8>>::new()); } #[test] - fn overlap_del_next_one() { + fn overlap_completely_during_clear() { // [2,3,4,5] -> wait // [3,4,5] -> del(overlapped) - // [1,2,3] -> send [1,2,3,4,5] - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); - connection.update(&packet_handshake2); + // [1,2,3] -> omit + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(2, &[2, 3, 4, 5], 0), Description::Ok); + assert_eq!(s.update(3, &[3, 4, 5], 0), Description::Ok); + assert_eq!(s.clear(), vec![vec![2, 3, 4, 5]]); - let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 2, 1, true, false, false, false, &[2,3,4,5]); - let packet_established_from_client1 = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1,2,3]); - let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 3, 1, true, false, false, false, &[3,4,5]); - let ret = connection.update(&packet_established_from_client2); - assert!(ret.1 == TcpSegmentDescription::Unordered); - let ret = connection.update(&packet_established_from_client3); - assert!(ret.1 == TcpSegmentDescription::Unordered); - let ret = connection.update(&packet_established_from_client1); - assert!(ret.1 == TcpSegmentDescription::Normal); - println!("ret: {:?}", ret.0.as_ref().unwrap()); + assert_eq!(s.update(1, &[1, 2, 3], 0), Description::Ok); + assert_eq!(s.clear(), Vec::<Vec<u8>>::new()); + } + + #[test] + fn timeout() { + let mut s = Stream::new(0, 10000, 100, 10000); + assert_eq!(s.update(1, &[1, 2, 3, 4], 10001), Description::Ok); + assert_eq!(s.update(5, &[2, 3, 4, 5], 20002), Description::Timeout); - assert!(ret.0.as_ref().unwrap().len() == 1); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[1,2,3,4,5]); + assert_eq!(s.clear(), vec![vec![1, 2, 3, 4]]); } #[test] - fn overlap_surpass_all() { - // [2] -> wait - // [3] -> wait - // [1,2,3,4] -> send [1,2,3,4] - let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); - let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); - let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); - connection.update(&packet_handshake2); + fn full_window() { + let mut s = Stream::new(0, 10, 100, 10000); - let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 2, 1, true, false, false, false, &[2]); - let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 3, 1, true, false, false, false, &[3]); - let packet_established_from_client1 = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1,2,3,4]); - let ret = connection.update(&packet_established_from_client3); - assert!(ret.1 == TcpSegmentDescription::Unordered); - let ret = connection.update(&packet_established_from_client2); - assert!(ret.1 == TcpSegmentDescription::Unordered); - let ret = connection.update(&packet_established_from_client1); - assert!(ret.1 == TcpSegmentDescription::Normal); - assert!(ret.0.as_ref().unwrap().len() == 1); - assert!(ret.0.as_ref().unwrap()[0].payload() == &[1,2,3,4]); + assert_eq!(s.update(1, &[1, 2, 3, 4], 0), Description::Ok); + assert_eq!(s.update(5, &[5, 6, 7, 8], 0), Description::Ok); + assert_eq!(s.update(9, &[2, 3, 4, 5], 0), Description::WindowFull); + + assert_eq!(s.pop().unwrap(), &[1, 2, 3, 4, 5, 6, 7, 8]); // pop will clear window size + + let v:Vec<_> = (1..=10).collect(); + assert_eq!(s.update(9, v.as_slice(), 0), Description::Ok); + assert_eq!(s.update(19, &[1], 0), Description::WindowFull); } + #[test] + fn too_many_packet() { + let mut s = Stream::new(0, 10000, 2, 10000); + assert_eq!(s.update(1, &[1, 2, 3, 4], 0), Description::Ok); + assert_eq!(s.update(6, &[6, 7, 8], 0), Description::Ok); // hole + assert_eq!(s.update(9, &[2, 3, 4, 5], 0), Description::TooManyPacket); + assert_eq!(s.pop().unwrap(), &[1, 2, 3, 4]); // pop 1 - // todo: 回绕 -}
\ No newline at end of file + assert_eq!(s.update(9, &[11], 0), Description::Ok); + assert_eq!(s.update(10, &[12], 0), Description::TooManyPacket); + assert_eq!(s.clear(), vec![vec![6, 7, 8, 11]]); + } +} diff --git a/src/session/tcp_reassembly_with_deque.rs b/src/session/tcp_reassembly_with_deque.rs new file mode 100644 index 0000000..0cb14ca --- /dev/null +++ b/src/session/tcp_reassembly_with_deque.rs @@ -0,0 +1,1069 @@ +use std::collections::VecDeque; +use std::f32::consts::E; +use std::net::{Ipv4Addr}; +use std::num::Wrapping; + +use crate::protocol::ipv4::IPv4Header; +use crate::protocol::ipv6::IPv6Header; +use crate::protocol::udp::UdpHeader; +use crate::protocol::ethernet::EthernetFrame; +use crate::protocol::tcp::{TcpHeader}; +use crate::protocol::dns::DNS_MESSAGE; +use crate::protocol::http::HTTP_MESSAGE; +use crate::packet::packet::Encapsulation; +use crate::packet::packet::Packet as RawPacket; + +const DEFAULT_MAX_PACKETS: usize = 128; + + + + +//todo: evbuffer + +// todo: 超时 rdt +// 内存(所有segment 一共加起来有几个byte) +// window size +// 提供各种接口,来设置我的行为 +// todo: interval tree 重新处理overlap 问题 + + + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum TcpSegmentDescription { + // has packet + Normal, + TooManyPacket, + FinTrigger, + + // no packet + Unordered, + DuplicateSeq, + OldPacket, + NoSegment, + NotIp4Tcp, + + HandshakeFail(String), + SynAckOk, + Reopen, // todo +} + +// since the pub encapsulation has many reference of the original packet buffer, we have to copy them first +#[allow(non_camel_case_types)] +#[derive(Debug, Clone)] +enum CopiedEncapsulation { + L2_ETH(EthernetFrame, Vec<u8>), + L3_IP4(IPv4Header, Vec<u8>), + L3_IP6(IPv6Header, Vec<u8>), + L4_TCP(TcpHeader, Vec<u8>), + L4_UDP(UdpHeader, Vec<u8>), + L7_DNS(DNS_MESSAGE, Vec<u8>), + L7_HTTP(HTTP_MESSAGE, Vec<u8>), + Unsupported(Vec<u8>), +} + +#[derive(Debug, Clone)] +pub(crate) struct CopiedRawPacket { + encapsulation: Vec<CopiedEncapsulation>, + + orig_data: Vec<u8>, + orig_len: u32, +} + +impl CopiedRawPacket { + fn header(&self) -> TcpHeader { + for encapsulation in &self.encapsulation { + match encapsulation { + CopiedEncapsulation::L4_TCP(header, _) => return header.clone(), + _ => {} + } + } + panic!("not a tcp packet"); + } + fn payload(&self) -> &[u8] { + for encapsulation in &self.encapsulation { + match encapsulation { + CopiedEncapsulation::L4_TCP(_, payload) => return payload.as_slice(), + _ => {} + } + } + panic!("not a tcp packet"); + } + fn replace_payload(&mut self, payload: Vec<u8>) { + for encapsulation in &mut self.encapsulation { + match encapsulation { + CopiedEncapsulation::L4_TCP(_, p) => { + *p = payload; + return; + } + _ => {} + } + } + panic!("not a tcp packet"); + } +} + +impl From<Encapsulation<'_>> for CopiedEncapsulation { + fn from(encap: Encapsulation<'_>) -> Self { + match encap { + Encapsulation::L2_ETH(l2, bytes) => CopiedEncapsulation::L2_ETH(l2, bytes.to_vec()), + Encapsulation::L3_IP4(ipv4, bytes) => CopiedEncapsulation::L3_IP4(ipv4, bytes.to_vec()), + Encapsulation::L3_IP6(ipv6, bytes) => CopiedEncapsulation::L3_IP6(ipv6, bytes.to_vec()), + Encapsulation::L4_TCP(tcp, bytes) => CopiedEncapsulation::L4_TCP(tcp, bytes.to_vec()), + Encapsulation::L4_UDP(udp, bytes) => CopiedEncapsulation::L4_UDP(udp, bytes.to_vec()), + Encapsulation::L7_DNS(dns, bytes) => CopiedEncapsulation::L7_DNS(dns, bytes.to_vec()), + Encapsulation::L7_HTTP(http, bytes) => CopiedEncapsulation::L7_HTTP(http, bytes.to_vec()), + Encapsulation::Unsupported(bytes) => CopiedEncapsulation::Unsupported(bytes.to_vec()), + } + } +} + +impl From<&RawPacket<'_>> for CopiedRawPacket { + fn from(packet: &RawPacket) -> Self { + CopiedRawPacket { + encapsulation: packet.encapsulation.clone().into_iter().map(CopiedEncapsulation::from).collect(), + orig_data: packet.orig_data.to_vec(), + orig_len: packet.orig_len, + } + } +} + +fn raw_packet_convert_to_my_packet(raw_packet: &RawPacket<'_>) -> Result<TcpPacket, TcpSegmentDescription> { + let mut payload = Vec::new(); + let mut ipv4_header = Option::None; + let mut tcp_header = Option::None; + for encapsulation in &raw_packet.encapsulation { + match encapsulation { + Encapsulation::L3_IP4(ipv4, _) => { + ipv4_header = Some(ipv4); + } + Encapsulation::L4_TCP(tcp, data) => { + tcp_header = Some(tcp); + payload = data.to_vec(); + } + _ => {} + } + } + if ipv4_header.is_none() || tcp_header.is_none() { + return Err(TcpSegmentDescription::NotIp4Tcp); + } + + Ok(TcpPacket { + payload, + src_ip: ipv4_header.unwrap().source_address, + dst_ip: ipv4_header.unwrap().dest_address, + src_port: tcp_header.unwrap().source_port, + dst_port: tcp_header.unwrap().dest_port, + seq_num: tcp_header.unwrap().seq_num, + ack_num: tcp_header.unwrap().ack_num, + raw_packet: CopiedRawPacket::from(raw_packet), + }) +} + +/* -------------------------------------------------------------------------- */ +/* stream */ +/* -------------------------------------------------------------------------- */ + +#[derive(Debug, Clone)] +struct TcpPacket { + payload : Vec<u8>, + src_ip: Ipv4Addr, + dst_ip: Ipv4Addr, + src_port: u16, + dst_port: u16, + seq_num: u32, + ack_num: u32, + + raw_packet: CopiedRawPacket, +} + +enum TcpFlags { + FIN = 0x01, + SYN = 0x02, + RST = 0x04, + PSH = 0x08, + ACK = 0x10, + URG = 0x20, +} + +impl TcpPacket { + fn get_sequence(&self) -> u32 { + self.seq_num + } + fn get_acknowledgement(&self) -> u32 { + self.ack_num + } + fn payload(&self) -> &[u8] { + self.payload.as_slice() + } + fn has_flag(&self, flag: TcpFlags) -> bool { + let header = self.raw_packet.header(); + match flag { + TcpFlags::URG => header.flag_urg, + TcpFlags::ACK => header.flag_ack, + TcpFlags::PSH => header.flag_psh, + TcpFlags::RST => header.flag_rst, + TcpFlags::SYN => header.flag_syn, + TcpFlags::FIN => header.flag_fin, + } + } +} + +#[derive(Debug)] +struct TcpSegment { + rel_seq: Wrapping<u32>, // todo: wrapping 主要是解决回绕问题https://blog.csdn.net/LU_ZHAO/article/details/105010778.当前没有实现,不过最好测一下 + +// todo: 带回绕的实际值查询、加减、设置和判断,难点是判断,来了一个新的seq number,我可能就要试一下是不是在回绕的范围内,如果把它当成回绕量,判断发现比上一个seq number 大,且大得很有限,就处理为回绕。 +// 看看其他代码怎么处理的. +// 注意输出到raw packet的时候还要再转一下。 + payload: Vec<u8>, + + tcp_header: TcpHeader, + + raw_packet: CopiedRawPacket, + rel_ack: Wrapping<u32>, // todo: 干掉它 +} + +impl TcpSegment { + /// Return the offset of the overlapping area if `self` (as left) overlaps on `right` + fn overlap_offset(&self, right: &TcpSegment) -> Option<usize> { + let next_seq = self.rel_seq + Wrapping(self.payload.len() as u32); + if next_seq > right.rel_seq { + let overlap_offset = (right.rel_seq - self.rel_seq).0 as usize; + Some(overlap_offset) + } else { + None + } + } + + /// Splits the segment into two at the given offset. + /// + /// # Panics + /// + /// Panics if `offset > self.payload.len()` + fn split_off(&mut self, offset: usize) -> TcpSegment { + assert!(offset < self.payload.len()); + let remaining = self.payload.split_off(offset); + let rel_seq = self.rel_seq + Wrapping(offset as u32); + TcpSegment { + payload: remaining, + rel_seq, + rel_ack: self.rel_ack, + raw_packet: self.raw_packet.clone(), + tcp_header: self.tcp_header.clone(), + } + } +} + +#[derive(Debug)] +struct TcpPeer { + // Initial Seq number (absolute) + isn: Wrapping<u32>, + // Initial Ack number (absolute) + ian: Wrapping<u32>, + // Next Seq number, isn + (sum of all sent segments lengths) + next_rel_seq: Wrapping<u32>, + // The current list of segments that this peer is about to sent (ordered by rel_seq) + segments: VecDeque<TcpSegment>, + addr: Ipv4Addr, + port: u16, +} + +impl TcpPeer { + fn insert_sorted(&mut self, s: TcpSegment) { + for (n, item) in self.segments.iter().enumerate() { + if item.rel_seq > s.rel_seq { + self.segments.insert(n, s); + return; + } + } + self.segments.push_back(s); + } +} + +#[derive(Debug)] +struct TcpStream { + pub client: TcpPeer, + pub server: TcpPeer, + in_connection: bool, +} + + +#[derive(Debug)] +pub struct TcpConnection { + stream: TcpStream, + + max_packets: usize, +} + +impl TcpPeer { + fn new(addr: &Ipv4Addr, port: u16) -> Self { + TcpPeer { + isn: Wrapping(0), + ian: Wrapping(0), + next_rel_seq: Wrapping(0), + segments: VecDeque::new(), + addr: *addr, + port, + } + } +} + +impl TcpStream { + pub fn new(packet: &TcpPacket) -> Self { + TcpStream { + client: TcpPeer::new(&packet.src_ip, packet.src_port), + server: TcpPeer::new(&packet.dst_ip, packet.dst_port), + in_connection: true, + } + } + + fn handle_synsent(&mut self, tcp: TcpPacket) { + let seq = Wrapping(tcp.get_sequence()); + + self.client.isn = seq; + self.client.next_rel_seq = Wrapping(1); + self.server.ian = seq; + + if !tcp.payload().is_empty() { + println!("Data in handshake SYN"); + // https://stackoverflow.com/questions/37994131/send-tcp-syn-packet-with-payload + // it is possible to have data in SYN, just queue it(the src window size is 0 currently) + let segment = TcpSegment { + rel_seq: Wrapping(1), // just assume client has sent a ACK, and turn to ESTABLISHED. + payload: tcp.payload().to_vec(), + tcp_header: tcp.raw_packet.header(), + raw_packet: tcp.raw_packet, + rel_ack: Wrapping(1), + }; + queue_segment(&mut self.client, segment); + } + } + + fn handle_synrcv(&mut self, tcp: TcpPacket) -> Result<(), TcpSegmentDescription> { + // Server -- SYN+ACK --> Client + let (src, dst) = (&mut self.server, &mut self.client); + let seq = Wrapping(tcp.get_sequence()); + let ack = Wrapping(tcp.get_acknowledgement()); + + if !tcp.has_flag(TcpFlags::SYN) || !tcp.has_flag(TcpFlags::ACK) { + return Err(TcpSegmentDescription::HandshakeFail("Not a SYN + ACK".to_string())); + } + + // if we had data in SYN, add its length + let next_rel_seq = if dst.segments.is_empty() { + Wrapping(1) + } else { // + Wrapping(1) + Wrapping(dst.segments[0].payload.len() as u32) + }; + if ack != dst.isn + next_rel_seq { + return Err(TcpSegmentDescription::HandshakeFail("ack number is wrong".to_string())); + } + + src.isn = seq; + src.next_rel_seq = Wrapping(1); + dst.ian = seq; + + Ok(()) + } + + fn update_after_handshake(&mut self, + tcp: TcpPacket, + to_server: bool) -> (Option<Vec<TcpSegment>>, TcpSegmentDescription) { + let (origin, destination) = if to_server { + (&mut self.client, &mut self.server) + } else { + (&mut self.server, &mut self.client) + }; + + let rel_seq = Wrapping(tcp.get_sequence()) - origin.isn; + let rel_ack = Wrapping(tcp.get_acknowledgement()) - destination.isn; + let is_fin = tcp.has_flag(TcpFlags::FIN) || tcp.has_flag(TcpFlags::RST); // before borrowing tcp + + println!("update_after_handshake: payload len={}", tcp.payload().len()); + println!( + " Tcp rel seq {} ack {} next seq {}", + rel_seq, + rel_ack, + origin.next_rel_seq + ); + + let segment = TcpSegment { + rel_seq, + rel_ack, + payload: tcp.payload().to_vec(), // XXX data cloned here + tcp_header: tcp.raw_packet.header(), + raw_packet: tcp.raw_packet, + }; + queue_segment(origin, segment); + if is_fin { + // fin packet can also have payload, so we queued it first. Refer to: + // https://stackoverflow.com/questions/8702646/can-a-tcp-packet-with-the-fin-flag-also-have-data + let sent_pkt = flush_peer_segments(origin); + return (Some(sent_pkt), TcpSegmentDescription::FinTrigger); + } + // todo: closed connection restart + + let sent_pkt = send_peer_segments(origin); + if origin.segments.len() > DEFAULT_MAX_PACKETS { + let sent_pkt = flush_peer_segments(origin); + return (Some(sent_pkt), TcpSegmentDescription::TooManyPacket); + } + + if sent_pkt.is_err() { + return (None, sent_pkt.unwrap_err()); + } else { + return (Some(sent_pkt.unwrap()), TcpSegmentDescription::Normal); + } + } +} + +fn queue_segment(peer: &mut TcpPeer, segment: TcpSegment) { + if segment.payload.is_empty() { + return; + } + //todo: 老代码有一个 EARLY_DETECT_OVERLAP 不知道干嘛的 + + if peer.segments.is_empty() { + println!("Pushing segment (front)"); + peer.segments.push_front(segment); + return; + } + + println!("Adding segment"); + peer.insert_sorted(segment); +} + +// let the peer send segments in its queue, update ack numbers, and pop segments that were sent +fn send_peer_segments(peer: &mut TcpPeer) -> Result<Vec<TcpSegment>, TcpSegmentDescription> { + if peer.segments.is_empty() { + println!("No segment to send"); + return Err(TcpSegmentDescription::NoSegment); + } + let mut ret = Vec::new(); + let mut description = TcpSegmentDescription::Normal; + while !peer.segments.is_empty() { + let segment = &peer.segments[0]; + println!("send segment, payload: {:?}", segment.payload); + + if segment.rel_seq > peer.next_rel_seq { // there is a gap + println!("Gap detected"); + description = TcpSegmentDescription::Unordered; + break; + } + + if segment.rel_seq < peer.next_rel_seq { // caused by flush_peer_segments, or duplicate pkt, omit old segments + // todo: 感觉这里最好区别一下是不是因为flush_peer_segments导致的,虽然只影响错误码 + // 甚至会是over lap 导致的 + println!("Dropping segment"); + if (segment.rel_seq + Wrapping(segment.payload.len() as u32)) > peer.next_rel_seq { + println!("Segment overlaps next, payload before: {:?}", segment.payload); + let mut segment = peer.segments.pop_front().unwrap(); + let overlap_offset = (peer.next_rel_seq - segment.rel_seq).0; + segment.payload = segment.payload.split_off(overlap_offset as usize); + println!("Segment overlaps next, payload after: {:?}", segment.payload); + segment.rel_seq = peer.next_rel_seq; + peer.segments.push_front(segment); + assert!(!peer.segments.is_empty()); + } else if (segment.rel_seq + Wrapping(segment.payload.len() as u32)) == peer.next_rel_seq { + println!("Segment ends at next"); + peer.segments.pop_front(); + description = TcpSegmentDescription::DuplicateSeq; + } else { + peer.segments.pop_front(); + description = TcpSegmentDescription::OldPacket; + println!("Segment ends before next"); + } + continue; + } + + // safety: segments is just tested above + let mut segment = peer.segments.pop_front().unwrap(); + + remove_overlapped(peer, &mut segment); + adjust_seq_numbers(peer, &segment); + println!("Sending segment, payload: {:?}", segment.payload); + segment.raw_packet.replace_payload(segment.payload.clone()); + ret.push(segment); + } + println!("ret len: {}", ret.len()); + if ret.len() == 0 { + return Err(description); + } + + Ok(ret) +} + +fn flush_peer_segments(peer: &mut TcpPeer) -> Vec<TcpSegment> { + // 最终预期: + // 1. 队列全清空 + // 2. next seq 正常调整 + + // // 之后呢? + // 标记该Session为满释放异常,并声明一个新的变量,为“上次flush的时候,最大的rel seq” + // 之后,如果有新的segment进来,那么就判断,如果rel seq < 上次flush的最大rel seq,那么直接丢弃 + // 否则,就正常处理,放入队列中。 + + let mut ret = Vec::new(); + while !peer.segments.is_empty() { + // safety: segments is just tested above + let mut segment = peer.segments.pop_front().unwrap(); + + remove_overlapped(peer, &mut segment); + if peer.segments.len() == 0 { // the last one has the biggest rel seq + peer.next_rel_seq = segment.rel_seq + Wrapping(segment.payload.len() as u32); + } + + ret.push(segment); + } + + ret +} + + // 情况1: [1,2,3] [4,5,6] + // [3, 4,5] + // 2: [1,2,3] + // [1,2,3] + // 3: [4,5,6] + // [4,5,6] + // 以上三种均为duplicate,直接丢弃 + // 4: [1,2,3] + // [1,2,3,4] + // 保留[1,2,3] [4] + // 5: [2,3] [6,7] + // [1,2,3,4,5,6] + // 保留[1,2,3,4,5,6] [7] +fn remove_overlapped(peer: &mut TcpPeer, segment: &mut TcpSegment) { + // loop while segment has overlap + while let Some(next) = peer.segments.front() { + if let Some(overlap_offset) = segment.overlap_offset(next) { + println!( + "overlaps next candidate (at offset={})", + overlap_offset + ); + // we will modify the subsequent segment (next) + // safety: element presence was tested in outer loop + let next = peer.segments.pop_front().unwrap(); + + // split next + let overlap_size = segment.payload.len() - overlap_offset; + let min_overlap_size = std::cmp::min(overlap_size, next.payload.len()); + // compare overlap area + if next.payload[..min_overlap_size] + != segment.payload[overlap_offset..overlap_offset + min_overlap_size] + { + println!("Overlap area differs!"); + } + if overlap_size >= next.payload.len() { + // subsequent segment starts after and is smaller, so drop it + drop(next); + continue; + } + // otherwise, split next into left and right, drop left and accept right + let mut left = next; + let right = left.split_off(overlap_size); + // to accept right, merge it into segment + segment.payload.extend_from_slice(&right.payload); + } else { + // println!("no overlap, break"); + break; + } + } +} + +fn adjust_seq_numbers(origin: &mut TcpPeer, segment: &TcpSegment) { + if !segment.payload.is_empty() { + // adding length is wrong in case of overlap + // origin.next_rel_seq += Wrapping(segment.payload.len() as u32); + origin.next_rel_seq = segment.rel_seq + Wrapping(segment.payload.len() as u32); + } + + if segment.tcp_header.flag_fin { + // println!("Segment has FIN"); + origin.next_rel_seq += Wrapping(1); + } +} + +impl TcpConnection { + pub(crate) fn try_new(packet: &RawPacket) -> Result<Self, TcpSegmentDescription> { + let simple_packet = raw_packet_convert_to_my_packet(packet)?; + Self::_try_new(simple_packet) + } + + pub(crate) fn update(&mut self, packet: &RawPacket) -> (Option<Vec<CopiedRawPacket>>, TcpSegmentDescription) { + let simple_packet = raw_packet_convert_to_my_packet(packet); + if let Err(e) = simple_packet { + return (None, e); + } + self._update(simple_packet.unwrap()) + } + + fn _try_new(packet: TcpPacket) -> Result<Self, TcpSegmentDescription> { + let mut connection = TcpConnection { + stream: TcpStream::new(&packet), + max_packets: DEFAULT_MAX_PACKETS, + }; + + if !packet.has_flag(TcpFlags::SYN) { + return Err(TcpSegmentDescription::HandshakeFail("Not a SYN".to_string())); + } + if packet.has_flag(TcpFlags::ACK) { + println!("First packet is SYN+ACK"); + return Err(TcpSegmentDescription::HandshakeFail("First packet is SYN+ACK".to_string())); + } + if packet.has_flag(TcpFlags::RST) { + return Err(TcpSegmentDescription::HandshakeFail("First packet is RST".to_string())); + } + if packet.has_flag(TcpFlags::FIN) { + return Err(TcpSegmentDescription::HandshakeFail("First packet is FIN".to_string())); + } + + connection.stream.handle_synsent(packet); + Ok(connection) + } + + fn _update(&mut self, tcp: TcpPacket) -> (Option<Vec<CopiedRawPacket>>, TcpSegmentDescription) { + let stream = &mut self.stream; + + + // get origin and destination + let to_server = tcp.dst_ip == stream.server.addr && + tcp.dst_port == stream.server.port; + println!("to_server: {}", to_server); + + if self.stream.in_connection { + let ret = self.stream.handle_synrcv(tcp); + if let Err(e) = ret { + return (None, e); + } + + self.stream.in_connection = false; + return (None, TcpSegmentDescription::SynAckOk); + } + let (segments, ret) = self.stream.update_after_handshake(tcp, to_server); + + if segments.is_none() { + return (None, ret); + } + + let ret_packet = segments.unwrap().into_iter(). + map(|segment| {segment.raw_packet}).collect(); + + return (Some(ret_packet), ret); + } +} + + +#[cfg(test)] +mod tests { + use std::vec; + use crate::protocol::ip::IPProtocol; + + use super::*; + + static SLICE_DUMMY:&[u8] = &[42,42,42]; + + #[derive(Debug, Clone)] + enum PeerRole { + Client, + Server, + } + #[derive(Debug, Clone)] + struct PeerInTest { + addr: Ipv4Addr, + /// println: port + port: u16, + role: PeerRole, + } + + fn new_raw<'a>(from: &PeerInTest, to: &PeerInTest, seq_num: u32, ack_num: u32, + has_ack: bool, has_syn: bool, has_rst: bool, has_fin: bool, segment: &'a [u8]) + -> RawPacket<'a> { + let src_ip = from.addr; + let dst_ip = to.addr; + let header = TcpHeader { + source_port: from.port, + dest_port: to.port, + seq_num, + ack_num, + data_offset: 0, + reserved: 0, + flag_urg: false, + flag_ack: has_ack, + flag_psh: false, + flag_rst: has_rst, + flag_syn: has_syn, + flag_fin: has_fin, + window: 65535, + checksum: 0, + urgent_ptr: 0, + options: None, + }; + + let ip_header = IPv4Header { + version: 4, + ihl: 5, + tos: 0, + length: 0, + id: 0, + flags: 0, + frag_offset: 0, + ttl: 0, + protocol: IPProtocol::TCP, + checksum: 0, + source_address: src_ip, + dest_address: dst_ip, + }; + + let encap1 : Encapsulation = Encapsulation::L3_IP4(ip_header, SLICE_DUMMY); + let encap2 : Encapsulation = Encapsulation::L4_TCP(header, segment); + let encap_vec = vec![encap1, encap2]; + + RawPacket { + orig_data: SLICE_DUMMY, + orig_len: SLICE_DUMMY.len() as u32, + encapsulation: encap_vec, + } + } + + const CLIENT: PeerInTest = PeerInTest { + addr: Ipv4Addr::new(192, 168, 1, 1), + port: 1234, + role: PeerRole::Client, + }; + const SERVER: PeerInTest = PeerInTest { + addr: Ipv4Addr::new(192, 168, 1, 2), + port: 80, + role: PeerRole::Server, + }; + + #[test] + fn single_segment_ping_pong() { + const INIT_SEQ:u32 = 12345; + let packet_handshake1 = new_raw(&CLIENT, &SERVER, INIT_SEQ + 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, INIT_SEQ+1, true, true, false, false, &[]); + let ret = connection.update(&packet_handshake2); + assert!(ret.1 == TcpSegmentDescription::SynAckOk); + + let packet_established_from_client = new_raw(&CLIENT, &SERVER, INIT_SEQ+1, 1, true, false, false, false, &[1, 2, 3]); + let ret = connection.update(&packet_established_from_client); + println!("ret: {:?}", ret); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.unwrap()[0].payload() == &[1, 2, 3]); + + let packet_established_from_server = new_raw(&SERVER, &CLIENT, 1, INIT_SEQ+4, true, false, false, false, &[4, 5, 6]); + let ret = connection.update(&packet_established_from_server); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.unwrap()[0].payload() == &[4, 5, 6]); + + let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, INIT_SEQ+4, 4, true, false, false, false, &[7, 8, 9]); + let ret = connection.update(&packet_established_from_client2); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.unwrap()[0].payload() == &[7, 8, 9]); + } + + #[test] + fn several_ordered_consecutive_segments() { + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1, 2, 3]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.unwrap()[0].payload() == &[1, 2, 3]); + let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 4, 1, true, false, false, false, &[4, 5, 6]); + let ret = connection.update(&packet_established_from_client2); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.unwrap()[0].payload() == &[4, 5, 6]); + let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 7, 1, true, false, false, false, &[7, 8, 9]); + let ret = connection.update(&packet_established_from_client3); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.unwrap()[0].payload() == &[7, 8, 9]); + } + + #[test] + fn several_unordered_consecutive_segments() { + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 4, 1, true, false, false, false, &[4, 5, 6]); + let ret = connection.update(&packet_established_from_client2); + assert!(ret.1 == TcpSegmentDescription::Unordered); + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1, 2, 3]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[1, 2, 3]); + assert!(ret.0.unwrap()[1].payload() == &[4, 5, 6]); + let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 7, 1, true, false, false, false, &[7, 8, 9]); + let ret = connection.update(&packet_established_from_client3); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.unwrap()[0].payload() == &[7, 8, 9]); + } + + #[test] + fn several_unordered_inconsecutive_segments() { + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 4, 1, true, false, false, false, &[4, 5, 6]); + let ret = connection.update(&packet_established_from_client2); + println!("ret: {:?}", ret); + assert!(ret.1 == TcpSegmentDescription::Unordered); + let packet_from_server = new_raw(&SERVER, &CLIENT, 1, 1, true, false, false, false, &[11, 12, 13]); + let ret = connection.update(&packet_from_server); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[11, 12, 13]); + + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1, 2, 3]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[1, 2, 3]); + assert!(ret.0.unwrap()[1].payload() == &[4, 5, 6]); + let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 7, 1, true, false, false, false, &[7, 8, 9]); + let ret = connection.update(&packet_established_from_client3); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.unwrap()[0].payload() == &[7, 8, 9]); + } + + #[test] + fn duplicate_packet() { + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1, 2, 3]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[1, 2, 3]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::DuplicateSeq); + assert!(ret.0.is_none()); + } + + #[test] + fn too_many_packet() { + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + // let first packet drop , so that the queue will be filled until full + for i in 1..DEFAULT_MAX_PACKETS + 1{ + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1 + i as u32, 1, true, false, false, false, &[1]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::Unordered); + } + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1 + DEFAULT_MAX_PACKETS as u32, 1, true, false, false, false, &[1]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::TooManyPacket); + assert!(ret.0.unwrap().len() == DEFAULT_MAX_PACKETS); + + // the first packet come unexpectedly, just throw it away + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::OldPacket); + assert!(ret.0.is_none()); + + // continue to send + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 2 + DEFAULT_MAX_PACKETS as u32, 1, true, false, false, false, &[2,3,4]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.unwrap()[0].payload() == &[2,3,4]); + } + + #[test] + fn segment_in_syn() { + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[1,2,3]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 4, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 4, 1, true, false, false, false, &[4,5,6]); + let ret = connection.update(&packet_established_from_client); + println!("ret: {:?}", ret); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[1,2,3]); + assert!(ret.0.as_ref().unwrap()[1].payload() == &[4,5,6]); + } + + #[test] + fn wrong_flag_during_handshake_syn() { + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, false, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1); + assert!(connection.is_err()); + assert!(connection.unwrap_err() == TcpSegmentDescription::HandshakeFail("Not a SYN".to_string())); + + + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, true, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1); + assert!(connection.is_err()); + assert!(connection.unwrap_err() == TcpSegmentDescription::HandshakeFail("First packet is RST".to_string())); + } + + #[test] + fn wrong_flag_during_handshake_acksyn() { + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[1,2,3]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 3, true, true, false, false, &[]); // expected ack num is 4 + let ret = connection.update(&packet_handshake2); + assert!(ret.1 == TcpSegmentDescription::HandshakeFail("ack number is wrong".to_string())); + + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 4, false, true, false, false, &[]); // no ack + let ret = connection.update(&packet_handshake2); + assert!(ret.1 == TcpSegmentDescription::HandshakeFail("Not a SYN + ACK".to_string())); + } + + #[test] + fn not_tcp_ip_packet() { + let mut packet = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + packet.encapsulation.pop(); + let mut connection = TcpConnection::try_new(&packet); + assert!(connection.is_err()); + assert!(connection.unwrap_err() == TcpSegmentDescription::NotIp4Tcp); + } + + #[test] + fn fin_with_data() { + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 2, 1, true, false, false, false, &[2,3]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::Unordered); + + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 4, 1, true, false, false, true, &[4,5,6]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::FinTrigger); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[2,3]); + assert!(ret.0.as_ref().unwrap()[1].payload() == &[4,5,6]); + } + + #[test] + fn overlap_partially_sent_before() { + // [1,2,3] -> sent + // [3,4,5,6] -> [4,5,6] + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1,2,3]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[1,2,3]); + + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 3, 1, true, false, false, false, &[3,4,5,6]); + let ret = connection.update(&packet_established_from_client); + println!("ret: {:?}", ret.0.as_ref().unwrap()[0].payload()); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[4,5,6]); // [3] overlap, only send [4,5,6] + } + + #[test] + fn overlap_as_old_packet() { + // [1,2,3,4,5,6] -> sent + // [2,3,4] -> drop(description: old packet) + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1,2,3,4,5,6]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[1,2,3,4,5,6]); + + let packet_established_from_client = new_raw(&CLIENT, &SERVER, 2, 1, true, false, false, false, &[2,3,4]); + let ret = connection.update(&packet_established_from_client); + assert!(ret.1 == TcpSegmentDescription::OldPacket); + assert!(ret.0.is_none()); + } + + #[test] + fn overlap_change_next_one() { + // [2,3,4] -> wait + // [3,4,5] -> wait(join the first as [2,3,4,5]) + // [1] -> send [1] [2,3,4,5] + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 2, 1, true, false, false, false, &[2,3,4]); + let packet_established_from_client1 = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1]); + let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 3, 1, true, false, false, false, &[3,4,5]); + let ret = connection.update(&packet_established_from_client2); + assert!(ret.1 == TcpSegmentDescription::Unordered); + let ret = connection.update(&packet_established_from_client3); + assert!(ret.1 == TcpSegmentDescription::Unordered); + let ret = connection.update(&packet_established_from_client1); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.as_ref().unwrap().len() == 2); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[1]); + assert!(ret.0.as_ref().unwrap()[1].payload() == &[2,3,4,5]); + } + + #[test] + fn overlap_del_next_one() { + // [2,3,4,5] -> wait + // [3,4,5] -> del(overlapped) + // [1,2,3] -> send [1,2,3,4,5] + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 2, 1, true, false, false, false, &[2,3,4,5]); + let packet_established_from_client1 = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1,2,3]); + let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 3, 1, true, false, false, false, &[3,4,5]); + let ret = connection.update(&packet_established_from_client2); + assert!(ret.1 == TcpSegmentDescription::Unordered); + let ret = connection.update(&packet_established_from_client3); + assert!(ret.1 == TcpSegmentDescription::Unordered); + let ret = connection.update(&packet_established_from_client1); + assert!(ret.1 == TcpSegmentDescription::Normal); + println!("ret: {:?}", ret.0.as_ref().unwrap()); + + assert!(ret.0.as_ref().unwrap().len() == 1); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[1,2,3,4,5]); + } + + #[test] + fn overlap_surpass_all() { + // [2] -> wait + // [3] -> wait + // [1,2,3,4] -> send [1,2,3,4] + let packet_handshake1 = new_raw(&CLIENT, &SERVER, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::try_new(&packet_handshake1).unwrap(); + let packet_handshake2 = new_raw(&SERVER, &CLIENT, 0, 1, true, true, false, false, &[]); + connection.update(&packet_handshake2); + + let packet_established_from_client2 = new_raw(&CLIENT, &SERVER, 2, 1, true, false, false, false, &[2]); + let packet_established_from_client3 = new_raw(&CLIENT, &SERVER, 3, 1, true, false, false, false, &[3]); + let packet_established_from_client1 = new_raw(&CLIENT, &SERVER, 1, 1, true, false, false, false, &[1,2,3,4]); + let ret = connection.update(&packet_established_from_client3); + assert!(ret.1 == TcpSegmentDescription::Unordered); + let ret = connection.update(&packet_established_from_client2); + assert!(ret.1 == TcpSegmentDescription::Unordered); + let ret = connection.update(&packet_established_from_client1); + assert!(ret.1 == TcpSegmentDescription::Normal); + assert!(ret.0.as_ref().unwrap().len() == 1); + assert!(ret.0.as_ref().unwrap()[0].payload() == &[1,2,3,4]); + } + + + + + // todo: 回绕 +}
\ No newline at end of file |
