helper.rs 2.5 KB

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