summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/c_lang/fs4.rs599
-rw-r--r--src/c_lang/fs4_binding.rs961
-rw-r--r--src/c_lang/mod.rs2
-rw-r--r--src/lib.rs4
-rw-r--r--src/session/tcp_reassembly.rs1190
-rw-r--r--src/session/tcp_reassembly_with_deque.rs1069
6 files changed, 2899 insertions, 926 deletions
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
diff --git a/src/lib.rs b/src/lib.rs
index 4321c02..13d5f0f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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