Skip to main content

minecraft_pinger/bedrock/
pinger.rs

1use 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}