From f22a917f2148da1b34e7a61b5fc04f0395a1d9a5 Mon Sep 17 00:00:00 2001 From: Verox001 Date: Fri, 21 Feb 2025 00:26:09 +0100 Subject: [PATCH] Finished status and ping handling --- main.go | 331 ++++++++++++++++++-------------------------------------- 1 file changed, 106 insertions(+), 225 deletions(-) diff --git a/main.go b/main.go index 3896089..ef2307e 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,8 @@ package main import ( + "bytes" + "encoding/binary" "encoding/json" "errors" "fmt" @@ -11,11 +13,8 @@ const ( HandshakePacketID = 0x00 StatusRequestID = 0x00 StatusResponseID = 0x00 -) - -const ( - SEGMENT_BITS = 0x7F - CONTINUE_BIT = 0x80 + PingRequestID = 0x01 + PongResponseID = 0x01 ) type HandshakePacket struct { @@ -42,6 +41,10 @@ type PlayerInfo struct { Sample []Player `json:"sample"` } +type Pong struct { + Timestamp int64 `json:"timestamp"` +} + type Player struct { Name string `json:"name"` ID string `json:"id"` @@ -51,11 +54,6 @@ type Chat struct { Text string `json:"text"` } -type Reader struct { - data []byte - cursor int -} - type ClientState struct { conn net.Conn nextState int @@ -79,7 +77,6 @@ func main() { } client := &ClientState{conn: conn, nextState: 0} - go handleConnection(client) } } @@ -88,10 +85,7 @@ func handleConnection(client *ClientState) { defer client.conn.Close() fmt.Println("New connection from:", client.conn.RemoteAddr()) - r := &Reader{data: make([]byte, 0)} - buf := make([]byte, 1024) - for { n, err := client.conn.Read(buf) if err != nil { @@ -99,76 +93,87 @@ func handleConnection(client *ClientState) { break } - // Append new data to the reader buffer - r.data = append(r.data, buf[:n]...) + reader := bytes.NewReader(buf[:n]) - // Process packets as long as there is data - for len(r.data) > 0 { - startCursor := r.cursor + packetLength, err := readVarInt(reader) + if err != nil || packetLength > reader.Len() { + fmt.Println("Incomplete packet received") + break + } - packetLength, err := r.readVarInt() - if err != nil { - r.cursor = startCursor // Reset if incomplete packet - break - } + packetID, err := readVarInt(reader) + if err != nil { + fmt.Println("Error reading packet ID:", err) + break + } - if len(r.data[r.cursor:]) < packetLength { - r.cursor = startCursor // Reset if incomplete packet - break - } + fmt.Println("Packet ID:", packetID) - packetID, err := r.readVarInt() - if err != nil { - fmt.Println("Error reading packet ID:", err) - break - } - - fmt.Println("Packet ID:", packetID) - - if packetID == StatusRequestID && client.nextState == 1 { - handleStatusRequest(client.conn) + switch packetID { + case HandshakePacketID | StatusRequestID: + if client.nextState == 1 { + handleStatusRequest(client) } else { - if packetID == HandshakePacketID { - handshake, err := handleHandshake(r) - if err != nil { - fmt.Println("Error processing handshake:", err) - return - } - client.nextState = handshake.NextState + handshake, err := handleHandshake(reader) + if err != nil { + fmt.Println("Error processing handshake:", err) + return } + client.nextState = handshake.NextState + } + case PingRequestID: + var timestamp int64 + if err := binary.Read(reader, binary.BigEndian, ×tamp); err != nil { + fmt.Println("Error reading timestamp:", err) + break } - // Remove processed data - r.data = r.data[r.cursor:] - r.cursor = 0 + var responsePacket bytes.Buffer + writeVarInt(&responsePacket, 9) // Packet length: 1 byte for ID + 8 bytes for timestamp + responsePacket.WriteByte(PongResponseID) + binary.Write(&responsePacket, binary.BigEndian, timestamp) + + if _, err := client.conn.Write(responsePacket.Bytes()); err != nil { + fmt.Println("Error sending pong response:", err) + } else { + fmt.Println("Pong response sent successfully:", timestamp) + } } } } -func handleHandshake(r *Reader) (HandshakePacket, error) { +func handleHandshake(reader *bytes.Reader) (HandshakePacket, error) { var handshake HandshakePacket - if err := readHandshakePacket(r, &handshake); err != nil { - fmt.Println("Error reading handshake packet:", err) + var err error + + handshake.ProtocolVersion, err = readVarInt(reader) + if err != nil { return handshake, err } + handshake.ServerAddress, err = readString(reader) + if err != nil { + return handshake, err + } + + if err := binary.Read(reader, binary.BigEndian, &handshake.ServerPort); err != nil { + return handshake, err + } + + handshake.NextState, err = readVarInt(reader) + if err != nil { + return handshake, err + } + + fmt.Printf("Handshake received: %+v\n", handshake) return handshake, nil } -func handleStatusRequest(conn net.Conn) { +func handleStatusRequest(client *ClientState) { status := StatusResponse{ - Version: VersionInfo{ - Name: "1.17.1", - Protocol: 756, - }, - Players: PlayerInfo{ - Max: 100, - Online: 5, - Sample: []Player{}, - }, - Description: Chat{ - Text: "A Minecraft Server", - }, + Version: VersionInfo{"1.21.4", 769}, + Players: PlayerInfo{Max: 100, Online: 5, Sample: []Player{}}, + Description: Chat{Text: "A Minecraft Server"}, } response, err := json.Marshal(status) @@ -177,190 +182,66 @@ func handleStatusRequest(conn net.Conn) { return } - w := &Writer{data: make([]byte, 1024)} + var packetData bytes.Buffer + packetData.WriteByte(StatusResponseID) + writeVarInt(&packetData, len(response)) + packetData.Write(response) - if err := w.writeVarInt(StatusResponseID); err != nil { - fmt.Println("Error writing response ID:", err) - return - } + var responsePacket bytes.Buffer + writeVarInt(&responsePacket, packetData.Len()) + responsePacket.Write(packetData.Bytes()) - if err := w.writeVarInt(len(response)); err != nil { - fmt.Println("Error writing response length:", err) - return - } + fmt.Println("Final Response Packet:", responsePacket.Bytes()) - if err := w.writeString(string(response)); err != nil { - fmt.Println("Error writing response:", err) - return - } - - // Send response to client - _, err = conn.Write(w.data[:w.cursor]) - if err != nil { + if _, err = client.conn.Write(responsePacket.Bytes()); err != nil { fmt.Println("Error sending response:", err) + } else { + fmt.Println("Status response sent successfully") } } -func (r *Reader) readByte() (byte, error) { - if r.cursor >= len(r.data) { - return 0, errors.New("EOF") - } - b := r.data[r.cursor] - r.cursor++ - return b, nil -} - -func (r *Reader) readVarInt() (int, error) { - value := 0 - position := 0 - +func writeVarInt(buf *bytes.Buffer, value int) { for { - currentByte, err := r.readByte() + temp := byte(value & 0x7F) + value >>= 7 + if value > 0 { + temp |= 0x80 + } + buf.WriteByte(temp) + if value == 0 { + break + } + } +} + +func readVarInt(reader *bytes.Reader) (int, error) { + value, position := 0, 0 + for { + b, err := reader.ReadByte() if err != nil { return 0, err } - - value |= int(currentByte&SEGMENT_BITS) << position - - if (currentByte & CONTINUE_BIT) == 0 { + value |= int(b&0x7F) << position + if (b & 0x80) == 0 { break } - position += 7 if position >= 32 { - return 0, errors.New("VarInt is too big") + return 0, errors.New("VarInt too big") } } - return value, nil } -func (r *Reader) readString() (string, error) { - length, err := r.readVarInt() +func readString(reader *bytes.Reader) (string, error) { + length, err := readVarInt(reader) if err != nil { return "", err } - if r.cursor+length > len(r.data) { - return "", errors.New("EOF: Reached String unexpectedly") + strBuf := make([]byte, length) + if _, err := reader.Read(strBuf); err != nil { + return "", err } - - str := string(r.data[r.cursor : r.cursor+length]) - r.cursor += length - return str, nil -} - -func (r *Reader) readUnsignedShort() (uint16, error) { - b1, err := r.readByte() - if err != nil { - return 0, err - } - - b2, err := r.readByte() - if err != nil { - return 0, err - } - - return uint16(b1)<<8 | uint16(b2), nil -} - -type Writer struct { - data []byte - cursor int -} - -func (w *Writer) writeByte(b byte) error { - if w.cursor >= len(w.data) { - return errors.New("EOF") - } - w.data[w.cursor] = b - w.cursor++ - return nil -} - -func (w *Writer) writeVarInt(value int) error { - for { - temp := byte(value & SEGMENT_BITS) - value >>= 7 - if value != 0 { - temp |= CONTINUE_BIT - } - if err := w.writeByte(temp); err != nil { - return err - } - if value == 0 { - break - } - } - return nil -} - -func (w *Writer) writeString(s string) error { - length := len(s) - if err := w.writeVarInt(length); err != nil { - return err - } - if w.cursor+length > len(w.data) { - return errors.New("EOF") - } - copy(w.data[w.cursor:], s) - w.cursor += length - return nil -} - -func writeByte(conn net.Conn, b byte) error { - _, err := conn.Write([]byte{b}) - return err -} - -func writeVarInt(conn net.Conn, value int) error { - var buf [5]byte - n := 0 - for { - temp := byte(value & SEGMENT_BITS) - value >>= 7 - if value != 0 { - temp |= CONTINUE_BIT - } - buf[n] = temp - n++ - if value == 0 { - break - } - } - _, err := conn.Write(buf[:n]) - return err -} - -func readHandshakePacket(r *Reader, packet *HandshakePacket) error { - // Print the whole packet - fmt.Println("Packet: ", r.data) - - var err error - packet.ProtocolVersion, err = r.readVarInt() - fmt.Println("version: ", packet.ProtocolVersion) - if err != nil { - return err - } - - packet.ServerAddress, err = r.readString() - fmt.Println(packet.ServerAddress) - if err != nil { - return err - } - - port, err := r.readUnsignedShort() - if err != nil { - return err - } - packet.ServerPort = port - fmt.Println("Port: ", packet.ServerPort) - - packet.NextState, err = r.readVarInt() - fmt.Println("Next state: ", packet.NextState) - if err != nil { - return err - } - - return nil + return string(strBuf), nil }