Finished status and ping handling

This commit is contained in:
Verox001 2025-02-21 00:26:09 +01:00
parent dc9e176cc1
commit f22a917f21

331
main.go
View File

@ -1,6 +1,8 @@
package main package main
import ( import (
"bytes"
"encoding/binary"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -11,11 +13,8 @@ const (
HandshakePacketID = 0x00 HandshakePacketID = 0x00
StatusRequestID = 0x00 StatusRequestID = 0x00
StatusResponseID = 0x00 StatusResponseID = 0x00
) PingRequestID = 0x01
PongResponseID = 0x01
const (
SEGMENT_BITS = 0x7F
CONTINUE_BIT = 0x80
) )
type HandshakePacket struct { type HandshakePacket struct {
@ -42,6 +41,10 @@ type PlayerInfo struct {
Sample []Player `json:"sample"` Sample []Player `json:"sample"`
} }
type Pong struct {
Timestamp int64 `json:"timestamp"`
}
type Player struct { type Player struct {
Name string `json:"name"` Name string `json:"name"`
ID string `json:"id"` ID string `json:"id"`
@ -51,11 +54,6 @@ type Chat struct {
Text string `json:"text"` Text string `json:"text"`
} }
type Reader struct {
data []byte
cursor int
}
type ClientState struct { type ClientState struct {
conn net.Conn conn net.Conn
nextState int nextState int
@ -79,7 +77,6 @@ func main() {
} }
client := &ClientState{conn: conn, nextState: 0} client := &ClientState{conn: conn, nextState: 0}
go handleConnection(client) go handleConnection(client)
} }
} }
@ -88,10 +85,7 @@ func handleConnection(client *ClientState) {
defer client.conn.Close() defer client.conn.Close()
fmt.Println("New connection from:", client.conn.RemoteAddr()) fmt.Println("New connection from:", client.conn.RemoteAddr())
r := &Reader{data: make([]byte, 0)}
buf := make([]byte, 1024) buf := make([]byte, 1024)
for { for {
n, err := client.conn.Read(buf) n, err := client.conn.Read(buf)
if err != nil { if err != nil {
@ -99,76 +93,87 @@ func handleConnection(client *ClientState) {
break break
} }
// Append new data to the reader buffer reader := bytes.NewReader(buf[:n])
r.data = append(r.data, buf[:n]...)
// Process packets as long as there is data packetLength, err := readVarInt(reader)
for len(r.data) > 0 { if err != nil || packetLength > reader.Len() {
startCursor := r.cursor fmt.Println("Incomplete packet received")
break
}
packetLength, err := r.readVarInt() packetID, err := readVarInt(reader)
if err != nil { if err != nil {
r.cursor = startCursor // Reset if incomplete packet fmt.Println("Error reading packet ID:", err)
break break
} }
if len(r.data[r.cursor:]) < packetLength { fmt.Println("Packet ID:", packetID)
r.cursor = startCursor // Reset if incomplete packet
break
}
packetID, err := r.readVarInt() switch packetID {
if err != nil { case HandshakePacketID | StatusRequestID:
fmt.Println("Error reading packet ID:", err) if client.nextState == 1 {
break handleStatusRequest(client)
}
fmt.Println("Packet ID:", packetID)
if packetID == StatusRequestID && client.nextState == 1 {
handleStatusRequest(client.conn)
} else { } else {
if packetID == HandshakePacketID { handshake, err := handleHandshake(reader)
handshake, err := handleHandshake(r) if err != nil {
if err != nil { fmt.Println("Error processing handshake:", err)
fmt.Println("Error processing handshake:", err) return
return
}
client.nextState = handshake.NextState
} }
client.nextState = handshake.NextState
}
case PingRequestID:
var timestamp int64
if err := binary.Read(reader, binary.BigEndian, &timestamp); err != nil {
fmt.Println("Error reading timestamp:", err)
break
} }
// Remove processed data var responsePacket bytes.Buffer
r.data = r.data[r.cursor:] writeVarInt(&responsePacket, 9) // Packet length: 1 byte for ID + 8 bytes for timestamp
r.cursor = 0 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 var handshake HandshakePacket
if err := readHandshakePacket(r, &handshake); err != nil { var err error
fmt.Println("Error reading handshake packet:", err)
handshake.ProtocolVersion, err = readVarInt(reader)
if err != nil {
return handshake, err 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 return handshake, nil
} }
func handleStatusRequest(conn net.Conn) { func handleStatusRequest(client *ClientState) {
status := StatusResponse{ status := StatusResponse{
Version: VersionInfo{ Version: VersionInfo{"1.21.4", 769},
Name: "1.17.1", Players: PlayerInfo{Max: 100, Online: 5, Sample: []Player{}},
Protocol: 756, Description: Chat{Text: "A Minecraft Server"},
},
Players: PlayerInfo{
Max: 100,
Online: 5,
Sample: []Player{},
},
Description: Chat{
Text: "A Minecraft Server",
},
} }
response, err := json.Marshal(status) response, err := json.Marshal(status)
@ -177,190 +182,66 @@ func handleStatusRequest(conn net.Conn) {
return 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 { var responsePacket bytes.Buffer
fmt.Println("Error writing response ID:", err) writeVarInt(&responsePacket, packetData.Len())
return responsePacket.Write(packetData.Bytes())
}
if err := w.writeVarInt(len(response)); err != nil { fmt.Println("Final Response Packet:", responsePacket.Bytes())
fmt.Println("Error writing response length:", err)
return
}
if err := w.writeString(string(response)); err != nil { if _, err = client.conn.Write(responsePacket.Bytes()); err != nil {
fmt.Println("Error writing response:", err)
return
}
// Send response to client
_, err = conn.Write(w.data[:w.cursor])
if err != nil {
fmt.Println("Error sending response:", err) fmt.Println("Error sending response:", err)
} else {
fmt.Println("Status response sent successfully")
} }
} }
func (r *Reader) readByte() (byte, error) { func writeVarInt(buf *bytes.Buffer, value int) {
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
for { 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 { if err != nil {
return 0, err return 0, err
} }
value |= int(b&0x7F) << position
value |= int(currentByte&SEGMENT_BITS) << position if (b & 0x80) == 0 {
if (currentByte & CONTINUE_BIT) == 0 {
break break
} }
position += 7 position += 7
if position >= 32 { if position >= 32 {
return 0, errors.New("VarInt is too big") return 0, errors.New("VarInt too big")
} }
} }
return value, nil return value, nil
} }
func (r *Reader) readString() (string, error) { func readString(reader *bytes.Reader) (string, error) {
length, err := r.readVarInt() length, err := readVarInt(reader)
if err != nil { if err != nil {
return "", err return "", err
} }
if r.cursor+length > len(r.data) { strBuf := make([]byte, length)
return "", errors.New("EOF: Reached String unexpectedly") if _, err := reader.Read(strBuf); err != nil {
return "", err
} }
return string(strBuf), nil
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
} }