Skip to main content

minecraft_pinger/bedrock/
pinger.rs

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