1use num_cpus;
2use pnet::datalink::MacAddr;
3use rand::Rng;
4use std::net::IpAddr;
5use std::net::Ipv4Addr;
6use std::net::Ipv6Addr;
7use std::time::Duration;
8use threadpool::ThreadPool;
9use tracing::warn;
10
11use crate::DEFAULT_TIMEOUT;
12use crate::SYSTEM_NET_CACHE;
13use crate::error::PistolError;
14
15const MAX_THREADS: usize = 1000;
16
17pub fn time_sec_to_string(cost: Duration) -> String {
18 if cost.as_secs_f64() > 1.0 {
19 format!("{:.3}s", cost.as_secs_f64())
20 } else {
21 format!("{:.3} ms", cost.as_secs_f64() * 1000.0)
22 }
23}
24
25pub fn num_threads_check(num_threads: usize) -> usize {
26 let mut num_threads = num_threads;
27 if num_threads > MAX_THREADS {
28 warn!(
29 "system try to create too many threads (current threads num: {}, fixed threads num: {}))",
30 num_threads, MAX_THREADS
31 );
32 num_threads = MAX_THREADS;
33 }
34 num_threads
35}
36
37pub fn neigh_cache_update(addr: IpAddr, mac: MacAddr) -> Result<(), PistolError> {
38 let mut snc = match SYSTEM_NET_CACHE.lock() {
40 Ok(snc) => snc,
41 Err(e) => {
42 return Err(PistolError::TryLockGlobalVarFailed {
43 var_name: String::from("SYSTEM_NET_CACHE"),
44 e: e.to_string(),
45 });
46 }
47 };
48 Ok(snc.update_neighbor_cache(addr, mac))
49}
50
51pub fn random_port() -> u16 {
53 let mut rng = rand::rng();
54 rng.random_range(10000..=65535)
55}
56
57pub fn random_ipv4_addr() -> Ipv4Addr {
59 let mut rng = rand::rng();
60 let x0 = rng.random_range(0..=255);
61 let x1 = rng.random_range(0..=255);
62 let x2 = rng.random_range(0..=255);
63 let x3 = rng.random_range(0..=255);
64 Ipv4Addr::new(x0, x1, x2, x3)
65}
66
67pub fn random_ipv6_addr() -> Ipv6Addr {
69 let mut rng = rand::rng();
70 let x0 = rng.random_range(0..=65535);
71 let x1 = rng.random_range(0..=65535);
72 let x2 = rng.random_range(0..=65535);
73 let x3 = rng.random_range(0..=65535);
74 let x4 = rng.random_range(0..=65535);
75 let x5 = rng.random_range(0..=65535);
76 let x6 = rng.random_range(0..=65535);
77 let x7 = rng.random_range(0..=65535);
78 Ipv6Addr::new(x0, x1, x2, x3, x4, x5, x6, x7)
79}
80
81pub fn random_port_range(start: u16, end: u16) -> u16 {
83 let mut rng = rand::rng();
84 rng.random_range(start..=end)
85}
86
87pub fn get_cpu_num() -> usize {
89 num_cpus::get()
90}
91
92pub fn get_threads_pool(num_threads: usize) -> ThreadPool {
93 let pool = if num_threads > 0 {
94 ThreadPool::new(num_threads)
95 } else {
96 let cpus = get_cpu_num();
97 ThreadPool::new(cpus)
98 };
99 pool
100}
101
102pub fn get_default_timeout() -> Duration {
103 Duration::from_secs_f64(DEFAULT_TIMEOUT)
104}
105
106pub struct PistolHex {
107 pub hex: String, }
109
110impl PistolHex {
111 pub fn new_hex(hex_str: &str) -> PistolHex {
112 let hex_str_len = hex_str.len();
113 let after_fix = if hex_str_len % 2 == 1 {
114 format!("0{}", hex_str)
115 } else {
116 hex_str.to_string()
117 };
118 PistolHex { hex: after_fix }
119 }
120 pub fn be_vec_to_u32(input: &[u8]) -> Result<u32, PistolError> {
121 if input.len() <= 4 {
122 let padding_size = 4 - input.len();
123 let mut after_padding = vec![0; padding_size];
124 for &i in input {
125 after_padding.push(i as u32);
126 }
127 let a = after_padding[0] << 24;
128 let b = after_padding[1] << 16;
129 let c = after_padding[2] << 8;
130 let d = after_padding[3];
131 Ok(a + b + c + d)
132 } else {
133 let v = format!("{:?}", input);
134 Err(PistolError::InputTooLoog { v })
135 }
136 }
137 pub fn decode_as_u32(&self) -> Result<u32, PistolError> {
138 match hex::decode(&self.hex) {
139 Ok(d) => Self::be_vec_to_u32(&d),
140 Err(e) => Err(e.into()),
141 }
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148 use pnet::datalink::interfaces;
149 #[test]
150 fn test_convert() {
151 let v: Vec<u8> = vec![1, 1, 1, 1];
152 let r = PistolHex::be_vec_to_u32(&v).unwrap();
153 assert_eq!(r, 16843009);
154
155 let s = "51E80C";
156 let h = PistolHex::new_hex(s);
157 let r = h.decode_as_u32().unwrap();
158 assert_eq!(r, 5367820);
159
160 let s = "1C";
161 let h = PistolHex::new_hex(s);
162 let r = h.decode_as_u32().unwrap();
163 assert_eq!(r, 28);
164
165 let s = "A";
166 let h = PistolHex::new_hex(s);
167 let r = h.decode_as_u32().unwrap();
168 assert_eq!(r, 10);
169 }
170 #[test]
171 fn test_get_cpus() {
172 let cpus = get_cpu_num();
173 println!("{}", cpus);
174 }
175 #[test]
176 fn interface_loopback() {
177 for interface in interfaces() {
178 if interface.is_loopback() {
179 println!("{} is loopback interface", interface);
180 }
181 }
182 }
183 #[test]
184 fn interface_list() {
185 for interface in interfaces() {
186 println!("list interface: {}, {:?}", interface.name, interface.ips);
187 }
188 }
189}