helper.rs 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. use std::{
  2. collections::hash_map::DefaultHasher,
  3. hash::{Hash, Hasher},
  4. net::SocketAddr,
  5. time::Duration,
  6. };
  7. use anyhow::{Context, Result};
  8. use socket2::{SockRef, TcpKeepalive};
  9. use tokio::net::{TcpStream, ToSocketAddrs, UdpSocket};
  10. use tracing::error;
  11. // Tokio hesitates to expose this option...So we have to do it on our own :(
  12. // The good news is that using socket2 it can be easily done, without losing portablity.
  13. // See https://github.com/tokio-rs/tokio/issues/3082
  14. pub fn try_set_tcp_keepalive(conn: &TcpStream) -> Result<()> {
  15. let s = SockRef::from(conn);
  16. let keepalive = TcpKeepalive::new().with_time(Duration::from_secs(60));
  17. s.set_tcp_keepalive(&keepalive)
  18. .with_context(|| "Failed to set keepalive")
  19. }
  20. pub fn set_tcp_keepalive(conn: &TcpStream) {
  21. if let Err(e) = try_set_tcp_keepalive(conn) {
  22. error!(
  23. "Failed to set TCP keepalive. The connection maybe unstable: {:?}",
  24. e
  25. );
  26. }
  27. }
  28. #[allow(dead_code)]
  29. pub fn feature_not_compile(feature: &str) -> ! {
  30. panic!(
  31. "The feature '{}' is not compiled in this binary. Please re-compile rathole",
  32. feature
  33. )
  34. }
  35. /// Create a UDP socket and connect to `addr`
  36. pub async fn udp_connect<A: ToSocketAddrs>(addr: A) -> Result<UdpSocket> {
  37. // FIXME: This only works for IPv4
  38. let s = UdpSocket::bind("0.0.0.0:0").await?;
  39. s.connect(addr).await?;
  40. Ok(s)
  41. }
  42. #[allow(dead_code)]
  43. pub fn hash_socket_addr(a: &SocketAddr) -> u64 {
  44. let mut hasher = DefaultHasher::new();
  45. a.hash(&mut hasher);
  46. hasher.finish()
  47. }
  48. // Wait for the stablization of https://doc.rust-lang.org/std/primitive.i64.html#method.log2
  49. #[allow(dead_code)]
  50. fn log2_floor(x: usize) -> u8 {
  51. (x as f64).log2().floor() as u8
  52. }
  53. #[allow(dead_code)]
  54. pub fn floor_to_pow_of_2(x: usize) -> usize {
  55. if x == 1 {
  56. return 1;
  57. }
  58. let w = log2_floor(x);
  59. 1 << w
  60. }
  61. #[cfg(test)]
  62. mod test {
  63. use crate::helper::{floor_to_pow_of_2, log2_floor};
  64. #[test]
  65. fn test_log2_floor() {
  66. let t = [
  67. (2, 1),
  68. (3, 1),
  69. (4, 2),
  70. (8, 3),
  71. (9, 3),
  72. (15, 3),
  73. (16, 4),
  74. (1023, 9),
  75. (1024, 10),
  76. (2000, 10),
  77. (2048, 11),
  78. ];
  79. for t in t {
  80. assert_eq!(log2_floor(t.0), t.1);
  81. }
  82. }
  83. #[test]
  84. fn test_floor_to_pow_of_2() {
  85. let t = [
  86. (1 as usize, 1 as usize),
  87. (2, 2),
  88. (3, 2),
  89. (4, 4),
  90. (5, 4),
  91. (15, 8),
  92. (31, 16),
  93. (33, 32),
  94. (1000, 512),
  95. (1500, 1024),
  96. (2300, 2048),
  97. ];
  98. for t in t {
  99. assert_eq!(floor_to_pow_of_2(t.0), t.1);
  100. }
  101. }
  102. }