aboutsummaryrefslogtreecommitdiff
path: root/minecraft-protocol/src/server_status_pinger.rs
blob: 86d0cae9d823c9ff4f321bbf7a2735309e7f0cd1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use crate::{connection::Connection, resolver, ServerAddress};
use tokio::{
    io::{AsyncReadExt, AsyncWriteExt, BufWriter},
    net::TcpStream,
};

struct ServerStatus {}

async fn write_byte(buf: &mut Vec<u8>, n: u8) {
    buf.write_u8(n).await.unwrap();
    println!("write_byte: {}", n);
}

async fn write_bytes(buf: &mut Vec<u8>, bytes: &[u8]) {
    buf.write_all(bytes).await.unwrap();
    println!("write_bytes: {:?}", buf);
}

async fn write_varint(buf: &mut Vec<u8>, mut n: u32) {
    loop {
        if (n & 0xFFFFFF80) == 0 {
            write_byte(buf, n as u8).await;
            return ();
        }
        write_byte(buf, (n & 0x7F | 0x80) as u8).await;
        n >>= 7;
    }
}

async fn write_utf(buf: &mut Vec<u8>, string: &[u8], len: usize) {
    if string.len() > len {
        panic!(
            "String too big (was {} bytes encoded, max {})",
            string.len(),
            len
        );
    }
    write_varint(buf, string.len() as u32).await;
    write_bytes(buf, string).await;
}

async fn write_short(buf: &mut Vec<u8>, n: u16) {
    buf.write_u16(n).await.unwrap();
    println!("write_short: {}", n);
}

pub async fn ping_server(address: &ServerAddress) -> Result<(), String> {
    let resolved_address = resolver::resolve_address(&address).await?;

    let mut conn = Connection::new(&resolved_address).await?;

    // protocol version is 757

    // client intention packet
    // friendlyByteBuf.writeVarInt(this.protocolVersion);
    // friendlyByteBuf.writeUtf(this.hostName);
    // friendlyByteBuf.writeShort(this.port);
    // friendlyByteBuf.writeVarInt(this.intention.getId());

    println!("resolved_address {}", &resolved_address.ip);
    println!("writing intention packet {}", address.host);

    let mut buf: Vec<u8> = vec![0x00]; // 0 is the packet id for handshake
    write_varint(&mut buf, 757).await;
    write_utf(&mut buf, address.host.as_bytes(), 32767).await;
    write_short(&mut buf, address.port).await;
    write_varint(&mut buf, 1).await;

    let mut full_buffer = vec![];
    write_varint(&mut full_buffer, buf.len() as u32).await; // length of 1st packet id + data as VarInt
    full_buffer.append(&mut buf);
    full_buffer.extend_from_slice(&[
        1,    // length of 2nd packet id + data as VarInt
        0x00, // 2nd packet id: 0 for request as VarInt
    ]);

    conn.stream.write_all(&full_buffer).await.unwrap();
    conn.stream.flush().await.unwrap();

    // log what the server sends back
    loop {
        if 0 == conn.stream.read_buf(&mut conn.buffer).await.unwrap() {
            // The remote closed the connection. For this to be a clean
            // shutdown, there should be no data in the read buffer. If
            // there is, this means that the peer closed the socket while
            // sending a frame.

            // log conn.buffer
            println!("{:?}", conn.buffer);
            if conn.buffer.is_empty() {
                println!("buffer is empty ok");
                return Ok(());
            } else {
                return Err("connection reset by peer".into());
            }
        }
    }

    Ok(())
}