rust_mc_status/protocol/
bedrock.rs1use std::time::{Duration, SystemTime};
32
33use tokio::net::UdpSocket;
34use tokio::time::timeout;
35
36use crate::error::McError;
37use crate::models::{BedrockStatus, PingResult, ServerData};
38use crate::proxy::ProxyConfig;
39#[cfg(feature = "proxy")]
40use crate::proxy::UdpSupport;
41use super::{PingProtocol, ResolvedTarget};
42use crate::core::time::{start_timer, elapsed_ms};
43
44const READ_BUFFER_SIZE: usize = 4096;
45const BEDROCK_PING_PACKET_SIZE: usize = 35;
46const BEDROCK_MIN_RESPONSE_SIZE: usize = 35;
47
48#[derive(Debug, Clone, Copy, Default)]
54pub struct BedrockProtocol;
55
56impl PingProtocol for BedrockProtocol {
57 fn name(&self) -> &'static str { "bedrock" }
58
59 async fn ping(
60 &self,
61 target: &ResolvedTarget,
62 tout: Duration,
63 proxy: Option<&ProxyConfig>,
64 ) -> Result<PingResult, McError> {
65 #[cfg(feature = "proxy")]
67 if let Some(cfg) = proxy
68 && cfg.udp_support() != UdpSupport::Yes {
69 return Err(McError::proxy_udp_unsupported(cfg.addr().to_string()));
70 }
71 let _ = proxy; let start = start_timer();
74 let socket = UdpSocket::bind("0.0.0.0:0").await.map_err(McError::Io)?;
75
76 timeout(tout, socket.send_to(&build_ping(), target.addr))
77 .await
78 .map_err(|_| McError::timeout())?
79 .map_err(McError::Io)?;
80
81 let mut buf = [0u8; READ_BUFFER_SIZE];
82 let (len, _) = timeout(tout, socket.recv_from(&mut buf))
83 .await
84 .map_err(|_| McError::timeout())?
85 .map_err(McError::Io)?;
86
87 if len < BEDROCK_MIN_RESPONSE_SIZE {
88 return Err(McError::invalid_response("response too short"));
89 }
90
91 let latency = elapsed_ms(start);
92 let pong = String::from_utf8(buf[BEDROCK_PING_PACKET_SIZE..len].to_vec())
93 .unwrap_or_else(|e| String::from_utf8_lossy(e.as_bytes()).into_owned());
94
95 Ok(PingResult::new(ServerData::Bedrock(BedrockStatus::parse(&pong)?), latency))
96 }
97}
98
99fn build_ping() -> Vec<u8> {
102 let mut p = Vec::with_capacity(BEDROCK_PING_PACKET_SIZE);
103 p.push(0x01);
104 let ts = SystemTime::now()
105 .duration_since(SystemTime::UNIX_EPOCH)
106 .unwrap_or_default()
107 .as_millis() as u64;
108 p.extend_from_slice(&ts.to_be_bytes());
109 p.extend_from_slice(&[
110 0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE,
111 0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78,
112 ]);
113 p.extend_from_slice(&[0u8; 8]);
114 p
115}
116
117