Skip to main content

minecraft_pinger/java/
protocol.rs

1use crate::common::protocol::{read_var_int, read_var_int_stream, write_string, write_var_int};
2use crate::error::PingError;
3use bytes::{BufMut, Bytes, BytesMut};
4use log::debug;
5use tokio::io::AsyncReadExt;
6
7// Packets
8pub(crate) fn write_ping_handshake(
9    buffer: &mut BytesMut,
10    hostname: &str,
11    port: &u16,
12    protocol_version: &i32,
13) {
14    let mut handshake = BytesMut::with_capacity(128);
15    handshake.put_u8(0x00);
16    write_var_int(&mut handshake, *protocol_version); // protocol version
17    write_string(&mut handshake, hostname);
18    handshake.put_u16(*port); // Server Port
19    write_var_int(&mut handshake, 1); // next state = 1 status
20
21    write_var_int(buffer, handshake.len() as i32);
22    buffer.put(handshake.freeze());
23}
24
25pub(crate) fn write_ping_request(buffer: &mut BytesMut) {
26    write_var_int(buffer, 1); // length
27    write_var_int(buffer, 0x00); // packet id
28}
29
30pub(crate) struct Packet {
31    id: u8,
32    pub data: Bytes,
33}
34
35impl Packet {
36    pub fn new(id: u8, data: Bytes) -> Packet {
37        Packet { id, data }
38    }
39
40    pub fn id(&self) -> u8 {
41        self.id
42    }
43}
44
45pub(crate) async fn read_packet<R: AsyncReadExt + Unpin>(
46    stream: &mut R,
47) -> Result<Packet, PingError> {
48    let length = read_var_int_stream(stream).await?;
49
50    // Lire exactement `length` bytes
51    let mut buf = vec![0u8; length as usize];
52    stream.read_exact(&mut buf).await.map_err(|e| {
53        debug!("Read packet error 2 {e}");
54        PingError::ReadPacket(e.to_string())
55    })?;
56
57    let mut data = Bytes::from(buf);
58
59    Ok(Packet::new(read_var_int(&mut data)? as u8, data))
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use bytes::BytesMut;
66    use tokio::io::BufReader;
67
68    #[test]
69    fn test_write_ping_handshake() {
70        let mut buffer = BytesMut::new();
71        write_ping_handshake(&mut buffer, "example.com", &25565, &775);
72
73        // Should have length prefix + handshake data
74        assert!(!buffer.is_empty());
75
76        // Verify we can read the length
77        let mut data = buffer.clone().freeze();
78        let length = read_var_int(&mut data).unwrap();
79        assert_eq!(length as usize, data.len());
80    }
81
82    #[test]
83    fn test_write_ping_request() {
84        let mut buffer = BytesMut::new();
85        write_ping_request(&mut buffer);
86
87        let mut data = buffer.freeze();
88        let length = read_var_int(&mut data).unwrap();
89        assert_eq!(length, 1); // packet length
90
91        let packet_id = read_var_int(&mut data).unwrap();
92        assert_eq!(packet_id, 0x00); // status request packet id
93    }
94
95    #[test]
96    fn test_packet_new_and_id() {
97        let packet = Packet::new(0x01, Bytes::from_static(b"test"));
98        assert_eq!(packet.id(), 0x01);
99    }
100
101    #[tokio::test]
102    async fn test_read_packet_valid() {
103        let mut buffer = BytesMut::new();
104        write_ping_request(&mut buffer);
105        let data = buffer.freeze();
106
107        let mut reader = BufReader::new(&data[..]);
108        let packet = read_packet(&mut reader).await.unwrap();
109
110        assert_eq!(packet.id(), 0x00);
111    }
112
113    #[tokio::test]
114    async fn test_read_packet_invalid_length() {
115        let data = Bytes::from_static(&[
116            0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01,
117        ]);
118        let mut reader = BufReader::new(&data[..]);
119        let result = read_packet(&mut reader).await;
120        assert!(result.is_err());
121    }
122}