use chrono::Utc; use std::collections::HashMap; /****************************************************************************** * Struct ******************************************************************************/ const MAX_SESSION_EXPIRE_TIME: i64 = 60; #[derive(Clone, Copy, Debug, PartialEq)] pub enum SessionDirection { C2S, S2C, } #[derive(Clone, Copy, Debug, PartialEq)] pub enum SessionProto { TCP, UDP, } #[derive(Clone, Copy, Debug, PartialEq)] pub enum SessionState { New, Active, Inactive, Expired, } #[derive(Debug)] pub struct SessionMetrics { pub send_pkts: u64, pub send_bytes: u64, pub recv_pkts: u64, pub recv_bytes: u64, } #[derive(Debug)] struct SessionTimeStamp { ts_start: i64, ts_end: i64, ts_expires: i64, ts_last: i64, } /****************************************************************************** * why no current packet in session? * - session lifetime is longer than packet lifetime * - if current packet is iterm of session, require packet lifetime > session lifetime ******************************************************************************/ #[derive(Debug)] pub struct Session { session_id: String, session_proto: SessionProto, session_state: SessionState, session_metrics_c2s: SessionMetrics, session_metrics_s2c: SessionMetrics, session_timestamp: SessionTimeStamp, session_exdata: HashMap, session_current_dir: SessionDirection, } /****************************************************************************** * API ******************************************************************************/ impl Session { pub fn new(session_id: String) -> Session { let timestamp = Utc::now().timestamp(); Session { session_id, session_proto: SessionProto::TCP, session_state: SessionState::New, session_metrics_c2s: SessionMetrics { send_pkts: 0, send_bytes: 0, recv_pkts: 0, recv_bytes: 0, }, session_metrics_s2c: SessionMetrics { send_pkts: 0, send_bytes: 0, recv_pkts: 0, recv_bytes: 0, }, session_timestamp: SessionTimeStamp { ts_start: timestamp, ts_end: 0, ts_expires: timestamp + MAX_SESSION_EXPIRE_TIME, ts_last: timestamp, }, session_exdata: HashMap::new(), session_current_dir: SessionDirection::C2S, } } pub fn get_session_id(&self) -> String { self.session_id.clone() } pub fn get_session_start_ts(&self) -> i64 { self.session_timestamp.ts_start } pub fn set_session_proto(&mut self, proto: SessionProto) { self.session_proto = proto; } pub fn get_session_proto(&self) -> SessionProto { self.session_proto } pub fn set_session_state(&mut self, state: SessionState) { self.session_state = state; } pub fn get_session_state(&self) -> SessionState { self.session_state } pub fn inc_session_c2s_metrics( &mut self, send_pkts: u64, send_bytes: u64, recv_pkts: u64, recv_bytes: u64, ) { self.session_metrics_c2s.send_pkts += send_pkts; self.session_metrics_c2s.send_bytes += send_bytes; self.session_metrics_c2s.recv_pkts += recv_pkts; self.session_metrics_c2s.recv_bytes += recv_bytes; } pub fn get_session_c2s_metrics(&self) -> &SessionMetrics { &self.session_metrics_c2s } pub fn inc_session_s2c_metrics( &mut self, send_pkts: u64, send_bytes: u64, recv_pkts: u64, recv_bytes: u64, ) { self.session_metrics_s2c.send_pkts += send_pkts; self.session_metrics_s2c.send_bytes += send_bytes; self.session_metrics_s2c.recv_pkts += recv_pkts; self.session_metrics_s2c.recv_bytes += recv_bytes; } pub fn get_session_s2c_metrics(&self) -> &SessionMetrics { &self.session_metrics_s2c } pub fn update_session_expire_ts(&mut self) { self.session_timestamp.ts_expires = Utc::now().timestamp() + MAX_SESSION_EXPIRE_TIME; } pub fn get_session_expire_ts(&self) -> i64 { self.session_timestamp.ts_expires } pub fn update_session_last_ts(&mut self) { self.session_timestamp.ts_last = Utc::now().timestamp(); } pub fn get_session_last_ts(&self) -> i64 { self.session_timestamp.ts_last } pub fn set_session_end_ts(&mut self, ts: i64) { self.session_timestamp.ts_end = ts; } pub fn get_session_end_ts(&self) -> i64 { self.session_timestamp.ts_end } pub fn set_session_exdata(&mut self, key: String, value: String) { self.session_exdata.insert(key, value); } pub fn get_session_exdata(&self, key: String) -> Option<&String> { self.session_exdata.get(&key) } pub fn update_session_current_dir(&mut self, dir: SessionDirection) { self.session_current_dir = dir; } pub fn get_session_current_dir(&self) -> SessionDirection { self.session_current_dir } } /****************************************************************************** * TEST ******************************************************************************/ #[cfg(test)] mod tests { use super::Session; #[test] fn test_session() { let mut session = Session::new("192.168.0.1:2345-192.168.0.2:80-1".to_string()); assert_eq!( session.get_session_id(), "192.168.0.1:2345-192.168.0.2:80-1" ); assert_eq!(session.get_session_state(), super::SessionState::New); assert_eq!(session.get_session_c2s_metrics().recv_bytes, 0); assert_eq!(session.get_session_c2s_metrics().recv_bytes, 0); assert_eq!(session.get_session_c2s_metrics().send_pkts, 0); assert_eq!(session.get_session_c2s_metrics().send_bytes, 0); assert_eq!(session.get_session_s2c_metrics().recv_bytes, 0); assert_eq!(session.get_session_s2c_metrics().recv_bytes, 0); assert_eq!(session.get_session_s2c_metrics().send_pkts, 0); assert_eq!(session.get_session_s2c_metrics().send_pkts, 0); assert_eq!( session.get_session_start_ts(), session.get_session_last_ts() ); assert_eq!( session.get_session_start_ts(), session.get_session_expire_ts() - 60 ); assert_eq!(session.get_session_end_ts(), 0); session.set_session_exdata("Hello".to_string(), "Word".to_string()); assert_eq!( session.get_session_exdata("Hello".to_string()), Some(&"Word".to_string()) ); assert_eq!( session.get_session_current_dir(), super::SessionDirection::C2S ); } }