tyr/util.rs
1use std::{net::Ipv4Addr, os::unix::process::ExitStatusExt};
2
3use pnet::datalink;
4
5use crate::error;
6
7/// Generates a random port number within the range of 1024 to 65535.
8///
9/// # Returns
10///
11/// A `u16` representing a random port number.
12pub fn get_random_port() -> u16 {
13 fastrand::u16(1024..65535)
14}
15
16/// Generates a random IPv4 address.
17///
18/// # Returns
19///
20/// An `Ipv4Addr` representing a random IPv4 address.
21pub fn get_random_ip() -> Ipv4Addr {
22 Ipv4Addr::new(
23 fastrand::u8(0..255),
24 fastrand::u8(0..255),
25 fastrand::u8(0..255),
26 fastrand::u8(0..255),
27 )
28}
29
30/// Retrieves a network interface by its name.
31///
32/// # Arguments
33///
34/// * `name` - A string slice that holds the name of the network interface.
35///
36/// # Returns
37///
38/// * `Option<datalink::NetworkInterface>` - An option containing the network interface if found, or None if not found.
39pub fn get_interface(name: &str) -> Option<datalink::NetworkInterface> {
40 datalink::interfaces()
41 .into_iter()
42 .find(|interface| interface.name == name)
43}
44
45/// Retrieves all network interfaces available on the system.
46///
47/// # Returns
48///
49/// * `Vec<datalink::NetworkInterface>` - A vector containing all network interfaces.
50pub fn get_interfaces() -> Vec<datalink::NetworkInterface> {
51 datalink::interfaces()
52}
53
54/// Retrieves the network interface with the default gateway.
55///
56/// # Returns
57///
58/// * `Option<datalink::NetworkInterface>` - An option containing the network interface with the default gateway if found, or None if not found.
59pub fn get_default_interface() -> Option<datalink::NetworkInterface> {
60 datalink::interfaces().into_iter().find(|interface| {
61 interface
62 .ips
63 .iter()
64 .any(|ip| ip.is_ipv4() && ip.ip().is_loopback())
65 })
66}
67
68#[inline(always)]
69/// Checks if the current user is the root user.
70///
71/// Returns `true` if the current user is the root user, `false` otherwise.
72fn is_root() -> bool {
73 nix::unistd::Uid::current().is_root()
74}
75
76/// If the current user is not the root user, reruns the current program using sudo.
77///
78/// Returns `Ok(())` if the program was successfully rerun with sudo, or an `Err` if the rerun failed.
79pub fn rerun_if_not_root() -> crate::Result<()> {
80 if !is_root() {
81 let args: Vec<String> = std::env::args().collect();
82 let program = &args[0];
83 let rest_args = &args[1..];
84
85 let status = std::process::Command::new("sudo")
86 .arg(program)
87 .args(rest_args)
88 .status()?;
89
90 if !status.success() {
91 match status.signal() {
92 Some(nix::libc::SIGINT) => {
93 std::process::exit(130);
94 }
95 Some(signal) => {
96 return Err(error::Error::OsError(std::io::Error::new(
97 std::io::ErrorKind::PermissionDenied,
98 format!("Failed to grant root privileges: signal {}", signal),
99 )));
100 }
101 _ => {
102 return Err(error::Error::OsError(std::io::Error::new(
103 std::io::ErrorKind::PermissionDenied,
104 "Failed to grant root privileges",
105 )));
106 }
107 }
108 }
109 }
110 Ok(())
111}
112
113/// Calculates the number of threads to use based on the rated power.
114///
115/// The rated power is a value from 1 to 4, which mean use a fraction
116/// of the available threads.
117///
118/// # Arguments
119///
120/// * `rated_power` - The rated power value.
121///
122/// # Returns
123///
124/// The number of threads to use.
125///
126/// # Errors
127///
128/// Returns an error if the system fails to determine the available parallelism.
129///
130/// # Panics
131///
132/// Panics if the rated power is not in the range 1 to 4.
133///
134/// # Warning
135///
136/// 0 is also a legal power rating parameter. Using the zero rated power will
137/// put the unit into a full load condition, which will definitely affect the
138/// normal operation of the unit and may even cause unknown consequences.
139///
140/// **USE AT YOUR OWN RISK!**
141pub fn get_num_threads(rated_power: u8) -> crate::Result<usize> {
142 let available_parallelism = std::thread::available_parallelism()?.get();
143 Ok(match rated_power {
144 0 => available_parallelism,
145 1 => available_parallelism / 10,
146 2 => available_parallelism / 5,
147 3 => available_parallelism / 2,
148 4 => available_parallelism * 3 / 4,
149 _ => panic!(
150 "Invalid rated power {}, available ratings are 1 to 4",
151 rated_power
152 ),
153 })
154}