minecraft_pinger/bedrock/
pinger.rs1use crate::MinecraftPinger;
2use crate::bedrock::model::BedrockPing;
3use crate::bedrock::protocol::{create_ping, read_response};
4use crate::common::dns::resolve_filtered_addrs;
5use crate::config::PingConfig;
6use crate::error::PingError;
7use bytes::Bytes;
8use log::debug;
9use std::time::Instant;
10use tokio::net::UdpSocket;
11use tokio::time::timeout;
12
13impl MinecraftPinger {
14 pub async fn ping_bedrock_server(
15 &self,
16 ip: &str,
17 port: u16,
18 config: &PingConfig,
19 ) -> Result<BedrockPing, PingError> {
20 let rs = timeout(
21 config.timeout(),
22 self.ping_bedrock_server_internal(ip, port, config),
23 )
24 .await??;
25 Ok(rs)
26 }
27
28 async fn ping_bedrock_server_internal(
29 &self,
30 ip: &str,
31 port: u16,
32 config: &PingConfig,
33 ) -> Result<BedrockPing, PingError> {
34 debug!("Pinging bedrock server {}:{}", ip, port);
35
36 let (_, addrs) = resolve_filtered_addrs(self, ip, port, "udp", config.ip_filter()).await?;
37 let start_time = Instant::now();
38
39 let socket = UdpSocket::bind("0.0.0.0:0").await?;
40 timeout(config.timeout(), socket.connect(&addrs[..]))
41 .await?
42 .map_err(|e| {
43 debug!("Connection error: {}", e);
44 PingError::ConnectionRefused
45 })?;
46
47 let _ = socket.send(&create_ping()?).await;
48
49 let mut buffer = [0u8; 1024];
50 let len = timeout(config.timeout(), socket.recv(&mut buffer))
51 .await?
52 .map_err(|_| PingError::ConnectionRefused)?;
53
54 let connected_addr = socket.peer_addr().ok();
55
56 let mut response_bytes = Bytes::copy_from_slice(&buffer[..len]);
57 let latency = start_time.elapsed().as_millis() as u32;
58
59 let mut rs = read_response(&mut response_bytes)?;
60 rs.latency = latency;
61 rs.connected_addr = connected_addr;
62
63 Ok(rs)
64 }
65}