Skip to main content

minecraft_pinger/java/
pinger.rs

1use crate::MinecraftPinger;
2use crate::common::dns::resolve_filtered_addrs;
3use crate::common::protocol::read_string;
4use crate::error::PingError;
5use crate::java::config::JavaPingConfig;
6use crate::java::model::JavaPing;
7use crate::java::protocol::{read_packet, write_ping_handshake, write_ping_request};
8use bytes::BytesMut;
9use log::debug;
10use std::time::Instant;
11use tokio::io::{AsyncWriteExt, BufReader};
12use tokio::net::TcpStream;
13use tokio::time::timeout;
14
15impl MinecraftPinger {
16    pub async fn ping_java_server(
17        &self,
18        ip: &str,
19        port: u16,
20        config: &JavaPingConfig,
21    ) -> Result<JavaPing, PingError> {
22        let rs = timeout(
23            config.common().timeout(),
24            self.ping_java_server_internal(ip, port, config),
25        )
26        .await??;
27        Ok(rs)
28    }
29
30    async fn ping_java_server_internal(
31        &self,
32        ip: &str,
33        port: u16,
34        config: &JavaPingConfig,
35    ) -> Result<JavaPing, PingError> {
36        debug!("Pinging server {}:{}", ip, port);
37
38        let (hostname, addrs) =
39            resolve_filtered_addrs(self, ip, port, "tcp", config.common().ip_filter()).await?;
40
41        let stream_future = TcpStream::connect(&addrs[..]);
42        let mut stream = timeout(config.common().timeout(), stream_future)
43            .await?
44            .map_err(|e| {
45                debug!("Connection error: {}", e);
46                PingError::ConnectionRefused
47            })?;
48
49        stream.set_nodelay(true).unwrap_or_default();
50
51        debug!(
52            "Stream connected to {}",
53            stream
54                .peer_addr()
55                .map(|a| a.to_string())
56                .unwrap_or_else(|_| "unknown".to_string())
57        );
58
59        let start_time = Instant::now();
60
61        let mut buffer = BytesMut::with_capacity(256);
62
63        let classic_hostname = hostname.as_deref().unwrap_or(ip);
64
65        let handshake_host = config.hostname().as_deref().unwrap_or(classic_hostname);
66        write_ping_handshake(
67            &mut buffer,
68            handshake_host,
69            &port,
70            &config.protocol_version(),
71        );
72        write_ping_request(&mut buffer);
73
74        stream
75            .write_all(&buffer.freeze())
76            .await
77            .map_err(|_| PingError::SendPacket)?;
78        debug!("Stream all packets !");
79
80        let connected_addr = stream.peer_addr().ok();
81
82        let mut buffered_reader = BufReader::new(&mut stream);
83        let mut packet = read_packet(&mut buffered_reader).await?;
84        debug!("Received Packet ID: {}", packet.id());
85
86        let json = read_string(&mut packet.data)?;
87        let latency = start_time.elapsed().as_millis() as u32;
88
89        let mut as_res = serde_json::from_str::<JavaPing>(&json)?;
90
91        as_res.latency = latency;
92        as_res.connected_addr = connected_addr;
93        Ok(as_res)
94    }
95}